Principle of Least Surprise [duplicate] - java

This question already has answers here:
java double precision [duplicate]
(2 answers)
Closed 9 years ago.
double d = 0.0;
for (int i = 0; i < 10; i++)
{
d = d+0.1;
}
System.out.println(d);
This is an example I read somewhere on "Principle of Least Surprise"
I was just curious on why the code would return a 0.999999999 and if I change the datatype of d to float, i get a 1.0000001. What is the reason behind such behavior.

This is a classic case of imprecision in floating point numbers. Since 0.1 can't be represented cleanly in binary (it is a repeating number), there is rounding error as the number is added to itself over and over. The difference in behavior when we change to a float just comes down to a difference in how 0.1 actually is held over the course of more bits of storage.
If you need really accurate representation of decimal numbers, the BigDecimal class will quickly become your best friend. Based on how it internally stores the details of your decimal without loss of precision, computations maintain their integrity.

Related

How to reconstruct a number from its integral, fractional and exponent parts? [duplicate]

This question already has answers here:
How to manually parse a floating point number from a string
(11 answers)
How to convert strings to floats with perfect accuracy?
(5 answers)
Closed 2 years ago.
I am writing a parser where I need to parse numbers.
Numbers are in the JSON format, i.e. simplified, something like:
[+|-] integral [. fractional] [e|E exponent]
So these are the 3 parts of the number I have. Each part is an integer.
For example:
0.4
Integral = 0
Fractional = 4
Exponent = 0
2.84e+6
Integral = 2
Fractional = 84
Exponent = 6
I know how to compute the number in Java in a very crude manner. Something like this:
long integral;
long fractional;
int exp;
double decimal = fractional;
while (decimal >= 1.0) {
decimal *= 0.1;
}
var n = (integral + decimal) * Math.pow(10, exp);
But this has terrible properties like losing precision completely, overflowing etc. specially for very large numbers (e.g. 10e99, 2.7e-23).
Is there a way to create a number in Java from its constituent parts such that the number keeps the properties as close as possible to the floating point literal?
My current idea is to try to create the exact bits in memory that would represent the floating point number using the IEEE 754 representation Java (and many languages) uses.
This blog post helped me understand the floating point representation, but I am still kind of stuck.
My current try to do that uses a ByteBuffer which can do:
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(<bits representing the number exactly in floating point>);
buffer.flip();
double n = buffer.getDouble();
The "only" problem being, figuring out the right bits, which is not trivial (if someone knows a method to do that , please do share).
EDIT: Performance is important, so I am trying to avoid creating a String then throwing it at Double.parseDouble(str)... as that feels pretty expensive compared to writing the bits into memory... but I might be wrong and this is indeed the most "efficient" option? Really don't know at this point, hopefully I can benchmark when I have a few options.

Java 1029 / 9.8 = 104.999 [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 8 years ago.
double test = 1029 / 9.8; // = 104.99999...
int inttest1 = (int) test; // 104
int inttest2 = (int)Math.floor(test); // 104
double testtt = 9.8 * 105; // 1029.0
1029 / 9.8 equals 105
but Java returns 104.9999...
More serious problem is integer casing result is 104, not 105
Why this happens and how can I avoid this result?
There are an infinite number of numbers, even in the limited range represented by Java. That's because mathematically, if you give me any two distinct numbers, I can average them to get a number between them. No matter how close they are.
And there are only a limited number of bits available to represent those numbers.
Hence, something has to give. What gives is the precision of the numbers. Not all numbers can be represented exactly, so some (the vast majority actually) are approximations.
For example, 0.1 cannot be represented exactly with IEEE754 encoding, even with a billion bits available to you.
See this answer for more information on the inherent imprecision of limited-storage floating point numbers.
Casting to an int implicitly drops any decimal. No need to call Math.floor() (assuming positive numbers)
To avoid this behavior use BigDecimal;
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
Standard floating point variables are in binary floating point. Many decimal floating point values (which are the ones you type in your code) have no exact representation in binary floating point. So it isn't doing the calculation with the exact numbers you entered but with some values very close to it. You can use Math.round to round the result to the precision you need and most likely the small error will disappear.
If you really need exact decimal calculation use BigDecimal but note that it is much slower.

Getting wrong answer in double arithmetic in Java [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Double calculation producing odd result
I'm writing a program in Java that deals with a lot of double arithmetic. I eventually get to the point where I need to add 0.6666666666666666 and -0.666666666666667. However, the answer that I get is -3.3306690738754696E-16.
In other words,
double d1 = 0.6666666666666666;
double d2 = -0.666666666666667;
System.out.println(d1 + d2);
prints out "-3.3306690738754696E-16". Why is this happening?
Thank you in advance.
doubles are not perfectly accurate, and not every decimal can be perfectly represented as a double (see this). For all practical purposes, -3.3306690738754696E-16 is 0 *. However, if you need more precision, use BigDecimal. Keep in mind that this alternative will not be nearly as efficient as using primitive doubles. It's up to you to decide if you need this level of accuracy and to make a choice accordingly.
*: Evidently, that number is not exactly zero, but for the majority of real-world calculations and computations, a value that small would be inconsiderable. In meters, this value is smaller than the diameter of protons and neutrons - i.e. very very small. That's what I mean by "for all practical purposes".
double values cannot represent all values precisely and this is such an example. You can use BigDecimal instead:
BigDecimal bd1 = new BigDecimal("0.6666666666666666");
BigDecimal bd2 = new BigDecimal("-0.666666666666667");
System.out.println(bd1.add(bd2));
Output:
-4E-16

Floating point multiplication in java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to round a number to n decimal places in Java
When multiplying two numbers in java happens this:
double a = 9.495 * 100;
Expected result:
a = 949.5;
But the obtained result is:
a = 949.4999999999999
When I try to round number 9.495 in two decimal places the result is 9.49 instead of 9.50
Any ideas how to solve this problem?
If you want accurate floating point computations, do not use the float or double types, but rather make use of the BigDecimal class.
This is a side effect of floating point calculations, and is well understood, but not necessarily intuitive. This question has actually been asked literally thousands of times, and you need to study how floating point arithmetic works.
To get around this, if you only need 2-decimal precision, then use a integer instead.
For example, if you're dealing with currency, and you want to buy a 100 items for $4.95, then you represent the cost of that value as the integer "495", an multiply that by 100, which gives you "49500". You always treat the last two digits as cents, so "49500" is $495.00.
You cannot. Floating point and double precision numbers in a computer cannot represent all possible values.

Double minus int giving unexpected results [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Floating point arithmetic not producing exact results in Java
Floating point inaccuracy examples
In Java, given the following code:
double amount = scan.nextDouble();
tenBills = (int)amount / (int)10;
amount = amount - (tenBills * 10);
fiveBills = (int)amount / (int)5;
amount = amount - (fiveBills * 5);
After the first calculation, given an input of say 16 amount will equal 6.66 . But after the second calculation amount will be 1.6600000000000001 . I don't understand why subtracting an int from a double would cause such a result.
If you want a hardcore explanation, read the classic What Every Computer Scientist Should Know About Floating-Point Arithmetic. It explains why there are inevitably tiny rounding errors in floating point arithmetic like the one you're seeing.
If you just want a summary: Computers represent everything in binary. Binary representations while doing floating point arithmetic results in tiny inaccuracies in some situations.
Subtracting an int from a double does not change only the integer part of the double. It can also change the scale. In your particular case, the integer part before the subtraction (6) requires more bits to represent than the integer part after subtraction (1). This causes the entire representation of the number to allow for more fractional bits. Results can be (as you found out) a bit unexpected. (Pun intended)

Categories