Java - DecimalFormat not rounding off to 2 digits - java

I want to round off the numbers to 2 digits only, have written the below code:
Double input = 17.755;
DecimalFormat twoDigitDecimalFormat = new DecimalFormat("0.00");
Double output = Double.valueOf(twoDigitDecimalFormat.format(input));
I was expecting output should be 17.76 but it is giving me 17.75 only, for all the other cases it is working perfectly fine, but only this number is not working, if I add one more digit in the input, say 17.7551 then it will roundoff to 17.76

First of, your final value is a Double it does not have 2 digits! When you do Double.valueOf it will become the closest representable value. If you actually want two digits in Java then you need to use BigDecimal which actually stores base 10 floating point representations.
The trick is, the value you are using is not what you think it is.
double d = 17.755;
Java doubles are power of 2 exponent, so a number that appears to be an exact value in decimal, has a repeating representation in float. That means it needs to be truncated and the closest value is used.
jshell> double d = 17.755;
d ==> 17.755
jshell> var x = new BigDecimal(d);
x ==> 17.754999999999999005240169935859739780426025390625
jshell> var y = new BigDecimal("17.755");
y ==> 17.755
Now you can see that x which is an exact representation of d is actually less than 17.755 so when you round it it goes down.
y on the other hand is exactly 17.755 and will round according the the rules you apply.
jshell> System.out.printf("%.2f\n", y);
17.76
jshell> System.out.printf("%.2f\n", x);
17.75

Related

BigDecimal to values monetary

I have two float values:
float value1 = 1.9f;
float value2 = 20;
I want to multiply them and get an exact result, so I use BigDecimal and expect 38 as result:
BigDecimal total = new BigDecimal(value1).multiply(new BigDecimal(value2));
System.out.println(total); // 37.99999952316284179687500
When I do the same test with 10 and 1.9, I get 18.99999976158142089843750 instead of 19.
Why do I lose precision?
This is explained in the javadoc for the BigDecimal(double) constructor:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
And although your variables are floats, there is not ctor that takes floats, so they are cast as doubles. And like the docs say, if you used Strings for your values, you would get the exact result (38) you expect.
The error is right at the start:
float value1 = 1.9f;
You may think that value1 now contains exactly the value 1.9. But this is not the case. Floating point values are stored in binary. The important thing to remember is that some real values cannot be expressed by a finite sequence of digits, such as a float. 1.9 is such a number (just like in decimal the value 1.333... cannot be expressed by a finite sequence of digits).
So you should use BigDecimal from the start. Then the values can be exactly represented (because it is not stored in binary but in decimal) and the calculation results in the expected answer.
Let's say your value1 is a double as primitive type and want to output 2 decimal places and the value1 is 350. 4432567
double roundTotal = Math.round(value1 * 100.0) / 100.0;
or
double roundTotal = (double) Math.round(value1 * 100) / 100;
Output:
350.44
Note that the 2 digits precision. Zeros indicate the wanted number of decimal to display.
Example #2
double roundTotal = (double) Math.round(value1 * 10000) / 10000;
Output:
350.4432
You can use
Math.floor(float f);
//or
Math.ceil(float f);
functions for the exact value. Or you can override these functions for BigDecimal class.

why program can exactly display infinite repeating floating point number in java or other language

