DecimalFormat rounding gives different result than BigDecimal rounding - java

The following code gives -1 for BigDecimal and -0 for DecimalFormat. Why is there a difference? I would expect both to give -1
BigDecimal bd = new BigDecimal(-0.0009).setScale(0, RoundingMode.FLOOR);
System.out.println(bd.toPlainString());
DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.FLOOR);
System.out.println(df.format(-0.0009));
Decimal format seems to return correct/expected result when 0.000 is used but gives wrong/unexpected result for 0, 0.0, 0.00 patterns

This is because .setScale & setRoundingMode working in different ways
SetScale function Usage:-
* Returns a {#code BigDecimal} whose scale is the specified
* value, and whose unscaled value is determined by multiplying or
* dividing this {#code BigDecimal}'s unscaled value by the
* appropriate power of ten to maintain its overall value. If the
* scale is reduced by the operation, the unscaled value must be
* divided (rather than multiplied), and the value may be changed;
* in this case, the specified rounding mode is applied to the division.
setScale(0) rounds 0.00009 to 1
setScale(1) rounds 0.00009 to 0.1
setScale(2) rounds 0.00009 to 0.01
setScale(3) rounds 0.00009 to 0.01
With DecimalFormat Number is rounded & digits are shown as per the format size is mentioned.
DecimalFormat("0.00") makes 0.009 to 0.01
DecimalFormat("0.0") makes 0.009 to 0.0 (rounding was 0.001)
DecimalFormat("0") makes 0.009 to 0 (rounding was 0.001)
DecimalFormat("0.000") makes 0.009 to 0.009 (rounding was not needed)

Related

how compare Double.MAX_VALUE

I want to check if a double has Double.MAX_VALUE.
Is this the right way (version 1):
boolean hasMaxVal(double val){
return val == Double.MAX_VALUE;
}
or do i need to do something like this (version 2):
boolean hasMaxVal(double val){
return Math.abs(val - Double.MAX_VALUE) < 0.00001
}
Java's double type is a double-precision IEEE 754 floating-point number. This means there are 53 bits of precision in the mantissa, and hence the precision of the number is limited to about 16 significant figures in a decimal format.
Double.MAX_VALUE is approximately 1.798×10308, so the 16th significant figure has a magnitude on the order of 10308 - 16 = 10292. We can confirm this using the Math.ulp method, which returns a double value's "unit of least precision":
> Double.MAX_VALUE
1.7976931348623157E308
> Math.ulp(Double.MAX_VALUE)
1.9958403095347198E292
This means if you do want to test for a value "close to" Double.MAX_VALUE, it only makes sense to do so within an epsilon of at least 2E292. Your epsilon of 0.00001 is far too small for there to be any values within that range other than Double.MAX_VALUE itself, so your test is equivalent to val == Double.MAX_VALUE.

Java Math.IEEERemainder confusing result

Java's Math.IEEERemainder function states:
The remainder value is mathematically equal to f1 - f2 × n, where n is
the mathematical integer closest to the exact mathematical value of
the quotient f1/f2, and if two mathematical integers are equally close
to f1/f2, then n is the integer that is even
For the following:
double f1 = 0.1;
double f2 = 0.04;
System.out.println(Math.IEEEremainder(f1, f2));
The output is -0.019999999999999997
However, 0.1/0.04 = 2.5 which is equidistant from both the integers 2 and 3. Shouldn't we pick n = 2 here, resulting in 0.1 - 0.04*2 = 0.02, instead of -0.02 ?
See: Is floating point math broken?
You would think that 0.1 / 0.04 would return exactly 2.5, but that's not true. According to this article, 0.1 cannot be accurately represented using IEEE 754, and is actually represented as 0.100000000000000005551....
In this case, the quotient is slightly higher due to that minuscule offset, which results in a value of 3 for n, as it's no longer equidistant between 2 and 3.
Computing it results in the following:
0.1 - 0.04 * 3 = 0.1 - 0.12 = -0.02 ~= -0.019999999999999997

BigDecimal, precision and scale

I'm using BigDecimal for my numbers in my application, for example, with JPA. I did a bit of researching about the terms 'precision' and 'scale' but I don't understand what are they exactly.
Can anyone explain me the meaning of 'precision' and 'scale' for a BigDecimal value?
#Column(precision = 11, scale = 2)
Thanks!
A BigDecimal is defined by two values: an arbitrary precision integer and a 32-bit integer scale. The value of the BigDecimal is defined to be .
Precision:
The precision is the number of digits in the unscaled value.
For instance, for the number 123.45, the precision returned is 5.
So, precision indicates the length of the arbitrary precision integer. Here are a few examples of numbers with the same scale, but different precision:
12345 / 100000 = 0.12345 // scale = 5, precision = 5
12340 / 100000 = 0.1234 // scale = 4, precision = 4
1 / 100000 = 0.00001 // scale = 5, precision = 1
In the special case that the number is equal to zero (i.e. 0.000), the precision is always 1.
Scale:
If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.
This means that the integer value of the ‘BigDecimal’ is multiplied by .
Here are a few examples of the same precision, with different scales:
12345 with scale 5 = 0.12345
12345 with scale 4 = 1.2345
…
12345 with scale 0 = 12345
12345 with scale -1 = 123450 †
BigDecimal.toString:
The toString method for a BigDecimal behaves differently based on the scale and precision. (Thanks to #RudyVelthuis for pointing this out.)
If scale == 0, the integer is just printed out, as-is.
If scale < 0, E-Notation is always used (e.g. 5 scale -1 produces "5E+1")
If scale >= 0 and precision - scale -1 >= -6 a plain decimal number is produced (e.g. 10000000 scale 1 produces "1000000.0")
Otherwise, E-notation is used, e.g. 10 scale 8 produces "1.0E-7" since precision - scale -1 equals is less than -6.
More examples:
19/100 = 0.19 // integer=19, scale=2, precision=2
1/1000 = 0.0001 // integer=1, scale = 4, precision = 1
Precision: Total number of significant digits
Scale: Number of digits to the right of the decimal point
See BigDecimal class documentation for details.
Quoting Javadoc:
The precision is the number of digits in the unscaled value.
and
If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.
Precision is the total number of significant digits in a number.
Scale is the number of digits to the right of the decimal point.
Examples:
123.456 Precision=6 Scale=3
10 Precision=2 Scale=0
-96.9923 Precision=6 Scale=4
0.0 Precision=1 Scale=1
Negative Scale
For a negative scale value, we apply the following formula:
result = (given number) * 10 ^ (-(scale value))
Example
Given number = 1234.56
scale = -5
-> (1234.56) * 10^(-(-5))
-> (1234.56) * 10^(+5)
-> 123456000
Reference: https://www.logicbig.com/quick-info/programming/precision-and-scale.html
From your example annotation the maximum digits is 2 after the decimal point and 9 before (totally 11):
123456789,01

Java's Bigdecimal.divide and rounding

At work, we found a problem when trying to divide a large number by 1000. This number came from the database.
Say I have this method:
private static BigDecimal divideBy1000(BigDecimal dividendo) {
if (dividendo == null) return null;
return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}
When I make the following call
divideBy1000(new BigDecimal("176100000"))
I receive the expected value of 176100. But if I try the line below
divideBy1000(new BigDecimal("1761e+5"))
I receive the value 200000. Why this occurs? Both numbers are the same with different representation and the latest is what I receive from database. I understand that, somehow, the JVM is dividing the number 1761 by 1000, rounding up and filling with 0's at the end.
What is the best way to avoid this kind of behavior? Keep in mind that the original number is not controlled by me.
As specified in javadoc, a BigDecimal is defined by an integer value and a scale.
The value of the number represented by the BigDecimal is therefore
(unscaledValue × 10^(-scale)).
So BigDecimal("1761e+5") has scale -5 and BigDecimal(176100000) has scale 0.
The division of the two BigDecimal is done using the -5 and 0 scales respectively because the scales are not specified when dividing. The divide documentation explains why the results are different.
divide
public BigDecimal divide(BigDecimal divisor)
Returns a BigDecimal whose value is (this / divisor), and whose preferred scale is (this.scale() - divisor.scale()); if the exact quotient cannot be represented (because it has a non-terminating decimal expansion) an ArithmeticException is thrown.
Parameters:
divisor - value by which this BigDecimal is to be divided.
Returns:
this / divisor
Throws:
ArithmeticException — if the exact quotient does not have a terminating decimal expansion
Since:
1.5
If you specify a scale when dividing, e.g. dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP) you will get the same result.
The expressions new BigDecimal("176100000") and new BigDecimal("1761e+5") are not equal. BigDecimal keeps track of both value, and precision.
BigDecimal("176100000") has 9 digits of precision and is represented internally as the BigInteger("176100000"), multiplied by 1. BigDecimal("1761e+5") has 4 digits of precision and is represented internally as the BigInteger("1761"), multiplied by 100000.
When you a divide a BigDecimal by a value, the result respects the digits of precision, resulting in different outputs for seemingly equal values.
for your division with BigDecimal.
dividendo.divide(divisor,2,RoundingMode.CEILING)//00.00 nothing for up and nothing for down
in this operation have a precision for two decimals.
To avoid this kind of problems in Java when dividing by powers of 10 you have a much efficient and precise approach:
dividendo.movePointLeft(3)
Yeah, that's kind of issue what you're experimenting. If I may, in a situation where you only have exponental numbers, you should cast them and then use your method. See what I suggest is this bit of code down there:
long longValue = Double.valueOf("1761e+5").longValue();
BigDecimal value= new BigDecimal(longValue);
Use it in a method which would convert those string into a new BigDecimal and return this BigDecimal value. Then you can use those returned values with divideBy1000.That should clear any issue you're having.
If you have a lot of those, what you can do also in store those BigDecimal in a data structure like a list. Then use a foreach loop in which you apply divideBy1000 and each new value would be stored in a different list. Then you would just have to access this list to have your new set of values !
Hope it helps :)
Try using round().
private static BigDecimal divideBy1000(BigDecimal dividendo) {
if (dividendo == null) return null;
return dividendo.divide(BigDecimal.valueOf(1000)).round(new MathContext(4, RoundingMode.HALF_UP));
}
public static void main(String []args){
BigDecimal bigD = new BigDecimal("1761e5");
BigDecimal bigDr = divideBy1000(bigD);
System.out.println(bigDr);
}
The new MathContext(4, RoundingMode.HALF_UP)) line returns the division to 4 places.
This produces:
1.761E+5
Which is what you want. (:
Any time you are multiplying a BigDecimal by a power of 10, in this case you are multiplying by 10-3, you can use dividendo.scaleByPowerOfTen(power) which only modifies the scale of the BigDecimal object and side steps any rounding issues, or at least moves them to a later calculation.
The other answers here cover the more general case of dividing by any number.
I want to quote basic concepts for BigDecimal:
A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale.
public class BigDecimal extends Number implements Comparable<BigDecimal> {
// …
private final BigInteger intVal;
private final int scale;
}
That is, BigDecimal number is represented as unscaled integer value * 10^(-scale)
For example, 1.234 = 1234 * 10^(-3). So, precision is 4, scale is 3.
Please refer to basic concept in here.
For the former:
BigDecimal bd1 = new BigDecimal("176100000");
System.out.println(bd1.precision()); // 9
System.out.println(bd1.scale()); // 0
BigDecimal bd2 = BigDecimal.valueOf(1000);
System.out.println(bd2.precision()); // 4
System.out.println(bd2.scale()); // 0
System.out.println(bd1.divide(bd2)); // 176100
System.out.println(bd1.divide(bd2, RoundingMode.HALF_UP)); // 176100
BigDecimal result = bd1.divide(bd2);
System.out.println(result.precision()); // 6
System.out.println(result.scale()); // 0
The new BigDecimal("176100000")'s precision is 9 and scale is 0.
The BigDecimal.valueOf(1000)'s precision is 4 and scale is 0.
(176100000 * 10^0) / (1000 * 10^0) = 176100 * 10^0.
With method public BigDecimal divide​(BigDecimal divisor, RoundingMode roundingMode), we have to use the dividend(new BigDecimal("176100000"))'s scale as a scale of returning BigDecimal. In this case, the scale is 0.
Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().
As a result, we have BigDecimal number 176100 * 10^0 whose precision is 6 and scale is 0.
The rounding is applied, but the result is integer already, so we just get 176100.
For the latter:
BigDecimal bd1 = new BigDecimal("1761e+5");
System.out.println(bd1.precision()); // 4
System.out.println(bd1.scale()); // -5
BigDecimal bd2 = BigDecimal.valueOf(1000);
System.out.println(bd2.precision()); // 4
System.out.println(bd2.scale()); // 0
System.out.println(bd1.divide(bd2)); // 1.761E+5
System.out.println(bd1.divide(bd2, RoundingMode.HALF_UP)); // 2E+5
BigDecimal result1 = bd1.divide(bd2);
System.out.println(result1.precision()); // 4
System.out.println(result1.scale()); // -2
BigDecimal result2 = bd1.divide(bd2, RoundingMode.HALF_UP);
System.out.println(result2.precision()); // 1
System.out.println(result2.scale()); // -5
The new BigDecimal("1761e+5")'s precision is 4 and scale is -5.
The BigDecimal.valueOf(1000)'s precision is 4 and scale is 0.
(1761 * 10^(-(-5))) / (1000 * 10^0) = 1.761 * 10^(-(-5))
= 1761 * 10^(-(-2)) whose precision is 4 and scale is -2; prints "1.761E+5" using scientific notation of overriden toString.
If we apply rounding, 1.761 * 10^(-(-5)) = 2 * 10^(-(-5)) whose precision is 1 and scale is -5; prints "2E+5" using scientific notation of overriden toString.
I am might be wrong. If you could catch my mistakes, please comment to this answer. I'll correct them.

Rounding double to 2 decimal places returns always 0.0

I try to round a double value to 2 decimal places but I always get 0.0. I tried three approaches.
First:
System.out.println(Math.round(reward*100.0)/100.0);
Second:
System.out.println(String.valueOf(round(reward, 2)));
private double round(double value, int places)
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Third:
DecimalFormat df = new DecimalFormat("###.##");
System.out.println(df.format(reward));
Everytime I only get 0.0. Example values:
5.957818181818184E-16 0.0
3.927272727272729E-18 0.0
3.1250000000000005E-16 0.0
1.6000000000000006E-19 0.0
What am I missing here?
Thanks!
The four values you are testing there should be rounded to 0.0!
5.957818181818184E-16 equals 5.95... * 10^(-16) equals 0.000...0595... with 16 zeroes in front of the first non-zero digit. Similar for your other values. Are you familiar with the scientific notation?
All of the examples you've quoted are very, very, very small numbers. If you round them to two places, the result is zero. That's why you're getting the results you're getting; they're correct. The negative exponent with scientific notation tells us that.
For instance, 2E-1 is 0.2. You can write the number out, then move the decimal point to the left the number of times given in the exponent (it would be to the right if the exponent were positive). So your
5.957818181818184E-16
is really:
0.0000000000000005957818181818184
...which rounded to two places is 0.00.

Categories