Has this fp fix been considered?

From: Date: Tue, 25 Jun 2002 16:35:38 +0000
Subject: Has this fp fix been considered?
Groups: php.dev 
Request: Send a blank email to php-dev+get-85578@lists.php.net to get a copy of this message
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

« previous php.dev (#85578) next »