like a decimal number 0.1, represented as binary 0.00011001100110011...., this is a infinite repeating number.
when I write code like this:
float f = 0.1f;
the program will rounding it as binary 0 01111011 1001 1001 1001 1001 1001 101, this is not original number 0.1.
but when print this variable like this:
System.out.print(f);
I can get original number 0.1 rather than 0.100000001 or some other number. I think the program can't exactly represent "0.1", but it can display "0.1" exactly. How to do it?
I recover decimal number through add each bits of binary, it looks weird.
float f = (float) (Math.pow(2, -4) + Math.pow(2, -5) + Math.pow(2, -8) + Math.pow(2, -9) + Math.pow(2, -12) + Math.pow(2, -13) + Math.pow(2, -16) + Math.pow(2, -17) + Math.pow(2, -20) + Math.pow(2, -21) + Math.pow(2, -24) + Math.pow(2, -25));
float f2 = (float) Math.pow(2, -27);
System.out.println(f);
System.out.println(f2);
System.out.println(f + f2);
Output:
0.099999994
7.4505806E-9
0.1
in math, f1 + f2 = 0.100000001145... , not equals 0.1. Why the program would not get result like 0.100000001, I think it is more accurate.
Java's System.out.print prints just enough decimals that the resulting representation, if parsed as a double or float, converts to the original double or float value.
This is a good idea because it means that in a sense, no information is lost in this kind of conversion to decimal. On the other hand, it can give an impression of exactness which, as you make clear in your question, is wrong.
In other languages, you can print the exact decimal representation of the float or double being considered:
#include <stdio.h>
int main(){
printf("%.60f", 0.1);
}
result: 0.100000000000000005551115123125782702118158340454101562500000
In Java, in order to emulate the above behavior, you need to convert the float or double to BigDecimal (this conversion is exact) and then print the BigDecimal with enough digits. Java's attitude to floating-point-to-string-representing-a-decimal conversion is pervasive, so that even System.out.format is affected. The linked Java program, the important line of which is System.out.format("%.60f\n", 0.1);, shows 0.100000000000000000000000000000000000000000000000000000000000, although the value of 0.1d is not 0.10000000000000000000…, and a Java programmer could have been excused for expecting the same output as the C program.
To convert a double to a string that represents the exact value of the double, consider the hexadecimal format, that Java supports for literals and for printing.
I believe this is covered by Double.toString(double) (and similarly in Float#toString(float)):
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.
(my emphasis)

Double increments in Java [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to iterate between 0.1f and 1.0f with 0.1f increments in Java?
Part of my program needs to use values inside a while loop as:
0.1
0.2
0.3
...
0.9
so I need to provide them inside that loop.
Here is the code:
double x = 0.0;
while ( x<=1 )
{
// increment x by 0.1 for each iteration
x += 0.1;
}
I need the output to be EXACTLY:
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
But it actually gives me something like:
0.1
0.2
0.300000000000000000000000004
0.4
0.5
0.6
0.79999999999999999999999999
0.89999999999999999999999999
0.99999999999999999999999999
Welcome to the world of floating point, where 0.1 isn't 0.1. The problem is that many numbers, including 0.1, cannot be represented exactly in a double. So you aren't really adding exactly 0.1 to x each time through the loop.
One approach is to use integer arithmetic and divide by 10:
int i = 0;
while (i <= 10) {
double x = i / 10.0;
. . .
i++;
}
Another approach is to make x a BigDecimal, where you can specify that you want a particular precision. It basically is doing what the above loop does (an integer plus a scale), but packaged up in a nice class with lots of bells and whistles. Oh, and it has arbitrary precision.
you need to use the decimal formatter to get the expected output.
Below is the code for generating the expected output:
import java.text.DecimalFormat;
public class FloatIncrement {
public static void main (String args[]){
double x= 0.0;
DecimalFormat form = new DecimalFormat("#.#");
while(x<0.9){
x= x+0.1;
System.out.println("X : "+Double.valueOf(form.format(x)));
}
}
}
To get output you want, you could use DecimalFormat. Here is some sample code.
import java.text.DecimalFormat;
public class DF {
public static void main(String [] args) {
double x = 0.1;
DecimalFormat form = new DecimalFormat("#.#");
while (x <= .9) {
System.out.println(Double.valueOf(form.format(x)));
x += 0.1;
}
}
}
As far as the implementation you have now, there is no guarantee as to the precision of what gets printed due to the nature of floating point numbers.
Using BigDecimal
double x = 0.0;
int decimalPlaces = 2;
while ( x<=1 )
{
x += 0.1;
BigDecimal bd = new BigDecimal(x);
bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
x = bd.doubleValue();
System.out.println(x);
}
That's because you can use binary floating point to do precise decimal arithmetic because FP cannot precisely represent all decimal values.
You need to use an integer value representing some decimal fractional unit like hundredths or thousandths or use something like BigDecimal.
Double is stored in binary
float and double store numbers as a certain number of significant figures and a radix point (kind of like scientific notation). The significant figures part is not always perfect, because it's stored as a certain number of binary digits - so you can't expect it to perform the way you're expecting it to. (for a better explanation see http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)
Consider using a class such as BigDecimal or a class that implements rational numbers, like the ones mentioned here - Is there a commonly used rational numbers library in Java?
You could also just turn i into an integer, and change it from 1 to 10, and compensate for this in your code.

Converting numbers to float with 2 decimal places

float f = 0.00f;
System.out.println(f);
gives the output:
0.00
I'd like to format a number represented by a percentage to 2 decimal places. But the result should be a float and not a string.
e.g.
10.001 needs to be converted to 10.00
0.0 needs to be converted to 0.00
78.8 needs to be converted to 78.80
The values thus formatted will be assigned to a float.. how would one accomplish this?
private float parse(float val){
DecimalFormat twoDForm = new DecimalFormat("#.##");
return Float.valueOf(twoDForm.format(val));
}
As long as you call it passing an valid float, your result will be a float.
But you can't show the right most zero if its not a String.
In the general case, you can't do that. There's no guarantee that a particular decimal value can be represented by a float that has only two digits right of the decimal.
A float is the wrong data type for this kind of precision. You need to use a decimal type or a scaled integer instead.
Assignment works the same way. If you assign the value 133.47 to a floating-point variable, your environment will assign the closest valid floating-point number to the variable. The closest valid floating-point number will probably not be 133.47.
You can compile and execute this program in C.
#include <stdio.h>
int main (void) {
float r;
r = 133.47;
printf("%.2f, %f\n", r, r);
return 0;
}
It prints these values on my system
$ ./a.out
133.47, 133.470001
Formatting to two decimal places changed the way 'r' looks, but it didn't change its value. Your system will do floating-point arithmetic based on the actual value, not the formatted value. (Unless you also change the data type.)
Floats don't have decimal places. They have binary places. It follows that the only fractions that can be represented exactly in a float to two decimal places are 0, 0.25, 0.5, 0.75. In all the other cases what you are asking is impossible.
import java.text.DecimalFormat;
public class Padding {
public static void main(String[] args) {
float value = 10.001f;
DecimalFormat decimal = new DecimalFormat("0.00");
String formattedValue = decimal.format(value);
System.out.println(formattedValue);
}
}
Output : 10.00

Comparing float and double primitives in Java

I came across a strange corner of Java.(It seems strange to me)
double dd = 3.5;
float ff = 3.5f;
System.out.println(dd==ff);
o/p: true
double dd = 3.2;
float ff = 3.2f;
System.out.println(dd==ff);
o/p: false
I observed that if we compare any two values (a float and a double as I mentioned in the example) with .5 OR .0 like 3.5, 234.5, 645.0
then output is true i.e. two values are equal otherwise output is false though they are equals.
Even I tried to make method strictfp but no luck.
Am I missing out on something.
Take a look at What every computer scientist should know about floating point numbers.
Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation....
--- Edit to show what the above quote means ---
You shouldn't ever compare floats or doubles for equality; because, you can't really guarantee that the number you assign to the float or double is exact.
So
float x = 3.2f;
doesn't result in a float with a value of 3.2. It results in a float with a value of 3.2 plus or minus some very small error. Say 3.19999999997f. Now it should be obvious why the comparison won't work.
To compare floats for equality sanely, you need to check if the value is "close enough" to the same value, like so
float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
// close enough that we'll consider the two equal
...
}
The difference is that 3.5 can be represented exactly in both float and double - whereas 3.2 can't be represented exactly in either type... and the two closest approximations are different.
Imagine we had two fixed-precision decimal types, one of which stored 4 significant digits and one of which stored 8 significant digits, and we asked each of them to store the number closest to "a third" (however we might do that). Then one would have the value 0.3333 and one would have the value 0.33333333.
An equality comparison between float and double first converts the float to a double and then compares the two - which would be equivalent to converting 0.3333 in our "small decimal" type to 0.33330000. It would then compare 0.33330000 and 0.33333333 for equality, and give a result of false.
floating point is a binary format and it can represent numbers as a sum of powers of 2. e.g. 3.5 is 2 + 1 + 1/2.
float 3.2f as an approximation of 3.2 is
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/4194304 + a small error
However double 3.2d as an approximation of 3.2 is
2 + 1 + 1/8+ 1/16+ 1/128+ 1/256+ 1/2048+ 1/4096+ 1/32768+ 1/65536+ 1/524288+ 1/1048576+ 1/8388608+ 1/16777216+ 1/134217728+ 1/268435456+ 1/2147483648+ 1/4294967296+ 1/34359738368+ 1/68719476736+ 1/549755813888+ 1/1099511627776+ 1/8796093022208+ 1/17592186044416+ 1/140737488355328+ 1/281474976710656+ 1/1125899906842624 + a smaller error
When you use floating point, you need to use appropriate rounding. If you use BigDecimal instead (and many people do) it has rounding built in.
double dd = 3.2;
float ff = 3.2f;
// compare the difference with the accuracy of float.
System.out.println(Math.abs(dd - ff) < 1e-7 * Math.abs(ff));
BTW the code I used to print the fractions for double.
double f = 3.2d;
double f2 = f - 3;
System.out.print("2+ 1");
for (long i = 2; i < 1L << 54; i <<= 1) {
f2 *= 2;
if (f2 >= 1) {
System.out.print("+ 1/" + i);
f2 -= 1;
}
}
System.out.println();
The common implementation of floating point numbers, IEEE754, allows for the precise representation of only those numbers which have a short, finite binary expansion, i.e. which are a sum of finitely many (nearby) powers of two. All other numbers cannot be precisely represented.
Since float and double have different sizes, the representation in both types for a non-representable value are different, and thus they compare as unequal.
(The length of the binary string is the size of the mantissa, so that's 24 for float, 53 for double and 64 for the 80-bit extended-precision float (not in Java). The scale is determined by the exponent.)
This should work:
BigDecimal ddBD = new BigDecimal(""+dd);
BigDecimal ffBD = new BigDecimal(""+ff);
// test for equality
ddBO.equals(ffBD);
Always work with BigDecimal when you want to compare floats or doubles
and always use the BigDecimal constructor with the String parameter!

Categories

Resources