P: n/a

Hi all
I was helping my niece with her trigonometry homework last night. Her
calculator's batteries were flat, so I thought I would use Python's
math module to calculate sin, cos, and tan.
I tried the example in the text book first, to ensure that I was
getting the correct result, but it did not agree. Then my wife had the
idea of using the Microsoft calculator in scientific mode, and that
one did give the correct result.
Here are some examples 
sin(32) 
Python 0.55142668
Microsoft 0.52991926
cos(32) 
Python 0.83422336
Microsoft 0.84804809
tan(32) 
Python 0.66100604
Microsoft 0.62486935
Version is Python 2.3.3. I get the same results on Linux and on
Windows 2000. I also get the same results using the cmath module.
Can someone please explain these discrepancies?
Thanks
Frank Millman  
Share this Question
P: n/a
 fr***@chagford.com (Frank Millman) writes: sin(32)  Python 0.55142668 Microsoft 0.52991926
Python's number is the sin of 32 radians which is the same as the sin
of 0.584 radians. Microsoft's is the sin of 32 degrees which is 0.558
radians, so the results are coincidentally fairly close to one
another. Math libraries usually take args in radians while
calculators usually let you select between radians and degrees.
cos(32)  Python 0.83422336 Microsoft 0.84804809
tan(32)  Python 0.66100604 Microsoft 0.62486935
Same thing.  
P: n/a

Frank Millman wrote: Hi all
I was helping my niece with her trigonometry homework last night. Her calculator's batteries were flat, so I thought I would use Python's math module to calculate sin, cos, and tan.
I tried the example in the text book first, to ensure that I was getting the correct result, but it did not agree. Then my wife had the idea of using the Microsoft calculator in scientific mode, and that one did give the correct result.
Here are some examples 
sin(32)  Python 0.55142668 Microsoft 0.52991926
Version is Python 2.3.3. I get the same results on Linux and on Windows 2000. I also get the same results using the cmath module.
Can someone please explain these discrepancies?
Both are "correct" if you know what you have been asking for.
In standard mathematics the argument to a trigonometric function like
sin, cos, tan, ... is in radians (!)
This is even the case with most pocket calculators but there you can switch
modes.
In the example above, Microsoft  something special as ever  seems to expect
the argument in degrees (which is quite unusual)
Since an argument in radians normally is between 0 and 2*pi or between pi and pi,
an argument of 32 is unusual for a radians argument though perfectly legal.
If your input is in degrees, define
def mysin(x)
return math.sin(x/pi*180) # 1 degree = 180/pi radians (don's use x/180*pi)
now
print mysin(32) gives 0.529919264233

Helmut Jarausch
Lehrstuhl fuer Numerische Mathematik
RWTH  Aachen University
D 52056 Aachen, Germany  
P: n/a

Helmut Jarausch <ja******@igpm.rwthaachen.de> wrote in message Both are "correct" if you know what you have been asking for. In standard mathematics the argument to a trigonometric function like sin, cos, tan, ... is in radians (!)
There was some discussion about this recently over in
comp.lang.fortran, arising when someone queried sin/cos/tan etc for
very large angles (represented in floating point, eg: sin(1.0E18)).
Reduction (angle modulo 2pi) is considerably easier if you use a
*rational* unit for measuring angles, as the answer can remain exact
in terms of the particular number represented in floating point.
Without using an irrational number, exact representations of angles
can actually exist where you also have exact representations of sines
and cosines. With radians you can only represent zero exactly, and
below it seems not even that!
Can someone supply a real concrete example where there is a reason to
prefer radians when computing sin/cos/tan? (Not their derivatives!)
The latter of the three examples is most disappointing:
C:\>python
Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information. from math import sin,asin,pi sin(pi/6) # == 0.5
0.49999999999999994 degrees(asin(0.5)) # == 30
30.000000000000004 sin(pi) # == 0
1.2246063538223773e016
I understand why this fails  I just think the world is wrong.
Represent angles using some rational fraction of a circle and all this
crap goes away. Why convert to a unit which eliminates the possibility
of an exact representation of any result at all?
In the example above, Microsoft  something special as ever  seems to expect the argument in degrees (which is quite unusual)
The microsoft calculator has a checkbox for switching between degrees
and radians and gets all of the analytical results above correct. We
live in a mad world....
Jon  
P: n/a

