Bug #70173 [Com]: Precision problem in float

From: Date: Sat, 08 Aug 2015 14:32:53 +0000
Subject: Bug #70173 [Com]: Precision problem in float
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-195030@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=70173&edit=1

 ID:                 70173
 Comment by:         rainer dot jung at kippdata dot de
 Reported by:        rainer dot jung at kippdata dot de
 Summary:            Precision problem in float
 Status:             Open
 Type:               Bug
 Package:            *General Issues
 Operating System:   Solaris 10 Sparc
 PHP Version:        7.0.0beta2
 Block user comment: N
 Private report:     N

 New Comment:

OK, another step forward, but I gues that's how far I get without any hints:

Simplest test script:

<?php
$var = 2900000000;
var_dump($var);
?>

Expected result:
----------------
float(2900000000)

Actual result:
--------------
float(2899998720)

It works for PHP 5.6, fails for 7.

- The result of zend_strtod() when printed with fprintf and %f format is
"2900000000.000000". So this is OK.

- The double assignment in Zend/zend_language_scanner.c in line 2757 assigns the correct value
(verified with fprintf and %f). If I call php_var_dump(zendlval, 0) there it writes the correct
string "float(2900000000)".

- In the var_dump() call of next script line, the float argument is already wrong. If checked via
fprointf and %f it is "2899998720.000000". The address of struc in php_var_dump() has also
changed from the previous address of zendlval in zend_language_scanner.c.

I don't know where the change happens, I could just narrow it down so far.

Just to make sure: I don't think this is an expected float precision problem. The test works
for 5.6 and the observed precision is 7 instead of 14. It makes a lot of standard test suite tests
fail.


Previous Comments:
------------------------------------------------------------------------
[2015-08-08 12:53:52] rainer dot jung at kippdata dot de

I added debug statements to zend_strtod(). The call to it gets the correct input string, and if I
print the result before returning with fprintf(stderr, "%f") it is also correct. Only the
var_dump() output float(...) is wrong. So it seems the problem is more about the formatting of float
in var_dump().

------------------------------------------------------------------------
[2015-08-08 12:41:47] rainer dot jung at kippdata dot de

Concerning zend_strtod():

- I first tried the original library available under www.netlib.org/fp. It didn't show the
problem.

- I then tried to shrink the delta between the PHP copy and the original and ended up with a test
case, that doesn't show the problem even with PHP zend_strtod(). So it seems it is something in
PHP before the calls to zend_strtod(), or the problem is in the output rendering of the float.

Here's my test:

1) Create a file dtoa-main.c containing:

#include <stdio.h>
#include <zend_strtod.h>

int main() {
    fprintf(stdout, "%f\n", zend_strtod("29000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("290000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("2900000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("29000000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("290000000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("2900000000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("29000000000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("290000000000000", NULL));
    fprintf(stdout, "%f\n", zend_strtod("2900000000000000", NULL));
}

The numbers are the same as in the test.php I originally use to produce the problem.

Now compile this snippet against the original zend_strtod.o object file:

solaris10.sparc apache% gcc -I /path/to/php/bldir/Zend -I /path/to/php/bldir/TSRM -I
/path/to/php/bldir -Wl,-z -Wl,nodefs -o dtoa-test dtoa-main.c
/path/to/php/bldir/Zend/.libs/zend_strtod.o

The "-z nodefs" linker argument is only needed, because the object file references the
zend_error_noreturn symbol, which is not used in this test case. I didn't want to soak in many
more object files.

Now run the binary:

./dtoa-test
29000000.000000
290000000.000000
2900000000.000000
29000000000.000000
290000000000.000000
2900000000000.000000
29000000000000.000000
290000000000000.000000
2900000000000000.000000

So the float seems to be OK.

------------------------------------------------------------------------
[2015-08-08 11:06:44] rainer dot jung at kippdata dot de

Problem still exists for 7.0.0 Beta 3.

Linux x86_64 builds are fine (as expected).

------------------------------------------------------------------------
[2015-08-03 13:06:41] cmb@php.net

That might be related to the update of Zend/zend_strtod*[1].

[1] <https://github.com/php/php-src/commit/5d4616e2b08f20ce6a582587cf9d3e34775a43a4>

------------------------------------------------------------------------
[2015-07-31 05:53:27] rainer dot jung at kippdata dot de

Description:
------------
A precision problem in float makes a huge number of tests fail. It could well be, that this is a
platform specific failure (Solaris 10 Sparc, 32 Bit build).

Below you will find a test case with correct result returned from version 5.6.11 and wrong result
from 7.0.0 Beta 2.


Test script:
---------------
<?php
$var = 29000000;
var_dump($var);
$var = 290000000;
var_dump($var);
$var = 2900000000;
var_dump($var);
$var = 29000000000;
var_dump($var);
$var = 290000000000;
var_dump($var);
$var = 2900000000000;
var_dump($var);
$var = 29000000000000;
var_dump($var);
$var = 290000000000000;
var_dump($var);
$var = 2900000000000000;
var_dump($var);
?>

Expected result:
----------------
int(29000000)
int(290000000)
float(2900000000)
float(29000000000)
float(290000000000)
float(2900000000000)
float(29000000000000)
float(2.9E+14)
float(2.9E+15)


Actual result:
--------------
int(29000000)
int(290000000)
float(2899998720)
float(28999991296)
float(289999945728)
float(2899998408704)
float(28999988281344)
float(2.899999499223E+14)
float(2.8999984254812E+15)



------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=70173&edit=1


Thread (16 messages)

« previous php.bugs (#195030) next »