sum_iter: do not goto into a branch

I'm not necessarily against every goto in general, but jumping into a
branch is definitely a bad idea.  Better refactor.
This commit is contained in:
卜部昌平 2020-06-15 10:13:10 +09:00
parent 5e96054519
commit d060ebf83c
Notes: git 2020-06-29 11:07:08 +09:00

192
enum.c
View File

@ -3848,122 +3848,130 @@ struct enum_sum_memo {
}; };
static void static void
sum_iter(VALUE i, struct enum_sum_memo *memo) sum_iter_normalize_memo(struct enum_sum_memo *memo)
{ {
const int unused = (assert(memo != NULL), 0); assert(FIXABLE(memo->n));
memo->v = rb_fix_plus(LONG2FIX(memo->n), memo->v);
long n = memo->n; memo->n = 0;
VALUE v = memo->v; /* r can be an Integer when mathn is loaded */
VALUE r = memo->r; switch (TYPE(memo->r)) {
double f = memo->f; case T_FIXNUM: memo->v = rb_fix_plus(memo->r, memo->v); break;
double c = memo->c; case T_BIGNUM: memo->v = rb_big_plus(memo->r, memo->v); break;
case T_RATIONAL: memo->v = rb_rational_plus(memo->r, memo->v); break;
if (memo->block_given) case T_UNDEF: break;
i = rb_yield(i); default: UNREACHABLE; /* or ...? */
if (memo->float_value)
goto float_value;
if (FIXNUM_P(v) || RB_TYPE_P(v, T_BIGNUM) || RB_TYPE_P(v, T_RATIONAL)) {
if (FIXNUM_P(i)) {
n += FIX2LONG(i); /* should not overflow long type */
if (!FIXABLE(n)) {
v = rb_big_plus(LONG2NUM(n), v);
n = 0;
} }
memo->r = Qundef;
}
static void
sum_iter_fixnum(VALUE i, struct enum_sum_memo *memo)
{
memo->n += FIX2LONG(i); /* should not overflow long type */
if (! FIXABLE(memo->n)) {
memo->v = rb_big_plus(LONG2NUM(memo->n), memo->v);
memo->n = 0;
} }
else if (RB_TYPE_P(i, T_BIGNUM)) }
v = rb_big_plus(i, v); static void
else if (RB_TYPE_P(i, T_RATIONAL)) { sum_iter_bignum(VALUE i, struct enum_sum_memo *memo)
if (r == Qundef) {
r = i; memo->v = rb_big_plus(i, memo->v);
else }
r = rb_rational_plus(r, i); static void
sum_iter_rational(VALUE i, struct enum_sum_memo *memo)
{
if (memo->r == Qundef) {
memo->r = i;
} }
else { else {
if (n != 0) { memo->r = rb_rational_plus(memo->r, i);
v = rb_fix_plus(LONG2FIX(n), v);
n = 0;
} }
if (r != Qundef) { }
/* r can be an Integer when mathn is loaded */ static void
if (FIXNUM_P(r)) sum_iter_some_value(VALUE i, struct enum_sum_memo *memo)
v = rb_fix_plus(r, v); {
else if (RB_TYPE_P(r, T_BIGNUM)) memo->v = rb_funcallv(memo->v, idPLUS, 1, &i);
v = rb_big_plus(r, v); }
else static void
v = rb_rational_plus(r, v); sum_iter_Kahan_Babuska(VALUE i, struct enum_sum_memo *memo)
r = Qundef; {
}
if (RB_FLOAT_TYPE_P(i)) {
f = NUM2DBL(v);
c = 0.0;
memo->float_value = 1;
goto float_value;
}
else
goto some_value;
}
}
else if (RB_FLOAT_TYPE_P(v)) {
/* /*
* Kahan-Babuska balancing compensated summation algorithm * Kahan-Babuska balancing compensated summation algorithm
* See http://link.springer.com/article/10.1007/s00607-005-0139-x * See http://link.springer.com/article/10.1007/s00607-005-0139-x
*/ */
double x, t; double x;
switch (TYPE(i)) {
float_value: case T_FLOAT: x = RFLOAT_VALUE(i); break;
if (RB_FLOAT_TYPE_P(i)) case T_FIXNUM: x = FIX2LONG(i); break;
x = RFLOAT_VALUE(i); case T_BIGNUM: x = rb_big2dbl(i); break;
else if (FIXNUM_P(i)) case T_RATIONAL: x = rb_num2dbl(i); break;
x = FIX2LONG(i); default:
else if (RB_TYPE_P(i, T_BIGNUM)) memo->v = DBL2NUM(memo->f);
x = rb_big2dbl(i);
else if (RB_TYPE_P(i, T_RATIONAL))
x = rb_num2dbl(i);
else {
v = DBL2NUM(f);
memo->float_value = 0; memo->float_value = 0;
goto some_value; sum_iter_some_value(i, memo);
return;
}
double f = memo->f;
if (isnan(f)) {
return;
}
else if (! isfinite(x)) {
if (isinf(x) && isinf(f) && signbit(x) != signbit(f)) {
i = DBL2NUM(f);
x = nan("");
} }
if (isnan(f)) return;
if (isnan(x)) {
memo->v = i; memo->v = i;
memo->f = x; memo->f = x;
return; return;
} }
if (isinf(x)) { else if (isinf(f)) {
if (isinf(f) && signbit(x) != signbit(f)) {
memo->f = NAN;
memo->v = DBL2NUM(f);
}
else {
memo->f = x;
memo->v = i;
}
return; return;
} }
if (isinf(f)) return; double c = memo->c;
double t = f + x;
t = f + x; if (fabs(f) >= fabs(x)) {
if (fabs(f) >= fabs(x))
c += ((f - t) + x); c += ((f - t) + x);
else
c += ((x - t) + f);
f = t;
} }
else { else {
some_value: c += ((x - t) + f);
v = rb_funcallv(v, idPLUS, 1, &i);
} }
f = t;
memo->v = v;
memo->n = n;
memo->r = r;
memo->f = f; memo->f = f;
memo->c = c; memo->c = c;
(void)unused; }
static void
sum_iter(VALUE i, struct enum_sum_memo *memo)
{
assert(memo != NULL);
if (memo->block_given) {
i = rb_yield(i);
}
if (memo->float_value) {
sum_iter_Kahan_Babuska(i, memo);
}
else switch (TYPE(memo->v)) {
default: sum_iter_some_value(i, memo); return;
case T_FLOAT: sum_iter_Kahan_Babuska(i, memo); return;
case T_FIXNUM:
case T_BIGNUM:
case T_RATIONAL:
switch (TYPE(i)) {
case T_FIXNUM: sum_iter_fixnum(i, memo); return;
case T_BIGNUM: sum_iter_bignum(i, memo); return;
case T_RATIONAL: sum_iter_rational(i, memo); return;
case T_FLOAT:
sum_iter_normalize_memo(memo);
memo->f = NUM2DBL(memo->v);
memo->c = 0.0;
memo->float_value = 1;
sum_iter_Kahan_Babuska(i, memo);
return;
default:
sum_iter_normalize_memo(memo);
sum_iter_some_value(i, memo);
return;
}
}
} }
static VALUE static VALUE