BigDecimal rendering the decimal point according to locale? - java

related to another issue I found out that:
if I want to display BigDecimal.ZERO in JSF with 2 fraction digits, then I have to hardcode the rounding in my backing bean. Because numberConverter does not work on the constant.
BigDecimal.ZERO.SetScale(2, RoundingMode.HALF_UP); //this works and displays: "0.00"
Unfortunately I cannot use locale-dependent displaying the decimal point with that! I even cannot change the fractions with min/maxFractionDigits after hardcoding the roundingMode.
<f:convertNumber pattern="..." has NOT effect on the display.
This is a real mess, does someone know how to enforce a pattern when displaying a BigDecimal in JSF (not a String! then of course I could use new DecimalFormat).

If the actual format of the textis important - say, you're dealing with locale-dependant data - then you're going to need to use a formatter to render it in a specific 'style'. That's the entire purpose of the class. Using setScale() changes the mathematical precision available to the instance - it doesn't really have any effect (or shouldn't be garuanteed, anyways) about the textual display.

Related

Data Type for money in Java

I need to read data from a JSON and there are some money data as shown below:
$234,205,860
I thought to map this data to my DTO class as String, but I am not sure if there is a proper data type in Java. I look at on the web, but could not see any for this kind of data.
So, is there any data type for this money value? Or should I use String to keep this kind of data in Java?
Precision is the keyword here. Double* and float are a bad choice in most cases! To not lose precision, String could come to mind and would work for storing values nicely without running into issues ruining precision. Long may be fine as well in some cases.
If you need to manipulate values in the future go for BigDecimal.
What data type to use for money in Java?
Edit: *should be double (not long).
Assuming you want to cope with multiple currencies, you should create a class that holds both the currency value and units (dollars, pounds, riyals, etc).
For the value, you could use a scaled long (i.e. store cents, or whatever the smallest unit is) and scale the numbers for input/output. That works only if you are sure the value of cents (or smallest unit) is always less than 263-1 or 9,223,372,036,854,775,807, including any intermediate results of calculations. If you don't want to worry about potential overflow, BigDecimal is the way to go.
For the units, there's a java.util.Currency class, but it may or may not meet your needs.
Why NEVER to use floating point for currency:
Is floating point math broken
What Every Computer Scientist Should Know About Floating-Point Arithmetic

Java changing format of a double in an ArrayList<Double>

I have an ArrayList that i am inputting numbers into like
23466012.83
23466413.39
23466411.94
etc.
but when i reprint them from the array after i sort them they are reprinted like this
2.346601283E7
2.346641339E7
2.346641194E7
Why does java do this and how can this be fixed? (I want the format to be the same as when it was input)
Thanks!
Please review how Java handles primitive types and their related objects. By adding a "double" (lowercase) primitive type into a List, they are converted into "Double" objects, because List in Java can only hold objects, not primitives.
Therefore when you later output the Double object, it actually uses the simple toString() method of class Double to format the line. And this is implemented in a way to print the full range of Double in a readable format, this is why it chooses the so-called Scientific Notation with exponents display.
By using a more useful formatter, e.g. the Formatter class as mentioned in the comment or the MessageFormat class, you can better control how the output looks like.
Why does java do this
Java merely prints out your Double values using the default number format.
and how can this be fixed?
By explicitly specifying the desired number format.
I want the format to be the same as when it was input
First of all, you'll need to understand that you can't get "the same format as when it was input" because that information is irretrievably lost. It cannot be determined by inspecting a Double value how many significant digits were used to parse it.
If all you need is printing with two decimal places, one way to achieve it is with this statement:
System.out.format("%.2f%n", 23466012.83);
If, by any chance, you are not bound to using Double as the container of your numeric values, you may also consider BigDecimal, which can exactly represent an arbitrary value in decimal notation. It takes a lot more memory and is a lot slower in computation, but for many use cases neither of those may matter much. A larger issue is that the division of BigDecimal is an involved process because, by default, the API will insist on producing an exact result, which will fail for things as simple as 1/3.
System.out.format("%f%n", value);
Where value is the double primitive variable you want to print to sysout the screen.
Remove the %n if you want to continue printing on the same line.
There are existing answers that indicate how to format the output if you want the numbers output with two decimal places, regardless of how they were input.
If you really mean "I want the format to be the same as when it was input" there is only one practical option - store the input string. You can parse it as a double or BigDecimal for validation and when you need it as input to arithmetic, but always output it using the original.

Java best type to hold price [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Representing Monetary Values in Java
which java type is good to handle price value? and please tell my why ?
I dont know it is simply question :)
I only know that this type must be "safe". Because if we create shop applicatoion or somethink like that.
ps. I need BEST PRACTICE
and how it present in database ?
you should use BigDecimal when dealing with currencies. Java's native floating point types suffer from the same precision issues as other languages, since some decimals cannot be accurately represented as floating point numbers. Even thought it's not java specific, this is an excellent article which describes the complexities around representing decimal values as floating point numbers.
In general, transient values in your application should always use BigDecimal, only converting to a float when you must (for persistence, or displaying data to a user, etc).
an integer (or long) for the smallest denomenator you care about (cents for USD and EUR)
this is because floating points on computers are inherently inaccurate for decimal values(0.1+0.2 != 0.3)
you only need to translate between cent and main dollar in the UI while the domain calculates everything in cents
Personally, I would use BigDecimal (and so does my company!). I consider float or double bad suggestions because of the way floating-point values are stored in the system and there is a possibility of loss of precision (which you certainly don't want when handling money).
If you're building a financial system, I recommend you create or use your own Java class to represent monetary amounts.
As far as the data type to use to hold a monetary amount, long or BigDecimal.
Here's an example Money class that shows the types of methods you need when working with monetary amounts.
If you use sensible rounding of your results double is works perfectly well and not only the fastest but the simplest to write. This can represent money up to $70 trillion without error. Don't use float as this can only represent up to about $10,000 without error.
If you don't know what sensible rounding to use, BigDecimal or long cents could be a better choice.
You need to use the BigDecimal class.

BigDecimal for Stock Prices?

I realize that we should use BigDecimal for all monetary values, but what about stock prices in dollars?
I noticed that data feed API from major vendors uses the type double for stock quotes. Does anyone know why?
Does that mean my application can use the type double to store stock quotes that come from these vendors?
The reason for not using binary floating-point for money is that money uses decimal fractions and people (and accounting regulations) expect specific decimal behaviour from arithmetic operations performed on it - which binary floating-point does not provide.
However, stock quote feeds aren't generally used for accounting. They're displayed, compared, used as input for various chart analysis indicators or trading algorithms - all much closer to scientific applications than accounting, and not requiring decimal behaviour or precision. Instead, because of the large amount of data, storage efficiency and performance are relevant, and BigDecimal really sucks at those.
I work in the field. BigDecimal is obviously ideal from a precision perspective, but it sucks from a performance perspective. doubles are an option in some circumstances (particularly when dealing with normal equity prices, doubles are easily - with appropriate precautions - able to represent the entirety of the price range of all the equity exchanges I regularly deal with).
Another option is, if you know the range of DP used by the exchanges in question, to use fixed-point and a normal int or long. To take an example I know well, Xetra (the German electronic exchange) currently has at most 3 decimal places. Using 3dp, you can represent prices up to 2,147,483.647 with a normal int. Fine for an individual price, no good for representing the total of a day's trading.
It's all a question of what data you're receiving, what the precision of that data is and how you're processing it.
I reject the use of BigDecimal for monetary values (in general*). Use a data-type designed for use with currency (which has a minimum precision such as mils for USD) and knows how to handle other rules. This can also be used to prevent "accidental" conversion of USD to Yen, etc.
Joda Money or timeandmoney are two such examples.
While a BigDecimal is far better than a double for addressing a fixed precision, it is still not a correct monetary representation IMOHO. (BigDecimal may be the back-end [or it could be entirely replaced with another impl.], as a front-end it doesn't adequately represent the domain.)
Happy coding.
*As others have said, it depends upon the use.
Personally I would stick to BigDecimal. It's somewhat disturbing that the vendors are using doubles, but there's no reason why you should propagate their mistake. You'll start with "slightly bad" data, but at least you won't introduce further unexpected behaviour in whatever you do with the values.
You might want to talk to the vendors and find out why they're using doubles though...
A guess on this:
I noticed that data feed API from major vendors uses the type double for stock quotes. Does anyone know why?
When such a API uses a text-based format (like XML or JSON), the data transmitted are actually not double, but decimal numbers - and decimal numbers is what is meant here. And often double is the only datatype which supports decimal numbers (with digits after the point) in some of these APIs.
When you receive a stock price as double and want to calculate "in a money way" about it, make sure you know how much decimal digits (after the point) it has (should have - not from the double, but from the type of stock price), and convert it with this scale to a BigDecimal (or whatever you are using for money calculations).

DecimalFormat and doubles

DecimalFormat parses Double.toString() representation (which could be in scientific and financial format).
Why Sun has chosen this approach, instead of direct converting double to String?
PS:
To be more concrete. Why DecimalFormat internally uses Double.toString() in order to format Double, instead of formatting internal representation of Double itself?
DecimalFormat gives you more control over the format by allowing you to give it a formatting pattern.
may be he ask like "Double.toString(withSomeParameters)" will do the job instead of using DecimalFormat.
i think the reason, could be i18n. in some places you can type 1,800.39 .. while somewhere else you can type 1.800,39
I'm not shure what you mean by "direct converting", but toString() is always a debug information only! You should not use it to display values in a frontend. Use DecimalFormat for parsing and formatting!
Perhaps Sun is following DRY principles.
For financial applications, use BigDecimal instead, that give you control over rounding modes and precision.

Categories