Comparing small double values in Java - java

Why this assertion fails in Java:
double eps = 0.00000000000001;
double ten = 10.0;
double result = (ten - (ten - eps));
Assert.assertTrue(result <= eps);
If I remove one zero before digit 1 in eps, the assertion passes. I assume that this is related to the floating point implementation, but I'm not sure exactly how.
Also, if I replace digit 1 with 2 (like 0.00000000000002) the assertion passes as well. In that case, I can even add more zeros before the digit 2, the test will still pass. I tried with Double.MIN_VALUE (4.9E-324) and the assertion also passed.
Can someone, please, explain in more details:
Why the assertion passes with eps = 1.0E-13 but not with eps = 1.0E-14
Why the assertion passes with eps = Double.MIN_VALUE (4.9E-324) and not with eps = 1.0E-14
EDIT: The assertion also fails when I increase the eps to 1.0E-8: double eps = 0.00000001;

This is because of the organization of the bytes that represents the double type.
As you can see on the image below, it is a 64 bit structure. The bits [b0 .. b51] are 'concatenated' and elevated by the exponent, [b52 .. b62].
And the equation that determines what each combination of bits represents in real value, is:
With this formula, you have that the minimum value is represented by
3ff0 0000 0000 000116 => 1.0000000000000002
For better explanation, see this wiki page Double-precision floating-point format

In the last assertion you're comparing result (1.0658141036401503E-14) and eps (1.0E-14), matimatically that shoud be wrong as espected from the assertion, result in this case is bigger than eps. If you remove one 0 from eps rps become 1.0E-13 that is bigger than 1.0658141036401503E-14 in this case

The problem is that the assertion code is wrong-ish in a sense that it does not take into account the second subtraction ten - (ten - eps).
Let's explain this step by step. Let eps = 0.00000001 (1.0E-8). In this case, 10.0 - eps is 9.99999999. So far, so good. However, 10.0 - 9.99999999 is 0.00000001000000082740371, which is around the expected result of 0.00000001, but just a little bit larger, because floating point arithmetic (usually) gives just good enough approximation. Therefore, for some eps values the final result is very close, but just below the actual result and for some values it is again very close, but just above the actual result.
The code needs to be fixed in order to take into account that the result of the second subtraction is also just an approximation.
One way to do it is to change the assertion to:
Assert.assertTrue(Math.abs(result - eps) <= eps);
In order to understand more on floating point arithmetics, I've found this article quite well written: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
This quote summarize why the errors in floating point arithmetics happen:
There are two reasons why a real number might not be exactly
representable as a floating-point number. The most common situation is
illustrated by the decimal number 0.1. Although it has a finite
decimal representation, in binary it has an infinite repeating
representation. Thus when β = 2, the number 0.1 lies strictly between
two floating-point numbers and is exactly representable by neither of
them.

Try following code:
BigDecimal eps1 = new BigDecimal(eps);
BigDecimal ten1 = new BigDecimal(ten);
BigDecimal result1 = ten1.subtract( ten1.subtract(eps1) );
It should be stable regardless eps

Related

BigDecimal in scala

