String 999999999.9999999999 is rounded to 1,000,000,000 BigDecimal - java

I have a problem where my 999999999.9999999999 String is being rounded to 1,000,000,000 BigDecimal when I parse it.
Code:
NumberFormat format = new DecimalFormat("#.0000000000######");
format.setParseIntegerOnly(false);
Number number = format.parse(text);
Result:
number = 1.0E9
If I use the same format to parse the result BigDecimal back to String:
format.format(number) results in 1,000,000,000
Why does this happen and how I can force the original format.parse(text) call not to round?

Unless there's some code you've omitted, parse is returning a Double, not a BigDecimal. (Try System.out.println(number.getClass()) to check this.)
If you want a BigDecimal, you have to use setParseBigDecimal to tell it to return a BigDecimal. (And to do that, format has to be declared as DecimalFormat.)
DecimalFormat format = new DecimalFormat("#.0000000000######");
format.setParseBigDecimal(true);
Number number = format.parse(text);

Related

Conversion of String to BigDecimal format

I have a String which is like "$1,234.00". I need to convert it into a BigDecimal value. Cannot do it utilising normal BigDecimal conversion methods as it throws NumberFormatException. Is there a way it can be achieved?
"$1,234.00" is a formatted numeric text, so you need to parse the number using a NumberFormat.
In particular, you need a DecimalFormat so you can call the setParseBigDecimal(true) method, since you want a BigDecimal as the result, otherwise it would likely have returned a Double.
DecimalFormat format = new DecimalFormat("ยค#,##0.00", DecimalFormatSymbols.getInstance(Locale.US));
format.setParseBigDecimal(true);
BigDecimal number = (BigDecimal) format.parse(input);

DecimalFormat not rounding to two decimal places correctly

In the program I am writing I have a percent change function. With the numbers I'm using, it is supposed to return .03, yet I just get 0. Using a calculator, the value not formatted would be 0.03303. I want the number to be truncated after the second decimal place, no rounding at all.
df = new DecimalFormat("###.##;-###.##");
df.setRoundingMode(RoundingMode.DOWN);
//later in code
return df.format(((price-base_price)/price)*100.00D);
Edit: all variable types are doubles. Base price is 756.60 and price is 756.85
Your assumption about the value calculated in ((price-base_price)/price)*100.00D is incorrect (I think you've probably invoked integer math, try ((price-base_price)/(double)price)*100.00D). When I directly execute,
double value = 0.03303;
DecimalFormat df = new DecimalFormat("###.##;-###.##");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(value));
I get the (requested) output
0.03

Move decimal point in double

I have this code:
Long dval = new Long((new Date()).getTime());
System.out.println("ogval:"+dval);
Double dd = (double)dval;
System.out.println("dval:"+dd);
Here is the output:
ogval:1381490769636
dval:1.381490769636E12
When I convert the value to Double, it adds a decimal point. Can I do the typecasting and get the value in double as it is?
The desired output would be:
ogval:1381490769636
dval:1381490769636
I have a function whose argument accepts only double value. When I try to pass a timestamp, it passes the decimal value inside the method.
I can't edit the function because its an inbuilt function of some package.
Simple answer is no.
Floating types can contain integer up to some arbitrary value, given by the way floats are stored. If the number is too big, it gets converted to decimal.
If you need to work with big integer values use BigInteger class.
Great tool to examine those imperfections is this float converter.
Try 123456789 in the float converter, it won't be stored exactly.
Use DecimalFormat, like:
Long dval = new Long((new Date()).getTime());
System.out.println("ogval:" + dval);
Double dd = (double) dval;
DecimalFormat format=new DecimalFormat("##########");
System.out.println("dval:" + format.format(dd));
Your problem is not with the type that you are using, but with the format that you are applying to it. Currently, the default format is used, because string + double implicitly calls Double.toString, which converts your specific double to a String using scientific notation. You can force a different format if you wish by using printf or any other formatting method that Java makes available to you:
System.out.printf("dval: %12.0f", dd);
(demo)
as an alternative you can try using bigdecimal
Long dval = new Long((new Date()).getTime());
System.out.println("ogval:"+dval);
Double dd = (double)dval;
System.out.println("dval:"+dd);
BigDecimal bd = new BigDecimal(dval);
System.out.println("bdval:"+bd.toPlainString());

Formatting a number with correct decimal scale