On 23 Jul 2004, Jon Wright wrote: There was some discussion about this recently over in comp.lang.fortran, arising when someone queried sin/cos/tan etc for very large angles (represented in floating point, eg: sin(1.0E18)). Reduction (angle modulo 2pi) is considerably easier if you use a *rational* unit for measuring angles, as the answer can remain exact in terms of the particular number represented in floating point.
Reduction... from 1.0e18?! Of course that doesn't work with radians, it
doesn't even works with degrees! 64bit floating point numbers are only
accurate to +64.0 at that magnitude: (1.0e18+45)1.0e18
0.0 (1.0e18+90)1.0e17
128.0
Without using an irrational number, exact representations of angles can actually exist where you also have exact representations of sines and cosines. With radians you can only represent zero exactly, and below it seems not even that!
So don't store your angles as radians. Mangle them, reduce them, whatever
if degrees / grads, and then convert them to radians before passing them
to the trig functions.
Can someone supply a real concrete example where there is a reason to prefer radians when computing sin/cos/tan? (Not their derivatives!)
Because that's how the processor does it. If degrees were used in the
library, every sin() would have to be prefixed at the assembly level with
a multiply.
Derivates (and other mathematical reasons) are also perfectly valid
example. Every math / physics formula involving trigonometry uses
radians. If sin() accepted degrees, every formula I expressed in Python
would be littered with radian > degree conversions. Quite confusing for
a researcher picking up Python for the first time. Python's done a good
job at winning over academia (mostly due to Numeric and numarray);
switching to degrees is a step in the wrong direction.
I'll skip over the obvious argument of purity here (i.e. switching trig
functions to degrees is the equivalent of switching to 1based array
indexing).
The latter of the three examples is most disappointing:
C:\>python Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. from math import sin,asin,pi sin(pi/6) # == 0.5 0.49999999999999994 degrees(asin(0.5)) # == 30 30.000000000000004 sin(pi) # == 0 1.2246063538223773e016
I understand why this fails  I just think the world is wrong. Represent angles using some rational fraction of a circle and all this crap goes away. Why convert to a unit which eliminates the possibility of an exact representation of any result at all?
.2
0.20000000000000001
The error in your calculations is of the same order of magnitude as that
of the error introduced by the representation of numbers as floating point
(not surprisingly, since the magnitude of the error of the value of pi is
caused by that same feature), and is therefore, for all practical
purposes, irrelevant.
What's more, because any method of calculating sines (including that used
by the processor) requires that its arguments be in radians, there's no
way around this error, no matter how hard you try (unless, of course, you
implement an 80 or even 128bit floating point arithmetic library, in
which case it won't be included in Python because it will be an order of
magnitude slower than using the math coprocessor).
The microsoft calculator has a checkbox for switching between degrees and radians and gets all of the analytical results above correct. We live in a mad world....
I'm certain that's because it limits (reasonably) the accuracy of its
output, just like Python can do:
print sin(pi/6) # == 0.5
0.5 print degrees(asin(0.5)) # == 30
30.0 print sin(pi) # == 0
1.2246063538223773e016
Oops, that last one didn't work. How about:
'%.15f'%sin(pi)
'0.000000000000000'
Personally, I'd like to see an application where any accuracy greater than
that is needed... and anyways, just how often do you expect angles of 30,
45, 60, and 90 degrees to come up in regular calculations? The chance of
one of them occuring randomly is infinitesmally small (except for in
highschool geometry homework, of course), and when they do come up
deterministically in a formula, they are almost always optimized out of
the equation.  
P: n/a

[Christopher T King] ... Reduction... from 1.0e18?! Of course that doesn't work with radians, it doesn't even works with degrees!
Actually, it can. If you view a floatingpoint number as being
exactly what it says it is, then of course there's an exact reduction
of that number modulo pi. Very highquality math libraries compute
that too. I know because I wrote one <wink>. The popular fdlibm
(from Netlib) does "asif infinite precision" trig argument reduction
too. The details can be excruciating. You (of course) need to know
pi to greater than machine precision, but not to as much greater as
you may think: across all possible 754 doubles, you can find the one
closest to being an exact multiple of pi, and you only need to use
enough extra precision to get the right answer (to machine precision)
in that worst case. At least 3 groups have discovered that
independently (I was one of them, discovered when writing a libm for
Kendall Square Research in the early 90's, in collaboration with Peter
Tang).
IIRC, Mary Payne at DEC was the first to implement "infinite
precision" trig argument reduction in a commercial math library, and
she wrote a very readable paper about it I'm unable to find now. She
wasn't able to put an a priori bound on the amount of precision
needed, so it was less efficient than later attempts.
All in all, and despite having pushed the state of the art there
myself, it's a silly thng to bother with <wink>.  
P: n/a

On Fri, 23 Jul 2004, Tim Peters wrote: If you view a floatingpoint number as being exactly what it says it is,
then I have a proof that 1==2 to show you... ;)  
P: n/a

