kavehmz has asked for the
wisdom of the Perl Monks concerning the following question:
I have these results from several languages all in Intel x86 machine
C++ std math.h cos(100000000.0): 0.363385
Java cos(100000000.0) :0.3633850893556905
Perl cos (100000000.0):0.36338508935581
why Perl is returning last digits wrong, and why it does not truncate it to what it knows it is the last precision it can correctly calculate?
Re: cos (100000000.0)
by moritz (Cardinal) on Sep 01, 2009 at 14:14 UTC

It seems to be just a normal floating point error.
and why it does not truncate it to what it knows it is the last precision it can correctly calculate?
To know how many digits it can calculate correctly it would have to track rounding errors, resulting a large performance penalty. So it doesn't do that, and neither does C++ or Java.
C++ just uses a much more defensive default precision.
Perl 6  links to (nearly) everything that is Perl 6.
 [reply] 
Re: cos (100000000.0)
by ikegami (Pope) on Sep 01, 2009 at 14:25 UTC

Two comments.

First, I get the same answer as Java:
$ perl le'print cos(100000000)'
0.363385089355691
$ perl e'printf "%.16g\n", cos(100000000)'
0.3633850893556905
The underlying C library makes a difference.

Second, floating point numbers don't have a precision field. Assuming it's even possible, accommodating such a field would require a substantial drop in max precision. You are free to track such data yourself, however.
 [reply] [d/l] 

Maybe you answer is different from mine because you are running Perl in another architecture. Are you using a Intel based machine?
And how can I decide, up to what point I can trust Perl calculations?
Becasue it is a different situation that we have intrinsic error in floating point numbers like
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
For that kind of expected problems i am ready to check my values properly.
But for what I get from a call to a language function why should it be careful that it will return a wrong number?
Is there a way that I restrict Perl return values to what is safe for big number without truncating all return numbers from native Perl functions by myself?
And when Perl is returning numbers in this fashion can I be sure that if I use bigger numbers, the error wont grow to make more wrong digits?
 [reply] 

Maybe you answer is different from mine because you are running Perl in another architecture. Are you using a Intel based machine?
I've already said it's the underlying C library that makes the difference for cos().
And how can I decide, up to what point I can trust Perl calculations?
It's my understanding that libraries often approximate the result of trig functions. In Perl's case, it uses the underlying C library. I don't know what kind of precision guarantees (if any) C makes concerning its trig functions. Feel free to look it up.
And when Perl is returning numbers in this fashion can I be sure that if I use bigger numbers, the error wont grow to make more wrong digits?
I don't understand the question. You single out the previously discussed manner or returning numbers, but no ways of returning numbers were previously discussed. What does Perl returning numbers even mean? What are the other manners in which Perl returns numbers to which you allude?
Is there a way that I restrict Perl return values to what is safe for big number without truncating all return numbers from native Perl functions by myself?
The premise makes no sense. Truncating and rounding reduce precision.
Actual: 0.3633850893556905538...
Java's error: 0.0000000000000000538...
Your C's error: 0.0000000000001194462...
Rounded error: 0.0000000000003094462...
Truncated error: 0.0000000000006905538...
Besides that, the precision of the result of each operation depends on the precision of the result of each operand of that operation. Neither Perl nor the computer know the precision of the operands, so it can't know the precision of the output.
 [reply] [d/l] 

Maybe you answer is different from mine because you are running Perl in another architecture.
I am running perl in a different architecture (amd64), and I get the same result as you for perl:
C:\_32>perl e "print cos(100000000.0)"
0.36338508935581
I'm on Win32, and that's using the Microsoft C runtime library (msvcrt.dll). If I instead use the mpfr library, then I get the correct result:
C:\_32>perl MMath::MPFR e "$x=Math::MPFR>new(100000000.0);print cos
+($x)"
3.6338508935569053e1
Cheers, Rob  [reply] [d/l] [select] 
Re: cos (100000000.0)
by kennethk (Abbot) on Sep 01, 2009 at 15:01 UTC

Did you try checking out the site archives? For example, yesterday someone asked a very similar question with An arithmetic oddity and a Super Search for precision yields a large number of results, and the first one (int($x) gives strange result) is a good discussion of exactly this issue.
Please read up on how floating point arithmatic works  for example What Every Computer Scientist Should Know About FloatingPoint Arithmetic. I suspect that in C++ you are invoking the single precision cosine function (or maybe just the singleprecision string format for output) and double precision in Java and Perl  doesn't it strike you as odd that it returns half as many digits? And I would like to know why you think any of those are more or less accurate  have you actually calculated the analytical answer? And what are you trying to do that requires 16 digits of precision  the Planck constant is only known to 8.
In short, what are you really trying to do? This sounds a lot like an XY Problem to me.  [reply] 
Re: cos (100000000.0)
by FunkyMonk (Canon) on Sep 01, 2009 at 23:26 UTC

Given the points about floating point numbers that other Monks have mentioned, there's a few points I'd like to raise:
 Why are you taking the cosine of 100 million radians? I cannot think of any valid reason for doing that.
 Why do you care that the answer has an error of 1 part in 1,000,000,000,000?
 Why do you assume that it's perl that has the wrong answer?
Finally, my 64bit perl running on AMD gives:
$ perl le 'printf "%.55f\n", cos(100_000_000.0)'
0.3633850893556905270465051671635592356324195861816406250
Thus proving that Perl >> Java >> C++, AMD >> Intel and that Thursday is the new pink :)  [reply] [d/l] 

Why are you taking the cosine of 100 million radians? I cannot think of any valid reason for doing that.
Amen to that.
To the OP: trigonometric functions are about the most unreliable calculations that you can do on a computer. I think it is just not reasonable to expect very precise results, for such a huge parameter value. Actually, the difference in results between the different implementations is a lot smaller, than I had anticipated.
Floating point in Perl has about 15 significant digits. For a function like cos, the digits before the decimal point don't really matter, as you may just as well use the parameter value modulo 2*PI, and (ideally) expect the same outcome. That means that for this parameter, with 8 digits wasted, you have about 67 significant digits left. That is how close you may expect the result of the calculation of cos to be.
I am guessing you just made that parameter up, as a silly test.
 [reply] [d/l] [select] 
Re: cos (100000000.0)
by biohisham (Priest) on Sep 01, 2009 at 18:43 UTC

There's something related to Arbitraryprecision Arithmetic, I am not strong in Maths but from this query I got me curious and I found out that perl can allow you to use that sort of precision Arithmetic, please see, Arithmetic.
I know that negating 0 would give you the unsigned integer capacity of your machine, if this is got to do with addressing your problem, then I hope I have been able to contribute and I'd be happy, otherwise, I'd be happy as well if someone corrected me.
printf "%e", ~0;
Excellence is an Endeavor of Persistence.
Chance Favors a Prepared Mind.
 [reply] [d/l] 

I know that negating 0 would give you the unsigned integer capacity of your machine, if this is got to do with addressing your problem,
Both numbers fit into a doubleprecision float (the minimum size Perl uses for floats), so it's not a question of machine precision. It's a question of the precision/accuracy of the cos function.
Note that the Config module provides information on the size of number types used internally.
$ perl V:ivsize 4: 2**(4*81) .. 2**(4*81)1
ivsize='4'; 8: 2**(8*81) .. 2**(8*81)1
$ perl V:uvsize 4: 0 .. 2**(4*8)1
uvsize='4'; 8: 0 .. 2**(8*8)1
$ perl V:nvsize 8: double, 53 bits of precision
nvsize='8'; 16: quad, 113 bits of precision
 [reply] [d/l] [select] 