I've stumbled across interisting thing(maybe only for me) in scala. In a word, if we have a BigDecimal(let say val a = BigDecimal(someValue) where someValue is decimal string) the result of operation
N * a / N == a
will not always produce true. I suppose that it relates to any opeartions on BigDecimals. I know that in scala BigDecimals are created with default MathContext set to DECIMAL128(with HALF_EVEN rounding and precision equals to 34). I've discovered such behavior on decimals with more than 30 digits after point
My questions is why I get such results. Can I somehow control them?
example
-0.007633587786259541984732824427480916
As previous comments already point out, this is not avoidable with irrational numbers. This is because there's no way to represent an irrational number using the standard numeric types (if at all). Since I have no examples with irrational numbers (even PI is limited to a fixed number of digits, and therefore can be expressed as a quotient of 2 whole numbers, making it rational), I will use repeating decimals to illustrate the problem. I changed N*a/N to a/N*N because it demonstrates the problem better with whole numbers, but they're equivalent:
a = BigDecimal(1)
N = BigDecimal(3)
a/N = 0.333...
a/N*N = 0.999...
As you can see in the example above, you can use as many decimal places and any rounding mode, but the result is never going to be equal to 1. (Though it IS possible to get 1 using a different rounding mode per operation, i.e. BigDecimal(3, roundHalfEven) * (BigDecimal(1, roundUp) / 3))
One thing you can do to control the number comparison is to use a higher precision when performing your arithmetic operations and round to the desired (lower) precision when comparing:
val HighPrecision = new java.math.MathContext(36, java.math.RoundingMode.HALF_EVEN);
val TargetPrecision = java.math.MathContext.DECIMAL128;
val a = BigDecimal(1, HighPrecision)
val N = BigDecimal(3, HighPrecision)
(a/N*N).round(TargetPrecision) == a.round(TargetPrecision)
In the example above, the last expression evaluates to true.
UPDATE
To answer your comment, although BigDecimal is arbitrary precision, it is still limited by a precision. It can be 34 or it can be 1000000 (if you have enough memory). BigDecimal does NOT know that 1 / 3 is 0.33<repeating>. If you think about how division works, there's no way for BigDecimal to conclusively know that it's repeating without performing the division to infinite decimal places. But since a precision of 2 indicates it can stop dividing after 2 decimal places, it only knows that 1 / 3 is 0.33.

Why is comparing floats inconsistent in Java?

