numeric.c: avoid division by zero

In C, division by zero is undefined, even if the expression is double
(cf: ISO/IEC 9899:1990 section 6.3.5).  OTOH we have tests about such
operations and results, means we expect no exceptional situation shall
occur.  We need to carefully reroute the situation, and generate what
is needed.

See also: https://travis-ci.org/ruby/ruby/jobs/452680646#L2943

PS: Recently (last two decades), C have Annex. F document. It
normatively specifies that the division operator is IEEE 754's
division operator (cf: ISO/IEC 9899:1999 section F.3).  If we could
move to such newer version this could be no problem.  But that is not
possible today.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65642 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
shyouhei 2018-11-09 09:14:23 +00:00
Родитель 1d7d08262e
Коммит b8540e0a9d
1 изменённых файлов: 43 добавлений и 11 удалений

Просмотреть файл

@ -1083,6 +1083,12 @@ flo_mul(VALUE x, VALUE y)
}
}
static bool
flo_iszero(VALUE f)
{
return RFLOAT_VALUE(f) == 0.0;
}
/*
* call-seq:
* float / other -> float
@ -1093,23 +1099,52 @@ flo_mul(VALUE x, VALUE y)
static VALUE
flo_div(VALUE x, VALUE y)
{
long f_y;
double d;
double den;
double num = RFLOAT_VALUE(x);
double sign = 1.0;
if (RB_TYPE_P(y, T_FIXNUM)) {
f_y = FIX2LONG(y);
return DBL2NUM(RFLOAT_VALUE(x) / (double)f_y);
if (FIXNUM_ZERO_P(y)) {
goto zerodiv;
}
else {
den = FIX2LONG(y);
goto nonzero;
}
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
d = rb_big2dbl(y);
return DBL2NUM(RFLOAT_VALUE(x) / d);
if (rb_bigzero_p(y)) {
goto zerodiv;
}
else {
den = rb_big2dbl(y);
goto nonzero;
}
}
else if (RB_TYPE_P(y, T_FLOAT)) {
return DBL2NUM(RFLOAT_VALUE(x) / RFLOAT_VALUE(y));
if (flo_iszero(y)) {
sign = signbit(RFLOAT_VALUE(y)) ? -1.0 : 1.0;
goto zerodiv;
}
else {
den = RFLOAT_VALUE(y);
goto nonzero;
}
}
else {
return rb_num_coerce_bin(x, y, '/');
}
nonzero:
return DBL2NUM(num / den);
zerodiv:
if (num == 0.0) {
return DBL2NUM(nan(""));
}
else {
return DBL2NUM(num * sign * HUGE_VAL);
}
}
/*
@ -1676,10 +1711,7 @@ rb_float_abs(VALUE flt)
static VALUE
flo_zero_p(VALUE num)
{
if (RFLOAT_VALUE(num) == 0.0) {
return Qtrue;
}
return Qfalse;
return flo_iszero(num) ? Qtrue : Qfalse;
}
/*