Hello group,
Currently, the +, - en * operations in zend_operators in C do their
calculcations on long arguments with doubles, and check if the result
would fit in a long.
This failed for me on FreeBSD/alpha (in some of the math tests), because
doubles are not accurate enough to represent LONG_MIN or LONG_MAX. This
causes the comparison
'((double) LONG_MAX) + 1 > (double) LONG_MAX'
to result in 'false' because they have the same double representation.
Since a lot of tests use LONG_MAX in comparisons, this caused a lot of
them to fail on this architecture.
One solution could be to use long doubles, but in my opinion it is
better to check the sign bit directly.
A patch is attached.
--
Ard
The patch looks good - I committed it. Thanks!
Zeev
At 18:01 13/09/2003, Ard Biesheuvel wrote:
Hello group,
Currently, the +, - en * operations in zend_operators in C do their
calculcations on long arguments with doubles, and check if the result
would fit in a long.This failed for me on FreeBSD/alpha (in some of the math tests), because
doubles are not accurate enough to represent LONG_MIN or LONG_MAX. This
causes the comparison'((double) LONG_MAX) + 1 > (double) LONG_MAX'
to result in 'false' because they have the same double representation.
Since a lot of tests use LONG_MAX in comparisons, this caused a lot of
them to fail on this architecture.One solution could be to use long doubles, but in my opinion it is better
to check the sign bit directly.A patch is attached.
--
ArdIndex: zend_operators.c
RCS file: /repository/ZendEngine2/zend_operators.c,v
retrieving revision 1.160
diff -u -r1.160 zend_operators.c
--- zend_operators.c 17 Aug 2003 19:11:48 -0000 1.160
+++ zend_operators.c 13 Sep 2003 13:15:30 -0000
@@ -33,6 +33,8 @@
#include "ext/bcmath/number.h"
#endif+#define LONG_SIGN_MASK (1L << (8*SIZEOF_LONG-1))
ZEND_API int zend_atoi(const char *str, int str_len)
{
int retval;
@@ -664,13 +666,16 @@if (op1->type == IS_LONG && op2->type == IS_LONG) {
double dval = (double) op1->value.lval + (double)op2->value.lval;
long lval = op1->value.lval + op2->value.lval;/* check for overflow by comparing sign bits */if ( (op1->value.lval & LONG_SIGN_MASK) ==(op2->value.lval & LONG_SIGN_MASK)
&& (op1->value.lval & LONG_SIGN_MASK) != (lval &LONG_SIGN_MASK)) {
if ((dval > (double) LONG_MAX) || (dval < (double)LONG_MIN)) {
result->value.dval = dval;
result->value.dval = (double) op1->value.lval +(double) op2->value.lval;
result->type = IS_DOUBLE;
} else {
result->value.lval = op1->value.lval +op2->value.lval;
result->value.lval = lval; result->type = IS_LONG; } return SUCCESS;@@ -701,13 +706,16 @@
zendi_convert_scalar_to_number(op2, op2_copy, result);if (op1->type == IS_LONG && op2->type == IS_LONG) {
double dval = (double) op1->value.lval - (double)op2->value.lval;
long lval = op1->value.lval - op2->value.lval;/* check for overflow by comparing sign bits */if ( (op1->value.lval & LONG_SIGN_MASK) !=(op2->value.lval & LONG_SIGN_MASK)
&& (op1->value.lval & LONG_SIGN_MASK) != (lval &LONG_SIGN_MASK)) {
if ((dval < (double) LONG_MIN) || (dval > (double)LONG_MAX)) {
result->value.dval = dval;
result->value.dval = (double) op1->value.lval -(double) op2->value.lval;
result->type = IS_DOUBLE;
} else {
result->value.lval = op1->value.lval -op2->value.lval;
result->value.lval = lval; result->type = IS_LONG; } return SUCCESS;@@ -738,13 +746,14 @@
zendi_convert_scalar_to_number(op2, op2_copy, result);if (op1->type == IS_LONG && op2->type == IS_LONG) {
double dval = (double) op1->value.lval * (double)op2->value.lval;
if ((dval > (double) LONG_MAX) || (dval < (double)LONG_MIN)) {
result->value.dval = dval;
long lval = op1->value.lval * op2->value.lval;/* check for overflow by applying the reverse calculation */if (op1->value.lval != 0 && lval / op1->value.lval !=op2->value.lval) {
result->value.dval = (double) op1->value.lval *(double) op2->value.lval;
result->type = IS_DOUBLE;
} else {
result->value.lval = op1->value.lval *op2->value.lval;
result->value.lval = lval; result->type = IS_LONG; } return SUCCESS;