Helmut Jarausch <ja******@igpm.rwthaachen.de> wrote in message news:<41**************@igpm.rwthaachen.de>...
.... If your input is in degrees, define
def mysin(x) return math.sin(x/pi*180) # 1 degree = 180/pi radians (don's use x/180*pi)
now print mysin(32) gives 0.529919264233
x/180*pi _is_ correct. Your formula gives mysin(32) = 0.9408618465702292.
Btw, another way to write this is:
def mysin(x):
return math.sin(math.radians(x))  
P: n/a
 da*****@yahoo.com (Dan Bishop) wrote in message news:<ad**************************@posting.google. com>... Helmut Jarausch <ja******@igpm.rwthaachen.de> wrote in message news:<41**************@igpm.rwthaachen.de>... ... If your input is in degrees, define
def mysin(x) return math.sin(x/pi*180) # 1 degree = 180/pi radians (don's use x/180*pi)
now print mysin(32) gives 0.529919264233
x/180*pi _is_ correct. Your formula gives mysin(32) = 0.9408618465702292.
Btw, another way to write this is:
def mysin(x): return math.sin(math.radians(x))
Even better:
def mysin(x):
return math.sin(math.radians(x % 360))  
P: n/a
 da*****@yahoo.com (Dan Bishop) wrote in message news:<ad**************************@posting.google. com>... Helmut Jarausch <ja******@igpm.rwthaachen.de> wrote in message news:<41**************@igpm.rwthaachen.de>... ... If your input is in degrees, define
def mysin(x) return math.sin(x/pi*180) # 1 degree = 180/pi radians (don's use x/180*pi)
now print mysin(32) gives 0.529919264233
x/180*pi _is_ correct. Your formula gives mysin(32) = 0.9408618465702292.
Btw, another way to write this is:
def mysin(x): return math.sin(math.radians(x))
Even better:
def mysin(x):
return math.sin(math.radians(x % 360))  
P: n/a

On 23 Jul 2004 23:00:18 0700, da*****@yahoo.com (Dan Bishop) wrote: da*****@yahoo.com (Dan Bishop) wrote in message news:<ad**************************@posting.google. com>...
def mysin(x): return math.sin(math.radians(x))
Even better:
def mysin(x): return math.sin(math.radians(x % 360))
Why? for x in range( 20 ):
print '%.12f %.12f' % (math.sin( math.radians( x ) ), math.sin( math.radians( x % 360 ) ))
0.000000000000 0.000000000000
0.017452406437 0.017452406437
0.034899496703 0.034899496703
0.052335956243 0.052335956243
0.069756473744 0.069756473744
0.087155742748 0.087155742748
0.104528463268 0.104528463268
0.121869343405 0.121869343405
0.139173100960 0.139173100960
0.156434465040 0.156434465040
0.173648177667 0.173648177667
0.190808995377 0.190808995377
0.207911690818 0.207911690818
0.224951054344 0.224951054344
0.241921895600 0.241921895600
0.258819045103 0.258819045103
0.275637355817 0.275637355817
0.292371704723 0.292371704723
0.309016994375 0.309016994375
0.325568154457 0.325568154457
Regards,
Dan

Dan Sommers
<http://www.tombstonezero.net/dan/>
Never play leapfrog with a unicorn.  
P: n/a

Frank Millman wrote: Hi all
I was helping my niece with her trigonometry homework last night. Her calculator's batteries were flat, so I thought I would use Python's math module to calculate sin, cos, and tan.
Can someone please explain these discrepancies?
Thank you so much for the explanations, everyone. I appreciate your
patience.
I agree with Timothy's suggestion about adding a note to the
documentation. Obviously the math module is designed for those that
know what they are doing. However, you will always get the odd guy
like me that has some vague recollection of trigonometry from school
days, but does not really understand it, so it should help to avoid
similar confusion in the future.
Frank  
P: n/a

