Using float and double for calculation, giving different results [duplicate] - java

This question already has answers here:
Why not use Double or Float to represent currency?
(16 answers)
Is floating point math broken?
(31 answers)
Closed 7 years ago.
I am working on a project where we are calculating prices of items with 8 places of decimal points.
But sometime calculation results are different.
I tried some samples but getting different calculation results:
public static void main(String[] args) {
double value1 = 0.999939f * 0.987792f;
double value2 = 0.999939 * 0.987792;
double value3 = (double)0.999939f * 0.987792f;
System.out.println("value 1 : "+ value1);
System.out.println("value 2: "+ value2);
System.out.println("value 3 : "+ value3);
}
Outputs are:
value 1 : 0.9877317547798157
value 2 : 0.9877317446880001
value 3 : 0.9877317839126931
These three are different results.
I am confused. Can anyone please clarify me what is happening here?
Thanks.
I went through some already answered, But I just want some ways where I can calculate with float and doubles only. otherwise I have to change many places. It will be painful.

Because of how floats and decimals are represented, the casts could be causing different results.
For: double value1 = 0.999939f * 0.987792f you are multiplying two floats and then casting it to a double. The resulting float representation is the one being converted to a double.
For: double value2 = 0.999939 * 0.987792; you are multiply two doubles and saving it in a double. This is time there is no casting so the representation never changes (ie. no potential data loss from change in data representation).
For: double value3 = (double)0.999939f * 0.987792f; you are multiplying a double that is casted from a float, times a float. Because of how the Java math works, that second float is probably also being casted to a double, so now you are multiplying two doubles that were once floats causing a third set of representations.
Because float and doubles have different precisions each of these will get a different result. For more info about floating point arithmetic, see here.

When you write a number with the "f" character, it is taken as float, meaning it is encoded with 32bits, whereas without it, it is a double, encoded with 64bits.
The more bits, the more accurately you will represent decimal numbers. This does not make a difference for number with few decimals, but in your case it is significant.
In conclusion, use exclusively double variables in your code.

Related

