i know how rounding BigDecimal with the API,
but i actually work witjh a remote API which
sends to me unformated and not rounded BigDecimals.
As examples, the API back-end returns to me
3.70000000000000017763568394002504646778106689453125
which invites me to do something like
myBg.setScale(1,RoudingMode.HALF_EVEN);
when API back-end returns to me
3.74000000000000017763568394002504646778106689453125
it invited me to do something like
myBg.setScale(2,RoudingMode.HALF_EVEN);
So my question is :
is there a way to guess the adhoc scale/rounding to apply to the BigDecimal
without parse the BigDecimal and counting the numbers of 0 inside the number
3.74 --> 0000000000000 <-- 17763568394002504646778106689453125
Thanks by advance.
Related
I need to parse a json that contains a long number (that was produces in a java servlet). The problem is the long number gets rounded.
When this code is executed:
var s = '{"x":6855337641038665531}';
var obj = JSON.parse(s);
alert (obj.x);
the output is:
6855337641038666000
see an example here: http://jsfiddle.net/huqUh/
why is that, and how can I solve it?
As others have stated, this is because the number is too big. However, you can work around this limitation by sending the number as a string like so:
var s = '{"x":"6855337641038665531"}';
Then instead of using JSON.parse(), you can use a library such as javascript-bignum to work with the number.
It's too big of a number. JavaScript uses double-precision floats for numbers, and they have about 15 digits of precision (in base 10). The highest integer that JavaScript can reliably save is something like 251.
The solution is to use reasonable numbers. There is no real way to handle such large numbers.
The largest number JavaScript can handle without loss of precision is 9007199254740992.
I faced this issue some time ago, I was able to solve using this lib: https://github.com/josdejong/lossless-json
You can check this example:
let text = '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}';
// JSON.parse will lose some digits and a whole number:
console.log(JSON.stringify(JSON.parse(text)));
// '{"normal":2.3,"long":123456789012345680000,"big":null}' WHOOPS!!!
// LosslessJSON.parse will preserve big numbers:
console.log(LosslessJSON.stringify(LosslessJSON.parse(text)));
// '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}'
I encounter a problem when round a double to 2 decimals. I know this questions have been asked in many places. But my question is slightly different and I cannot find it in other places.
So far as I know, there are 2 ways to do this.
Math.round(double*100.0)/100.0
DecimalFormat(“###.##”)
I am trying to use the first way: a custom way to round double.
When the second decimal is 0, the result will only print the first decimal and ignore the second one.
For example,
Math.round(1.23333*100.0)/100.0 The result is 1.23. This works good.
Math.round(3.90*100.0)/100.0. The result is 3.9. Problem occurs. I want to show 3.90 instead of 3.9
Math.round(3*100.0)/100.0. The result is 4.0. I want 4.00 instead of 4.0
So, my question is that how I can have a double value with 2 decimals no matter if the last decimal is 0 or not. I know I can use the second way- DecimalFormat(“###.##”) to achieve what I want! But is it possible to do it by using the first way?
Edit: Thanks for the answers. It looks like it is NOT possible to use the round() method to achieve it. However, some people suggest to use the combination of 2 ways to achieve it. But I think using only DecimalFormat(“###.##”) can get what I want. Can anyone confirm it?
I would suggest using String.format("%1$.2f",x). It rounds the value to the specified precision (2 digits in our example) and leaves the trailing zeros on the right.
System.out.println(String.format("%1$.2f",3.121)) gives 3.12
System.out.println(String.format("%1$.2f",3.129)) gives 3.13
System.out.println(String.format("%1$.2f",3.12)) gives 3.12
System.out.println(String.format("%1$.2f",3.10)) gives 3.10
Have you tried the following?
DecimalFormat(“###.00”)
If not mistaken, trailing zeros are left blank when using the #-sign.
I believe you need to use a combination of both to achieve your needs.
The rounding to obtain a number with two decimals, and the DecimalFormat to display it with two decimals.
You should be formatting your result with DecimalFormat
DecimalFormat format = new DecimalFormat("0.00");
System.out.println(Math.round(3.90*100.0)/100.0); // 3.9
System.out.println(format.format(Math.round(3.90*100.0)/100.0)); // after using format 3.90
System.out.println(format.format(Math.round(3*100.0)/100.0));
And the output is
3.9
3.90
3.00
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.
I'm sure this would be a simple question to answer but I can't for the life of me decide what has to be done. So here's it: assuming we follow the "best practice" of using BigDecimal for financial calculations, how can one handle stuff (computations) which throw an exception?
As as example: suppose, I have to split a "user amount" for investing in bonds between "n" different entities. Now consider the case of user submitting $100 for investing to be split between 3 bonds. The equivalent code would look like:
public static void main(String[] args) throws Exception {
BigDecimal bd1 = new BigDecimal("100.0");
BigDecimal bd2 = new BigDecimal("3");
System.out.println(bd1.divide(bd2));
}
But as we all know, this particular code snippet would throw an ArithmeticException since the division is non-terminating. How does one handle such scenarios in their code when using infinite precision data types during computations?
TIA,
sasuke
UPDATE: Given that RoundingMode would help remedy this issue, the next question is, why is 100.0/3 not 33.33 instead of 33.3? Wouldn't 33.33 be a "more" accurate answer as in you expect 33 cents instead of 30? Is there any way wherein I can tweak this?
The answer is to use one of the BigDecimal.divide() methods which specify a RoundingMode.
For example, the following uses the rounding mode half even or bankers rounding (but half up or one of the other rounding modes may be more appropriate depending on requirements) and will round to 2 decimal places:
bd1.divide(bd2, 2, RoundingMode.HALF_EVEN);
divide has an overload that takes a rounding mode. You need to choose one. I believe "half even" is the most commonly used one for monetary calculations.
bd1.divide(bd2, 5, BigDecimal.ROUND_FLOOR)
It's an exemple, depending on the rounding you want.
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).