Dan Sommers wrote: On 23 Jul 2004 23:00:18 0700, da*****@yahoo.com (Dan Bishop) wrote: def mysin(x): return math.sin(math.radians(x % 360))
Why?
for x in range( 20 ): print '%.12f %.12f' % (math.sin( math.radians( x ) ), math.sin( math.radians( x % 360 ) ))
0.000000000000 0.000000000000 0.017452406437 0.017452406437 0.034899496703 0.034899496703 0.052335956243 0.052335956243 0.069756473744 0.069756473744 0.087155742748 0.087155742748 0.104528463268 0.104528463268 0.121869343405 0.121869343405 0.139173100960 0.139173100960 0.156434465040 0.156434465040 0.173648177667 0.173648177667 0.190808995377 0.190808995377 0.207911690818 0.207911690818 0.224951054344 0.224951054344 0.241921895600 0.241921895600 0.258819045103 0.258819045103 0.275637355817 0.275637355817 0.292371704723 0.292371704723 0.309016994375 0.309016994375 0.325568154457 0.325568154457 for x in range(10000000, 10000020): print '%.12f %.12f' %
(math.sin( math.radians( x ) ), math.sin( math.radians( x % 360 ) ))
0.984807753010 0.984807753012
0.981627183449 0.981627183448
0.978147600733 0.978147600734
0.974370064789 0.974370064785
0.970295726278 0.970295726276
0.965925826288 0.965925826289
0.961261695942 0.961261695938
0.956304755964 0.956304755963
0.951056516293 0.951056516295
0.945518575604 0.945518575599
0.939692620787 0.939692620786
0.933580426495 0.933580426497
0.927183854571 0.927183854567
0.920504853453 0.920504853452
0.913545457639 0.913545457643
0.906307787041 0.906307787037
0.898794046299 0.898794046299
0.891006524183 0.891006524188
0.882947592863 0.882947592859
0.874619707138 0.874619707139
When the numbers get larger, floats start losing precision. If you
restrict the numbers to the range [0, 360[ before conversion to radians
(and hence to degrees), that problem doesn't exist.

"Codito ergo sum"
Roel Schroeven  
P: n/a

Roel Schroeven wrote: When the numbers get larger, floats start losing precision. If you restrict the numbers to the range [0, 360[ before conversion to radians (and hence to degrees), that problem doesn't exist. (360**100 +0.0) % 360
184.0
Rule of thumb: floats are always inaccurate. % may only help when you are
dealing with large integers denoting an angle in degrees  an unlikely
scenario methinks.
Peter  
P: n/a

Peter Otten wrote: Roel Schroeven wrote:
When the numbers get larger, floats start losing precision. If you restrict the numbers to the range [0, 360[ before conversion to radians (and hence to degrees), that problem doesn't exist.
(360**100 +0.0) % 360
184.0
Rule of thumb: floats are always inaccurate. % may only help when you are dealing with large integers denoting an angle in degrees  an unlikely scenario methinks.
Ok, you're right, I only considered the case where the input is
specified in degrees.
Anyway, when dealing with angles it's in most cases very well possible
to keep the values small by doing % 360 or % (2*pi) in all relevant
operations on the angles.

"Codito ergo sum"
Roel Schroeven  
P: n/a

Dan Sommers <me@privacy.net> wrote in message news:<m2************@unique.fully.qualified.domain .name.yeah.right>... On 23 Jul 2004 23:00:18 0700, da*****@yahoo.com (Dan Bishop) wrote:
da*****@yahoo.com (Dan Bishop) wrote in message news:<ad**************************@posting.google. com>...
def mysin(x): return math.sin(math.radians(x)) Even better:
def mysin(x): return math.sin(math.radians(x % 360))
Why? for x in range( 20 ): print '%.12f %.12f' % (math.sin( math.radians( x ) ), math.sin( math.radians( x % 360 ) )) [2 identical columns]
It's not suprising that they're identical: When 0 <= x < 360, then x % 360 == x.
However, x = 360000000000L # a billion revolutions math.sin(math.radians(x))
6.6394736764063769e08 math.sin(math.radians(x % 360))
0.0  
P: n/a

On 24 Jul 2004 12:44:30 0700, da*****@yahoo.com (Dan Bishop) wrote: Dan Sommers <me@privacy.net> wrote in message news:<m2************@unique.fully.qualified.domain .name.yeah.right>... On 23 Jul 2004 23:00:18 0700, da*****@yahoo.com (Dan Bishop) wrote:
> da*****@yahoo.com (Dan Bishop) wrote in message news:<ad**************************@posting.google. com>... >> def mysin(x): >> return math.sin(math.radians(x))
> Even better:
> def mysin(x): > return math.sin(math.radians(x % 360))
Why?
>>> for x in range( 20 ): print '%.12f %.12f' % (math.sin( math.radians( x ) ), math.sin( math.radians( x % 360 ) )) [2 identical columns]
It's not suprising that they're identical: When 0 <= x < 360, then x % 360 == x.
Yes, obviously, no surprise there. Duh! (smacks self on forehead)
I do, hoever, agree with Peter Otten about very large integers denoting
angles in degreen being unlikely. Usually, the 'mod 2pi' ends up in the
calculation of the angle rather than in the call to math.<whatever>.
Regards,
Dan

Dan Sommers
<http://www.tombstonezero.net/dan/>
Never play leapfrog with a unicorn.   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 1913
 replies: 16
 date asked: Jul 18 '05
