Has the following fix for php's fp decimal arithmetic problems been considered?

Fix:
---

Numeric rounding to DBL_DIG decimal digits of  the results of
php's arithmetic operators via a redecimalize function:

  double redecimalize(double dval)
  {
    double f;
    if (dval == 0)
   {
      return dval;
   }
   f = pow(10.0, DBL_DIG - (1 + floor(log10(fabs(dval)))));
   return (double) (rint(dval*f))/f;
  }


Benefits:
------

1. Eliminates the decimal/binary fp issues:
i.e. the problems with comparison operators
(0.8 == 0.7 + 0.1 etc.); the problems with floor(), ceil(),
intval() and round(); the spurious result for 0.8 - (0.7 + 0.1);
and the cumulative loss of precision on long sequences of
arithmetic operations attributable to conversion errors.

2. Improved consistency in php's type handling, e.g. $a == $b
is sensible regardless of type.

3. Simplifies documentation.

4. Protects the newbie.

5. Provides a clear comparative advantage for php over Perl,
Javascript etc. in decimal/money arithmetic.

Costs:
----

1. Performance.
Although redecimalize() is about 15 times faster than the equivalent
atof(sprintf..., there is still a performance cost for each php arithmetic
operation of 10-30% depending on operands.

This is less than the cost of an object/array variable access i.e.
Fixed: $a = $b +$c
is quicker than:
Unfixed: $a = $b + $c->d

redecimalize() could be optimized to improve performance
further.

2. Code Changes.
One source, zend_operators.c, needs modification with the addition
of  about 20 lines of code i.e.
the redecimalize function shown above plus the following line
repeated twice for each arithmetic operator, (add_function, sub_function,
mul_function and div_function):-
    result->dval = redecimalize(result->dval);

3. Build Requirements.
The extra build requirements for zend_operators.c are to
find float.h for DBL_DIG, and  to pick up rint() from a maths library.
(rint() is used to ensure that the floating point round mode is respected
for compatibility with convert_to_string.).  If either of these
are problematic I guess we can get round them, though it would
be a pain to handle all the variants of round mode ourselves.



Where next?
--------
You'll notice that the version of redecimalize shown above is
far from optimal.  Most of the performance cost is in
calculating 'f', which could probably be made much faster,
e.g. by estimating log10 from the double's exponent.

I've only mentioned the arithmetic operators so far as they
are by far the most important, but this could easily be
extended to the appropriate mathematical functions e.g
pow(), log(), cosh().

The fix works for me with 4.2.1 on Linux, but I haven't
tried it on any other platforms.

However, I'm not keen to do much more unless I know
that this approach hasn't been ruled out in the past for
some reason of which I am not aware.

Comments please!


George



-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to