Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Re: Fix floats like you do in your head

by toma (Vicar)
on Dec 26, 2002 at 17:52 UTC ( #222380=note: print w/replies, xml ) Need Help??

in reply to Fix floats like you do in your head

Numerical methods are deceptively difficult. They require exquisite attention to detail to make them work properly. For example, if you are getting dsin(30)=0.49999999999999945 then you have a serious bug.

For most hardware out there, you cannot properly initialize a variable such as pi by entering lots of digits in your program. This is because the internal precision of the machine exceeds the precision that you are normally allowed to print or initialize. So if you catch yourself typing in lots of digits of pi, you are doing something wrong. Here is a better way to do it:

use Math::Trig; my $pi= 4*atan2(1,1); my $deg_to_radian= $pi/180; print sin(30*$deg_to_radian),"\n";
This prints 0.5, as you would hope that it would.

As far as the snippet goes, it is seriously borked. Among other problems, it has problems with the implicit string/numeric conversion that perl uses. This causes it to give different results for


The recent CPAN module Math::SnapTo version 0.02 also has serious errors. For good rounding, use Math::Round. It doesn't do exactly what you want (that is, round like a human), but neither does this snippet or Math::SnapTo.

It should work perfectly the first time! - toma

Replies are listed 'Best First'.
Re: Re: Fix floats like you do in your head
by tachyon (Chancellor) on Dec 27, 2002 at 05:55 UTC

    Yeah, I agree it is seriously borked. As you note Math::Round does a better job than Math::SnapTo so I have scheduled it for deletion :-(

    That said the pi thing is interesting. As your snippet shows using the value of pi from atan2 provides an accurate result. You are not actually using Math::Trig BTW as it has no sin.

    Theoretically speaking as it is impossible to express pi exactly it is also impossible to express 30 degrees in radians exactly so by definition you should not be able to get 0.5 unless there is internal rounding going on.

    As a demonstration of the vagaries of fp decimal math on binary based systems dsin(30) from Math::Trig::Units-0.02 with the hard coded pi returns 0.5 on the system I am on now, whereas it returns the 0.4999..... value on a similar win2k (obvoiusly not identical). Interestingly that system has and Athlon CPU whereas this one has PIII Xeons.

    It appears as though Math::Trig::Units will become Math::Trig in the near future. I have reverted to using atan2(1,1)*4 to get a value for pi (as Math::Trig does) and deleted the kludge subs from it.



      I agree with the Math::SnapTo decision, it didn't seem consistent with your standard of coding excellence!

      IIRC some ancient Intel hardware used to keep something like 80 bits of internal precision, and this was typically rounded to 64 bit IEEE by most compilers in some but not all operations. In this case, internal precision was a huge win!

      When testing multi-platform floating point test code, it is often convenient to account for rounding differences on different platforms. A form of diff called ndiff has been created to "compare putatively similar files, ignoring small numeric differences." I think ndiff would be a useful perl module!

      It should work perfectly the first time! - toma

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://222380]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (2)
As of 2023-09-22 15:13 GMT
Find Nodes?
    Voting Booth?

    No recent polls found