3

Does anyone know why this happens and if it can be fixed. I'm comparing results from C and PHP, but PHP is giving me different results.

I can supply some code if needed but has anyone experienced this before?

PHP code

$tempnum = 1.0e - 5 * -44954; // substr($line1,53,6);
$bstar = $tempnum / pow(10.0, 3);

$bstar gives me -0.00044954 in PHP but it should be -0.000450

C code

double tempnum = 1.0e - 5 * -44954;
double bstar = tempnum / pow(10.0, 3);

printf bstar gives me -0.000450

Thanks for your responses so far, but how does PHP come to this conclusion...

$twopi =        6.28318530717958623;    /* 2*Pi  */
$xmnpda=        1440; //1.44E3  ;       /* Minutes per day */

$temp = (($twopi/$xmnpda)/$xmnpda);

$xndt2o = -0.000603;
$xndt2o = $xndt2o * $temp;

echo $xndt2o gives me -1.8256568188E-9 in PHP but in C it gives me -0.000000

I don't know what all that is about in PHP.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 1
    possible duplicate of [The accuracy of PHP float calculate](http://stackoverflow.com/questions/3957705/the-accuracy-of-php-float-calculate) and hundreds of other variants on this question – Mark Baker Jan 23 '11 at 23:37
  • You should supply code right now. And tell us how they differ, what the results are and what you expect. (Also: PHP is implemented in C, it propably uses C doubles under the hood.) –  Jan 23 '11 at 23:37
  • 1
    We also need to see the equivalent C. – Oliver Charlesworth Jan 23 '11 at 23:43
  • I have supplied the code i am using. –  Jan 23 '11 at 23:45
  • You haven't fully - the C code won't compile. The format string is very important. – nobody Jan 24 '11 at 00:25
  • `pow(x, y)` may be implemented simply by `exp(y*log(x))` so the result will not be as correct as one expected http://stackoverflow.com/q/9704195/995714 http://stackoverflow.com/q/7937286/995714 – phuclv Sep 03 '15 at 05:20
  • Possible duplicate of [Why are floating point numbers inaccurate?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – Jonathan Hall Feb 15 '19 at 15:48

3 Answers3

3

Limited-precision floating-point formats are almost always slightly inaccurate, and these inaccuracies can compound each other and manifest in unexpected ways. Usually, the results are not so much wrong, but the only problem is that you did not expect the inaccuracies. For a general explanation, read The Floating-Point Guide.

Perhaps most relevant to your question: sequences of calculations should never be expected to yield exactly the same result across platforms, as there are many factors that can lead to different actual primitive operations being performed. This paper explains it in great detail..

A much simpler explanation for the difference you're seeing might be that the PHP code is somehow only using a 32 bit float somewhere, because the difference is showing up around the 6th/7th decimal, right where the accuracy of 32bit floats ends.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • but the calculations are the same in PHP and C, PHP was written in C so I would expect the same results. –  Jan 24 '11 at 00:18
  • 1
    @Carl: well, your expectations are wrong. That happens a lot with floating-point arithmetic. Do take a look at the paper I linked to. – Michael Borgwardt Jan 24 '11 at 00:20
  • My rule of thumb: Never trust floating point calculations with your life ;) All floating point arithmetic are inaccurate. This is an inherent limitation of representing a decimal number to a binary. This affects ALL programming languages (not just PHP and C), it is just a matter of how many bits can they give before bumping into this limitation. The Floating-Point guide is indeed a great read. – Ardee Aram Jun 22 '11 at 08:10
  • @azure_ardee: *all* number formats are inaccurate, since none of them can represent even the entirety of the integers, let alone rational or real numbers. The problem with binary floating-point formats is that they are inaccurate in *unexpected ways*, mainly having to do with the difference between binary and decimal representations. – Michael Borgwardt Jun 22 '11 at 11:01
2

The equivalent C code gives the same result if you tell printf to display more digits:

printf("%.8f\n", bstar);
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • @Carl, show us the printf you are using. If you are doing %.8f then you will only show 8 digits past the decimal point. The result of the calculation is something * 10^-9 which would require using more digits in the printf format string. – Doug T. Jan 23 '11 at 23:56
  • @Carl: It's simply display precision again. Try `printf("%g\n");`. – Oliver Charlesworth Jan 23 '11 at 23:59
  • @Oli OK if I do
    printf("xndt2o: %g\n", xndt2o);
    
    it gives me -0.00060251 and after my calculations it gives me -1.82566e-009
    
    
    –  Jan 24 '11 at 00:02
  • -0.00060251 is the same in php but as you can see -1.82566e-009 isn't the same in PHP and after about 500 lines of calculations in PHP my results are right off when the code is identical to the C code.. –  Jan 24 '11 at 00:08
  • @Oli Charlesworth I know how to use them in C, the only reason I am using printf is so I can compare the C result with PHP. I want my code to work in PHP not C. So regardless of how I tell C to print the precision, in the end, the results in PHP are right off. –  Jan 24 '11 at 00:21
  • @Carl: So far, your only code examples have simply been to do with how you've been displaying the numbers in C (which is what led me to believe that you don't understand how to use `printf`). Without seeing your actual code, no-one can help you fix the issue. I would suggest tracking down at what point in your "500 line calculation" the results start to diverge, and then edit your question accordingly. – Oliver Charlesworth Jan 24 '11 at 00:23
  • @Oli Charlesworth this is what I am guessing now because with your help, so far I got the same results in php and c if I play about with the precision when using printf in C. I am guessing i've missed something out somewhere or i am doing a calculation different when I converted the C code to PHP. There is about 1000 lines in total so this is going to be painstaking to print each line and compare the results. And as you say determine when the results start to diverge. –  Jan 24 '11 at 00:28
  • @Carl: Use a "binary chop". First see if the results are right after 500 lines. Depending on the result, look at line 250 or 750, and so on. It should only take 10 debugging points! – Oliver Charlesworth Jan 24 '11 at 00:33
  • @Oli Charlesworth Thanks for your help so far. I copied each line from C one at a time hoping it would work first time. I should have known better. Thanks again and I will keep you updated. –  Jan 24 '11 at 00:48
  • @Oli Charlesworth I think this is an actual problem with PHP because I am using very large numbers to calculate complex lat lon positions. I might need to use the BCMath functions or the proj4 plugin for PHP. Just a thought –  Jan 24 '11 at 01:00
  • @Oli Charlesworth - I was missing a couple of (int) casts from floats plus my answer below. Thank you so much for your replies. –  Jan 24 '11 at 03:17
0

Thank you so much for your help guys. I have figured it out.

Sometimes you need to work with big numbers in PHP. For example, sometimes 32-bit identifiers are not enough and you have to use BIGINT 64-bit.

I had already written about the mess that 64-bit integers are in PHP. But if the numbers you use do not cover 64-bit range fully, floats might save the day. The trick is that PHP floats are in fact doubles, i.e. double-precision 64-bit numbers. They have 52 bits for mantissa, and integer values up to 2^53-1 can be stored exactly. So if you’re using up to 53 bits, you’re OK with floats.

However, there’s a conversion caveat you should be aware of.

Float to string conversion is not portable across systems and PHP versions. So if you’re handling large numbers stored as float (especially on 32-bit systems where 32-bit int overflow will implicitly convert to float) and getting strange results, remember that string conversion might let you down. sprintf(), on the other hand, is always a friend when it comes to fixing PHP “subtleties” in numeric value handling: it can be used to workaround signed vs. unsigned int issues; it helps with float formatting; always a saviour.

References - MySQL Performance Blog