1

So I was writing a program to do some calculation and I noticed I wasn't getting the results I expected.

I am using the Math.acos() and Math.sqrt() functions, and when I expect to get a zero answer, I am getting incredibly small almost zero answers.

> System.out.println(Math.acos(27441738 / (Math.sqrt(27441738)*Math.sqrt(27441738))));
1.4901161193847656E-8

This, typically, should print out 0.0. Is there something I am missing here?

Slicktopher
  • 137
  • 2
  • 10
  • 10
    `1.4901161193847656E-8` is _almost_ 0. floating point numbers cannot represent these values exactly. Read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Reimeus Sep 06 '13 at 16:23
  • 1
    is 1.5e-8 not close enough? – arshajii Sep 06 '13 at 16:23
  • Well, the issue was that I was comparing two quantities and determining their distance from each other in radians, so when I am comparing two identical quantities I would prefer it to display that their distance is 0. I'll just have it round. – Slicktopher Sep 06 '13 at 16:25
  • For comparison see: http://stackoverflow.com/questions/434657/java-double-value-comparison – Omar Mainegra Sep 06 '13 at 16:27
  • 3
    You have to compare floating point values by using an epsilon value; there's no `= 0` checking. – Jeroen Vannevel Sep 06 '13 at 16:28
  • 1
    The "What every computer scientist" article is great, but a bit much for first-timers I think. http://floating-point-gui.de is a gentler introduction. – yshavit Sep 06 '13 at 16:31

1 Answers1

1

There is no general rule to narrow down the error in expressions that involve floating point operations.

For this particular case, you can make use of fraction rationalization to drastically mitigate the error:

                                              -------------
        x        x     1     x     1    √x    |  x    √x  |
 1 = -------- = --- * --- = --- * --- * --- = | --- * --- |  
     √x * √x    √x     √x   √x    √x    √x    | √x     x  |
                                              -------------

Evaluating the new expression (using bsh):

System.out.println( Math.acos( (27441738 / Math.sqrt(27441738)) * (Math.sqrt(27441738) / 27441738) ) );

Prints:

0.0

A thing about the suggested reading, as others have pointed out a good starting point to get information about FP is "What Every Computer Scientist Should Know About Floating-Point Arithmetic" a treatise of floating point operations in detail, although I prefer Computer Representation of Numbers and Computer Arithmetic, which is simpler and more pedagogical, it even starts with a toy fp system that introduce you to the complex concepts of floating point operations.

higuaro
  • 15,730
  • 4
  • 36
  • 43