class Test{
public static void main(String[] args){
float f1=3.2f;
float f2=6.5f;
if(f1==3.2){
System.out.println("same");
}else{
System.out.println("different");
}
if(f2==6.5){
System.out.println("same");
}else{
System.out.println("different");
}
}
}
output:
different
same
Why is the output like that? I expected same as the result in first case.
The difference is that 6.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.
An equality comparison between float and double first converts the float to a double and then compares the two. So the data loss.
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.
This rounding error is a characteristic feature of floating-point computation.
Squeezing infinitely many real numbers into a finite number of bits
requires an approximate representation. Although there are infinitely
many integers, in most programs the result of integer computations can
be stored in 32 bits.
In contrast, given any fixed number of bits,
most calculations with real numbers will produce quantities that
cannot be exactly represented using that many bits. Therefore the
result of a floating-point calculation must often be rounded in order
to fit back into its finite representation. This rounding error is the
characteristic feature of floating-point computation.
Check What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!
They're both implementations of different parts of the IEEE floating point standard. A float is 4 bytes wide, whereas a double is 8 bytes wide.
As a rule of thumb, you should probably prefer to use double in most cases, and only use float when you have a good reason to. (An example of a good reason to use float as opposed to a double is "I know I don't need that much precision and I need to store a million of them in memory.") It's also worth mentioning that it's hard to prove you don't need double precision.
Also, when comparing floating point values for equality, you'll typically want to use something like Math.abs(a-b) < EPSILON where a and b are the floating point values being compared and EPSILON is a small floating point value like 1e-5. The reason for this is that floating point values rarely encode the exact value they "should" -- rather, they usually encode a value very close -- so you have to "squint" when you determine if two values are the same.
EDIT: Everyone should read the link #Kugathasan Abimaran posted below: What Every Computer Scientist Should Know About Floating-Point Arithmetic for more!
To see what you're dealing with, you can use Float and Double's toHexString method:
class Test {
public static void main(String[] args) {
System.out.println("3.2F is: "+Float.toHexString(3.2F));
System.out.println("3.2 is: "+Double.toHexString(3.2));
System.out.println("6.5F is: "+Float.toHexString(6.5F));
System.out.println("6.5 is: "+Double.toHexString(6.5));
}
}
$ java Test
3.2F is: 0x1.99999ap1
3.2 is: 0x1.999999999999ap1
6.5F is: 0x1.ap2
6.5 is: 0x1.ap2
Generally, a number has an exact representation if it equals A * 2^B, where A and B are integers whose allowed values are set by the language specification (and double has more allowed values).
In this case,
6.5 = 13/2 = (1+10/16)*4 = (1+a/16)*2^2 == 0x1.ap2, while
3.2 = 16/5 = ( 1 + 9/16 + 9/16^2 + 9/16^3 + . . . ) * 2^1 == 0x1.999. . . p1.
But Java can only hold a finite number of digits, so it cuts the .999. . . off at some point. (You may remember from math that 0.999. . .=1. That's in base 10. In base 16, it would be 0.fff. . .=1.)
class Test {
public static void main(String[] args) {
float f1=3.2f;
float f2=6.5f;
if(f1==3.2f)
System.out.println("same");
else
System.out.println("different");
if(f2==6.5f)
System.out.println("same");
else
System.out.println("different");
}
}
Try like this and it will work. Without 'f' you are comparing a floating with other floating type and different precision which may cause unexpected result as in your case.
It is not possible to compare values of type float and double directly. Before the values can be compared, it is necessary to either convert the double to float, or convert the float to double. If one does the former comparison, the conversion will ask "Does the the float hold the best possible float representation of the double's value?" If one does the latter conversion, the question will be "Does the float hold a perfect representation of the double's value". In many contexts, the former question is the more meaningful one, but Java assumes that all comparisons between float and double are intended to ask the latter question.
I would suggest that regardless of what a language is willing to tolerate, one's coding standards should absolutely positively forbid direct comparisons between operands of type float and double. Given code like:
float f = function1();
double d = function2();
...
if (d==f) ...
it's impossible to tell what behavior is intended in cases where d represents a value which is not precisely representable in float. If the intention is that f be converted to a double, and the result of that conversion compared with d, one should write the comparison as
if (d==(double)f) ...
Although the typecast doesn't change the code's behavior, it makes clear that the code's behavior is intentional. If the intention was that the comparison indicate whether f holds the best float representation of d, it should be:
if ((float)d==f)
Note that the behavior of this is very different from what would happen without the cast. Had your original code cast the double operand of each comparison to float, then both equality tests would have passed.
In general is not a good practice to use the == operator with floating points number, due to approximation issues.
6.5 can be represented exactly in binary, whereas 3.2 can't. That's why the difference in precision doesn't matter for 6.5, so 6.5 == 6.5f.
To quickly refresh how binary numbers work:
100 -> 4
10 -> 2
1 -> 1
0.1 -> 0.5 (or 1/2)
0.01 -> 0.25 (or 1/4)
etc.
6.5 in binary: 110.1 (exact result, the rest of the digits are just zeroes)
3.2 in binary: 11.001100110011001100110011001100110011001100110011001101... (here precision matters!)
A float only has 24 bits precision (the rest is used for sign and exponent), so:
3.2f in binary: 11.0011001100110011001100 (not equal to the double precision approximation)
Basically it's the same as when you're writing 1/5 and 1/7 in decimal numbers:
1/5 = 0,2
1,7 = 0,14285714285714285714285714285714.
Float has less precision than double, bcoz float is using 32bits inwhich 1 is used for Sign, 23 precision and 8 for Exponent . Where as double uses 64 bits in which 52 are used for precision, 11 for exponent and 1for Sign....Precision is important matter.A decimal number represented as float and double can be equal or unequal depends is need of precision( i.e range of numbers after decimal point can vary). Regards S. ZAKIR

Java Glitch? Subtracting numbers?

Is this a glitch in Java?
I go to solve this expression: 3.1 - 7.1
I get the answer: -3.9999999999999996
What is going on here?
A great explanation can be found here. http://www.ibm.com/developerworks/java/library/j-jtp0114/
Floating point arithmetic is rarely exact. While some numbers, such
as 0.5, can be exactly represented as a binary (base 2) decimal (since
0.5 equals 2-1), other numbers, such as 0.1, cannot be. As a result, floating point operations may result in rounding errors, yielding a
result that is close to -- but not equal to -- the result you might
expect. For example, the simple calculation below results in
2.600000000000001, rather than 2.6:
double s=0;
for (int i=0; i<26; i++)
s += 0.1;
System.out.println(s);
Similarly, multiplying .1*26 yields a result different from that of
adding .1 to itself 26 times. Rounding errors become even more serious
when casting from floating point to integer, because casting to an
integral type discards the non-integral portion, even for calculations
that "look like" they should have integral values. For example, the
following statements:
double d = 29.0 * 0.01;
System.out.println(d);
System.out.println((int) (d * 100));
will produce as output:
0.29
28
which is probably not what you might expect at first.
See the provided reference for more information.
As mentioned by several others you cannot count on double if you would like to get an exact decimal value, e.g. when implementing monetary applications. What you should do instead is to take a closer look at BigDecimal:
BigDecimal a = new BigDecimal("3.1");
BigDecimal b = new BigDecimal("7.1");
BigDecimal result = a.subtract(b);
System.out.println(result); // Prints -4.0
Computers are 100% so in the math world that is correct, to the average person it is not. Java cant have a error on a specific number as it is just code that runs the same way but has a different input!
P.S. Google how to round a number
rounding errors in floating points
same way that 3 * 0.1 != 0.3 (when it's not folded by the compiler at least)
Automatic type promotion is happening and that is the result.
Here is some resource to learn.
http://docs.oracle.com/javase/specs/jls/se5.0/html/conversions.html
The next step would be is to learn to use formatters to format it to the given precision / requirements.

Subtraction of numbers double and long

In my JAVA program there is code like this:
int f_part = (int) ((f_num - num) * 100);
f_num is double and num is long. I just want to take the fractional part out and assign it to f_part. But some times f_part value is one less than it's value. Which means if f_num = 123.55 and num = 123, But f_part equals to 54. And it happens only f_num and num is greater than 100. I don't know why this happening. Please can someone explain why this happens and way to correct it.
This is due to the limited precision in doubles.
The root of your problem is that the literal 123.55 actually represents the value 123.54999....
It may seem like it holds the value 123.55 if you print it:
System.out.println(123.55); // prints 123.55
but in fact, the printed value is an approximation. This can be revealed by creating a BigDecimal out of it, (which provides arbitrary precision) and print the BigDecimal:
System.out.println(new BigDecimal(123.55)); // prints 123.54999999999999715...
You can solve it by going via Math.round but you would have to know how many decimals the source double actually entails, or you could choose to go through the string representation of the double in fact goes through a fairly intricate algorithm.
If you're working with currencies, I strongly suggest you either
Let prices etc be represented by BigDecimal which allows you to store numbers as 0.1 accurately, or
Let an int store the number of cents (as opposed to having a double store the number of dollars).
Both ways are perfectly acceptable and used in practice.
From The Floating-Point Guide:
internally, computers use a format (binary floating-point) that cannot
accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.
It looks like you're calculating money values. double is a completely inappropriate format for this. Use BigDecimal instead.
int f_part = (int) Math.round(((f_num - num) * 100));
This is one of the most often asked (and answered) questions. Floating point arithmetics can not produce exact results, because it's impossible to have an inifinity of real numbers inside 64 bits. Use BigDecimal if you need arbitrary precision.
Floating point arithmetic is not as simple as it may seem and there can be precision issues.
See Why can't decimal numbers be represented exactly in binary?, What Every Computer Scientist Should Know About Floating-Point Arithmetic for details.
If you need absolutely sure precision, you might want to use BigDecimal.

Is "long x = 1/2" equal to 1 or 0, and why? [duplicate]

This question already has answers here:
Integer division: How do you produce a double?
(11 answers)
Closed 7 years ago.
if I have something like:
long x = 1/2;
shouldn't this be rounded up to 1? When I print it on the screen it say 0.
It's doing integer division, which truncates everything to the right of the decimal point.
Integer division has its roots in number theory. When you do 1/2 you are asking how many times does 2 equal 1? The answer is never, so the equation becomes 0*2 + 1 = 1, where 0 is the quotient (what you get from 1/2) and 1 is the remainder (what you get from 1%2).
It is right to point out that % is not a true modulus in the mathematical sense but always a remainder from division. There is a difference when you are dealing with negative integers.
Hope that helps.
What this expression is doing is it first declares the existence of a long called x, and then assigning it the value of the right hand side expression. The right hand side expression is 1/2, and since 1 and 2 are both integers this is interpreted as integer division. With integer division the result is always an Integer, so something along the lines of 5/3 will return 1, as only one three fits in a five. So with 1/2, how many 2s can fit into 1? 0.
This can in some languages result in some interesting outputs if you write something like
double x = 1/2. You might expect 0.5 in this case, but it will often evaluate the integer value on the right first before assigning and converting the result into a double, giving the value 0.0
It is important to note that when doing this kind of type conversion, it will never round the result. So if you do the opposite:
long x = (long)(1.0/2.0);
then while (1.0/2.0) will evaluate to 0.5, the (long) cast will force this to be truncated to 0. Even if I had long x = (long)(0.9), the result will still be 0. It simply truncates after the decimal point.
It can't round because it's never in a state to be rounded
The expression "1/2" is never 0.5 before assign to long
Now, long x = 1.0/2.0 because the expression on the right before assign is valid for rounding. Unless you get 0.499999999999997...
this question was answered before on this site, you are doing an integer division, if you want to get the 0.5 use:
double x = (double)1/2;
and you will get the value of 0.5 .
There are lots of different rounding conventions, the most common being rounding towards +inf, rounding towards -inf and rounding towards zero. Lots of people assume there's one right way, but they all have different ideas about what that one way should be ;-)
There is no intermediate non-integer result for integer division, but of course the division is done deterministically, and one particular rounding convention will always be followed for a particular platform and compiler.
With Visual C++ I get 5/2 = 2 and -5/2 = -2, rounding towards zero.
The rounding in C, C++ and Java is commonly called "truncation" - meaning drop off the unwanted bits. But this can be misleading. Using 4 bit 2s complement binary, doing what truncation implies gives...
5/2 = 0101/0010 = 0010.1 --> 0010 = 2
-5/2 = 1011/0010 = 1101.1 --> 1101 = -3
Which is rounding towards -infinity, which is what Python does (or at least what it did in Python 2.5).
Truncation would be the right word if we used a sign-magnitude representation, but twos complement has been the de-facto standard for decades.
In C and C++, I expect while it's normally called truncation, in reality this detail is undefined in the standards and left to the implementation - an excuse for allowing the compiler to use the simplest and fastest method for the platform (what the processors division instruction naturally does). It's only an issue if you have negative numbers though - I've yet to see any language or implementation that would give 5/2 = 3.
I don't know what the Java standard says. The Python manual specifies "floor" division, which is a common term for rounding to -infinity.
EDIT
An extra note - by definition, if a/b = c remainder d, then a = (b*c)+d. For this to hold, you have to choose a remainder to suite your rounding convention.
People tend to assume that remainders and modulos are the same, but WRT signed values, they can be different - depending on the rounding rules. Modulo values are by definition never negative, but remainders can be negative.
I suspect the Python round-towards-negative-infinity rule is intended to ensure that the single % operator is valid both as a remainder and as a modulo. In C and C++, what % means (remainder or modulo) is (yes, you guessed it) implementation defined.
Ada actually has two separate operators - mod and rem. With division required to round towards zero, so that mod and rem do give different results.

Categories

Resources