I need to format a number with scale of 2 decimal places. The original number may be a whole number or a number with three decimal places. However the result should be formatted to have commas and also two decimal places always regardless of whether the original number is whole number or having decimal places.
When original num = 56565656.342 ==> I need 56,565,656.34
When original num = 56565656 ==> I need 56,565,656.00
When original num = 56565656.7 ==> I need 56,565,656.70
I am using the following code which is formatting the code but its failing to add the two decimal places in the above 2 & 3 cases.
String originalNumber = "56565656.7";
BigDecimal b = new BigDecimal(originalNumber).setScale(2, BigDecimal.ROUND_HALF_UP);
String formattedNumber = NumberFormat.getInstance().format(b);
Please let me know if there is any way to accomplish this in efficeint way.
Thanks in advance.
Take a look at the DecimalFormat class.
Alternatively you can setScale method from the BigDecimal Class.
BigDecimal bg1 = new BigDecimal("56565656.342");
BigDecimal bg2 = new BigDecimal("56565656.00");
BigDecimal bg3 = new BigDecimal("56565656.70");
DecimalFormat df = new DecimalFormat("###,###.00");
System.out.println(df.format(bg1.doubleValue()));
System.out.println(df.format(bg2.doubleValue()));
System.out.println(df.format(bg3.doubleValue()));
System.out.println(bg1.setScale(2, BigDecimal.ROUND_HALF_UP));
System.out.println(bg2.setScale(2, BigDecimal.ROUND_HALF_UP));
System.out.println(bg3.setScale(2, BigDecimal.ROUND_HALF_UP));
Yields:
56,565,656.34
56,565,656.00
56,565,656.70
56565656.34
56565656.00
56565656.70
EDIT: Also forgot to mention: If you are after precision, I would recommend you use the setScale method, using the .doubleValue() method will yield a double which can cause loss of precision.
Just use NumberFormat and specify the fraction digits, and rounding method, to print :
String [] originalNumbers = new String[] {
"56565656.342",
"56565656.7",
"56565656"
};
NumberFormat df = NumberFormat.getInstance();
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.HALF_UP);
for (String number : originalNumbers) {
String formattedNumber = df.format(new BigDecimal(number));
System.out.println(formattedNumber);
}
Will print
56,565,656.34
56,565,656.70
56,565,656.00
** Edit **
DecimalFormat df = new DecimalFormat("#,###.00");
Will produce the exact same result with the given code above.
DecimalFormat class would do it for you.... You will have to specify appropriate format.

Detect Java NumberFormat inaccuracy

I want to parse an integer accurately, one that has been potentially formatted according to the current locale. If I didn't parse the integer accurately, I want to know it. So I use:
String string = "1111122222333334444455555";
Locale locale = Locale.getDefault();
NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale);
numberFormat.setParseIntegerOnly();
Number number = numberFormat.parse(string);
Obviously "1111122222333334444455555" represents a big number, bigger than a Long can handle. So NumberFormat gives me... a Double??
I guess I would have expected to receive a BigInteger rather than a Double, especially since I asked for an integer-specific number formatter. But never mind that; the bigger problem is that the double value I get back is 1.1111222223333344E24! This is not equal to 1111122222333334444455555!!
If NumberFormat gives me a parsed value that does not equal that stored in the input string, how do I detect that?
Put another way: "How can I know if the Double value I get back from NumberFormat is exactly equivalent to the integral value represented in the original string?"
The javadocs for parse() state that it will return a Long if possible, otherwise it will return a Double. So just check that the return value is a Long.
"Returns a Long if possible (e.g., within the range [Long.MIN_VALUE, Long.MAX_VALUE] and with no decimals), otherwise a Double."
"How can I know if the Double value I get back from NumberFormat is exactly equivalent to the integral value represented in the original string?"
If it returns a Double, then it is not exactly equivalent to your integral value because a Double cannot accurately represent values at that magnitude. Concrete example:
Number a = numberFormat.parse("-9223372036854775809"); // Integer.MIN_VALUE - 1
Number b = numberFormat.parse("-9223372036854775810"); // Integer.MIN_VALUE - 2
System.out.println((a.equals(b))); // prints "true"
Number c = numberFormat.parse("-9223372036854776800");
System.out.println((a.equals(c))); // prints "true"
For you question -
If NumberFormat gives me a parsed value that does not equal that stored in the input string, how do I detect that?
You can use
if(number.toString().equals(string))
//Parsed correctly
else
//Invalid parse
This might not be the solution but worth notice.
public static void main(String[] args) {
String string = "1111122222333334444455555";
Locale locale = Locale.getDefault();
NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale);
numberFormat.setParseIntegerOnly(true);
Number number = numberFormat.parse(string);
BigDecimal b = new BigDecimal(number.toString());
System.out.println(b.toBigInteger());
}
Output of this code is : 1111122222333334400000000
As you can see this is not equal to the number in the actual string , so their might be an overflow occoured.

Categories

Resources