upiterbarg / mpmath

Automatically exported from code.google.com/p/mpmath
Other
0 stars 0 forks source link

Trig and equality #247

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
I'm running this:

import unittest
from mpmath import *

class Test(unittest.TestCase):

    def testBasicMaths(self):
        assert (sqrt(3) * sin(acos(1/sqrt(3))) * sin(pi/4)).ae('1')
        print( sqrt(3) * sin(acos(1/sqrt(3))) * sin(pi/4))
        assert sqrt(3) * sin(acos(1/sqrt(3))) * sin(pi/4) == 1.0

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

What is the expected output? What do you see instead?
I expect this:
Finding files... done.
Importing test modules ... done.

1.0
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

I get this:
Finding files... done.
Importing test modules ... done.

1.0
======================================================================
FAIL: testBasicMaths (Coordinates.Test1.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "H:\git\StarClash\Space Clash - Client\src\Coordinates\Test1.py", line 14, in testBasicMaths
    assert sqrt(3) * sin(acos(1/sqrt(3))) * sin(pi/4) == 1.0
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.010s

FAILED (failures=1)

For some reason 1.0 even though its very very close to 1, its just not quite 
close enough to give not fail the test.

What version of the product are you using? On what operating system?
0.18 on Python 3.3 on Windows 7

Please provide any additional information below.

Original issue reported on code.google.com by GavinBra...@gmail.com on 15 Jan 2014 at 11:13

GoogleCodeExporter commented 9 years ago
One thing, if I set mp.dps=156 then it starts working (although 156 decimal 
places seems a little over the top).

Original comment by GavinBra...@gmail.com on 15 Jan 2014 at 11:23

GoogleCodeExporter commented 9 years ago
This is not a bug. You can generally only expect the result of a floating-point 
calculation to be an approximation of the mathematically exact result, and the 
print function deliberately discards a couple of digits to hide the effects of 
small rounding errors (just as it does for Python's built-in floats). To see 
that the number is different from 1.0, use repr() instead:

>>> repr(sqrt(3) * sin(acos(1/sqrt(3))) * sin(pi/4))
"mpf('0.99999999999999978')"

Original comment by fredrik....@gmail.com on 16 Jan 2014 at 6:59

GoogleCodeExporter commented 9 years ago
Yeah, that's also what I had worked out - I'd read about repr, but forgotten 
about it.

Weirdly, this calculation appears to be dependent on the precision as to 
whether it equates to 1, or very very nearly 1 (but not quite).

For example, I've found that setting mp.dps=8 make this work.
A higher level of precision changes it into 0.999<other bits>
Then it turns back into 1.0 at mp.dps=156

I guess I'll have to choose a level of precision I am happy with, and 
potentially use the ae functionality for checks rather than 

Original comment by GavinBra...@gmail.com on 16 Jan 2014 at 9:33

GoogleCodeExporter commented 9 years ago
The result will be a pseudorandom number close to 1. So by random chance, it 
will be slightly smaller than 1 at some precisions, slightly larger than 1 at 
some precisions, and exactly equal to 1 at some precisions. Choosing a 
precision where it just happens to work is not a reliable solution. The correct 
solution is to check that the result is close to 1 (for example using ae()).

Original comment by fredrik....@gmail.com on 16 Jan 2014 at 9:41

GoogleCodeExporter commented 9 years ago
OK, I accept that.
Can you close the ticket please?

Original comment by GavinBra...@gmail.com on 16 Jan 2014 at 11:25

GoogleCodeExporter commented 9 years ago
Sure. Thanks for the feedback.

Original comment by fredrik....@gmail.com on 16 Jan 2014 at 11:33