php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #24876 Round function returns different data
Submitted: 2003-07-30 18:57 UTC Modified: 2003-07-31 14:20 UTC
From: jeff at tmtrading dot com Assigned:
Status: Not a bug Package: Math related
PHP Version: 4CVS-2003-07-30 (stable) OS: Redhat 8.0
Private report: No CVE-ID: None
 [2003-07-30 18:57 UTC] jeff at tmtrading dot com
Description:
------------
php: php4-STABLE-200307301930

gcc: 3.2 20020903 (Red Hat Linux 8.0 3.2-7)

I tried to model the "myround" function after the c code.
I am not a C coder but I managed to get php to output the correct result with the following _hack_.

--- php/ext/standard/math.c     2003-01-16 07:08:59.000000000 -0700
+++ php/ext/standard/math.c     2003-07-30 16:23:44.000000000 -0700
@@ -114,6 +114,7 @@
        zval **value, **precision;
        int places = 0;
        double f, return_val;
+       float fixme_val;

        if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
                zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &precision) == FAILURE) {
@@ -142,10 +143,11 @@
                        f = pow(10.0, (double) places);

                        return_val *= f;
+                       fixme_val = (float) return_val;
                        if (return_val >= 0.0)
-                               return_val = floor(return_val + 0.5);
+                               return_val = floor((double)(fixme_val + 0.5));
                        else
-                               return_val = ceil(return_val - 0.5);
+                               return_val = ceil((double)(fixme_val - 0.5));
                        return_val /= f;

                        RETURN_DOUBLE(return_val);


As you can see the patch is lame.  Since I am not a C programmer I do not know how to figure out why this works vs. the original (it appears correct!).


Reproduce code:
---------------
$numbers = array(4.045, 5.055, 41.045, 51.055);

foreach($numbers as $number) {
    printf("%f : %f : %f\n",$number, round($number,2), myround($number,2));
}

function myround($value, $precision) {
  (int) $places = $precision;
  (double) $f;
  (double) $return_val = (double) $value;

  $f = pow(10.0, (double) $places);
  $return_val *= $f;

  if($return_val >= 0.0)
    $return_val = floor($return_val + 0.5);
  else
    $return_val = ceil($return_val - 0.5);

  $return_val /= $f;
  return $return_val;
}

Expected result:
----------------
[jclark@deadeye cli]$ ./php -n -f test.php
4.045000 : 4.050000 : 4.050000
5.055000 : 5.060000 : 5.060000
41.045000 : 41.050000 : 41.050000
51.055000 : 51.060000 : 51.060000


Actual result:
--------------
[jclark@deadeye cli]$ ./php -n -f ./test.php
4.045000 : 4.040000 : 4.050000
5.055000 : 5.050000 : 5.060000
41.045000 : 41.050000 : 41.050000
51.055000 : 51.050000 : 51.060000


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-07-30 19:12 UTC] jeff at tmtrading dot com
Actually, below would seem to be a better solution.
What I'm trying to point out is that writing a round function in php and the php's standard funtion give two different answers.  That is just plain wrong.
There's probably a better way to fix it, but the patch below works for me (limited testing).

--- php4-STABLE-200307151930/ext/standard/math.c        2003-01-16 07:08:59.000000000 -0700
+++ php4-STABLE-200307301930/ext/standard/math.c        2003-07-30 17:04:50.000000000 -0700
@@ -114,6 +114,7 @@
        zval **value, **precision;
        int places = 0;
        double f, return_val;
+       double fuzz = 0.01;

        if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
                zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &precision) == FAILURE) {
@@ -143,9 +144,9 @@

                        return_val *= f;
                        if (return_val >= 0.0)
-                               return_val = floor(return_val + 0.5);
+                               return_val = floor((return_val + fuzz) + 0.5);
                        else
-                               return_val = ceil(return_val - 0.5);
+                               return_val = ceil((return_val - fuzz) - 0.5);
                        return_val /= f;

                        RETURN_DOUBLE(return_val);
 [2003-07-30 22:16 UTC] sniper@php.net
Round works fine, 4.045 rounded to 2 digits == 4.05.
Not bug.

 [2003-07-31 12:56 UTC] jeff at tmtrading dot com
I am going to assue you are testing on windows instead of linux as I specified.  I downloaded the latest stable snapshot this morning, but this time I also downloaded the windows version.  Windows returns the correct result, RedHat linux 8.0 does not.

The linux (and perhaps other unicies) math libraries return different numbers than windows does.  Thus, if you look at other libraries or math applications which manipulate double's, they always include some amount of "fuzz".

I realize that you guys are trying to go through bugs as quickly as possible, and weeding out the "bogus" ones can be daunting, but please don't close bugs until you have properly reproduced the potential problem.
 [2003-07-31 13:03 UTC] jeff at tmtrading dot com
I appears that this problem is bigger than I thought:

http://www.zend.com/lists/php-dev/200206/msg00831.html

Why is nothing being done about this?
 [2003-07-31 13:18 UTC] sniper@php.net
I tested with Linux. Perhaps you could see the 'problem' better if you adjusted the precision ini setting. (e.g. ini_set('precision', 32); as first line in your script..)

 [2003-07-31 14:02 UTC] jeff at tmtrading dot com
So you are saying I have to deal with type specific problems even though PHP is a high level (loosely typed) language?
Who the hell made that decision?
I'm not trying to do complex math or crunch large numbers.  The language should handle this.
 [2003-07-31 14:20 UTC] jeff at tmtrading dot com
I appoligize for my ignorance on these matters.  I simply don't understand why php has a round function when it does not work as most users would expect or the same on all platforms.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sat Dec 07 07:01:24 2019 UTC