Round up double value in java [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 2 years ago.
I want to round up a double value in java. Always to round up the value in ispite that matematecally correct way, sometimes, is round down the value. For example:
value = 6.5817
I want to round up, keeping two decimals. So I need the value will be like this:
value = 6.59
The important thing here is always keep two decimals and always round up the second decimal if the value have more two decimals.
Have someone idea how I can to do this in java?
Since double values are inexact, e.g. it cannot store a number like 0.07 exactly, you need to use BigDecimal to help round up a double value, with the least probability of getting the wrong value.
To round to 2 decimals, use:
double value = 6.5817;
double roundedUp = BigDecimal.valueOf(value).setScale(2, RoundingMode.UP).doubleValue();
System.out.println(roundedUp); // prints 6.59
Note that this code prints 0.07 when value = 0.07, unlike e.g. Math.ceil(value * 100.0) / 100.0, which incorrectly prints 0.08.
Try the following:
double a = 6.5817;
Math.ceil(a * 100.0) / 100.0;

How to get the value without round up/down in Java? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
double d0 = Double.parseDouble("53.82233040000000557");
double d1 = Double.valueOf("53.82233040000000557");
output
d0 = 53.822330400000006
d1 = 53.822330400000006
Precision Numbers in Java
Class java.math.BigDecimal is better for handling numbers where precision matters (like monetary amounts), see BigDecimal VS double.
It could be used for geo-coordinates (latitude/longitude). Although practitionars argue that double is precise enough for lat./long. - since you don't want to locate something at nano-meter scale.
Example Code
If you need high precision and scale for your number, use BigDecimal like this:
BigDecimal decimalValue = new BigDecimal("53.82233040000000557");
System.out.println("as BigDecimal: " + decimalValue.toPlainString());
// prints exactly: 53.82233040000000557
Run this code online (IDE one): Double VS BigDecimal for high precision
Read more
Read more in a tutorial on Java: BigDecimal and BigInteger
If you need precision, you have to use a BigDecimal.
The answer is that you cannot. The values you are getting are the most accurate approximation to your values that can possibly be stored in a double. There is no possible way to get a more accurate, less rounded value stored in a double.
If you require that the answers are not rounded at all, therefore, you should not be using double. The data type you should be using instead is BigDecimal.

How do I avoid loss of precision with doubles in Java? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 5 years ago.
I am writing a program that takes raw double values from a database and converts them to 8-byte hex strings, but I don't know how to prevent loss of precision. The data recieved from all devices are stored as doubles, including the 8-byte identification values.
Instances of doubles such as 7.2340172821234e+16 parse correctly without loss of precision, where the exponent is 10^16.
However, in instances where the exponent is 10^17, Java loses precision.
For example, 2.88512954935019e+17 is interpreted by Java as 1.44464854248327008E17
The code I am using looks like this:
public Foo(double bar) {
this.barString = Long.toHexString((long) bar);
if (barString.length == 15) {
barString = "0" + barString; //to account for leading zeroes lost on data entry
}
}
I am using a test case similar to this to test it:
#Test
public void testFooConstructor() {
OtherClass other = new OtherClass();
OtherClass.Foo test0 = other.new Foo(72340172821234000d); //7.2340172821234e+16
assertEquals("0101010100000150", test0.barString); //This test passes
OtherClass.Foo test1 = other.new Foo(144464854248327000d);//1.44464854248327e+17
assertEquals("02013e0500000758, test1.barString); //This test fails
}
The unit test states:
Expected: 02013e0500000758
Actual: 02013e0500000760
When I print out the values that Java stored 72340172821234000d and 144464854248327000d as it respectively prints:
7.2340172821234E16
1.44464854248327008E17
The latter value is off by 8, which seems to be consistent for the few that I have tested.
Is there anything I can do to correct this error?
EDIT: This is not a problem where I care about what is past the ones place. The question that some think this is a duplicate of is asking why floating point numbers are less precise, I am asking how to avoid the loss of precision, through similar workarounds to those that Roman Puchkovskiy suggested.
You could take your floating point values from database as strings (and not floating points) and then use BigDecimal to convert them to long:
String fpAsString = getFromDB();
long longValue = new BigDecimal(fpAsString).longValue();
this.barString = Long.toHexString(longValue);
BigDecimal.longValue() is analogous to narrowing primitive conversion from double to long, but it does not lose precision (apart from the loss of fractional part). You can lose something if the result does not fit into long, but the same will happen with your cast to long.
Float and Double types are variables that very good for storing either very large numbers or very small numbers but very bad with storing numbers with large number of digits and this is due to their binary representation.
Basically if taking a look at how Double or Float are stored in the memory, there are one bit for the sign, several bits for the exponent and several bits for the fraction.
So when looking at how the value is actually stored in the memory it is something like this:
And the actual value is calculated as follow:
(This example refer to Float which represented with 32 bits, Doubles is represented with 64 bits but the same principles apply)
The number of digits the number can represent is limited to the number of digits the fraction part can represent, but even with a very limited number of digits doubles and floats can represent very big numbers and very small numbers by using the exponent.
In java Double, the fraction part take 52 bits, if you will check in the calculator what is the biggest number a 52 bits number can be () you will see you will get a 16 digits number. Double can represent bigger numbers than that by adding zeroes before or after using the number represented by the exponent, but it can't store number that have more than 16 digits without lose of precision.
Notice, there is actually more to it and this is only a very basic explanation to Double and Float representation.
If you want to dive to the more accurate explanation you can check this wikipedia page: https://en.wikipedia.org/wiki/Single-precision_floating-point_format

How float is converted to double in java? [duplicate]

This question already has answers here:
Why converting from float to double changes the value?
(9 answers)
Closed 7 years ago.
I write the following code in java and check the values stored in the variables. when I store 1.2 in a double variable 'y' it becomes 1.200000025443 something.
Why it is not 1.200000000000 ?
public class DataTypes
{
static public void main(String[] args)
{
float a=1;
float b=1.2f;
float c=12e-1f;
float x=1.2f;
double y=x;
System.out.println("float a=1 shows a= "+a+"\nfloat b=1.2f shows b= "+b+"\nfloat c=12e-1f shows c= "+c+"\nfloat x=1.2f shows x= "+x+"\ndouble y=x shows y= "+y);
}
}
You can see the output here:
float a=1 shows a= 1.0
float b=1.2f shows b= 1.2
float c=12e-1f shows c= 1.2
float x=1.2f shows x= 1.2
double y=x shows y= 1.2000000476837158
This is a question of formatting above anything else.
Take a look at the Float.toString documentation (Float.toString is what's called to produce the decimal representations you see for the floats, and Double.toString for the double):
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 float. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument f. Then f must be the float value nearest to x; or, if two float values are equally close to x, then f must be one of them and the least significant bit of the significand of f must be 0.
(emphasis mine)
The situation is the same for Double.toString. But, you need more digits to "uniquely distinguish the argument value from adjacent values of type double" than you do for float (recall that double is 64-bits while float is 32), that's why you're seeing the extra digits for double and not for float.
Note that anything that can be represented by float can also be represented by double, so you're not actually losing any precision in the conversion.
Of course, not all numbers can be exactly representable by float or double, which is why you see those seemingly random extra digits in the decimal representation in the first place. See "What Every Computer Scientist Should Know About Floating-Point Arithmetic".
The reason why there's such issue is because a computer works only in discrete mathematics, because the microprocessor can only represent internally full numbers, but no decimals. Because we cannot only work with such numbers, but also with decimals, to circumvent that, decades ago very smart engineers have invented the floating point representation, normalized as IEEE754.
The IEEE754 norm that defines how floats and doubles are interpreted in memory. Basically, unlike the int which represent an exact value, the floats and doubles are a calculation from:
sign
exponent
fraction
So the issue here is that when you're storing 1.2 as a double, you actually store a binary approximation to it:
00111111100110011001100110011010
which gives you the closest representation of 1.2 that can be stored using a binary fraction, but not exactly that fraction. In decimal fraction, 12*10^-1 gives an exact value, but as a binary fraction, it cannot give an exact value.
(cf http://www.h-schmidt.net/FloatConverter/IEEE754.html as I'm too lazy to do it myself)
when I store 1.2 in a double variable 'y' it becomes 1.200000025443 something
well actually in both the float and the double versions of y, the value actually is 1.2000000476837158, but because of the smaller mantissa of the float, the value represented is truncated before the approximation, making you believe it's an exact value, whereas in the memory it's not.

The difference made by ".0" in double calculation [duplicate]

This question already has answers here:
Why does the division of two integers return 0.0 in Java? [duplicate]
(6 answers)
Closed 8 years ago.
In the calculation of double numbers, what's the difference between, say, 6.0 and 6?
Because when I was solving a problem on online judge, the expression
estimatedPI = Math.sqrt(6*a/b);
got "Wrong answer" on OJ, while
estimatedPI = Math.sqrt(6.0*a/b);
got "Accepted" on OJ.
For the output, because I used
String result;
result = String.format("%.6f\n",estimatedPI);
System.out.print(result);
so the output looks exactly the same, with six digits after decimal point.
The estimatedPI is declared double and a,b declared int.
So why 6.0 got "Accepted" and 6 got "Wrong answer"? What would be the difference here?
Thanks.
Edit: Noted of duplicated questions.
6.0 is a double. 6 is an int.
If a and b are also ints, then 6*a/b is not a "double calculation" - it will be done using int arithmetic.
When you mix doubles and ints in a binary mathematical operation, the int is converted to a double and then the operation is done using double arithmetic. So 6.0*a does a double multiplication (converting a to double first), resulting in a double. Then (the result of that)/b also does a double division (converting b to double first).
The .0 is an indicator to the compiler that the constant is a floating point number rather than an integer. Your expression 6 * a / b will be treated as an integer expression.

Categories

Resources