From d060ebf83c74b79fd8315e6428bad53a0b0d3fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Mon, 15 Jun 2020 10:13:10 +0900 Subject: 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. --- enum.c | 222 ++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 115 insertions(+), 107 deletions(-) (limited to 'enum.c') diff --git a/enum.c b/enum.c index 8c8adcfe42..f72a64fc56 100644 --- a/enum.c +++ b/enum.c @@ -3848,122 +3848,130 @@ struct enum_sum_memo { }; 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); - - long n = memo->n; - VALUE v = memo->v; - VALUE r = memo->r; + assert(FIXABLE(memo->n)); + memo->v = rb_fix_plus(LONG2FIX(memo->n), memo->v); + memo->n = 0; + /* r can be an Integer when mathn is loaded */ + switch (TYPE(memo->r)) { + case T_FIXNUM: memo->v = rb_fix_plus(memo->r, memo->v); break; + 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; + case T_UNDEF: break; + default: UNREACHABLE; /* or ...? */ + } + 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; + } +} +static void +sum_iter_bignum(VALUE i, struct enum_sum_memo *memo) +{ + memo->v = rb_big_plus(i, memo->v); +} +static void +sum_iter_rational(VALUE i, struct enum_sum_memo *memo) +{ + if (memo->r == Qundef) { + memo->r = i; + } + else { + memo->r = rb_rational_plus(memo->r, i); + } +} +static void +sum_iter_some_value(VALUE i, struct enum_sum_memo *memo) +{ + memo->v = rb_funcallv(memo->v, idPLUS, 1, &i); +} +static void +sum_iter_Kahan_Babuska(VALUE i, struct enum_sum_memo *memo) +{ + /* + * Kahan-Babuska balancing compensated summation algorithm + * See http://link.springer.com/article/10.1007/s00607-005-0139-x + */ + double x; + switch (TYPE(i)) { + case T_FLOAT: x = RFLOAT_VALUE(i); break; + case T_FIXNUM: x = FIX2LONG(i); break; + case T_BIGNUM: x = rb_big2dbl(i); break; + case T_RATIONAL: x = rb_num2dbl(i); break; + default: + memo->v = DBL2NUM(memo->f); + memo->float_value = 0; + sum_iter_some_value(i, memo); + return; + } double f = memo->f; - double c = memo->c; - - if (memo->block_given) - i = rb_yield(i); - - 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; - } - } - else if (RB_TYPE_P(i, T_BIGNUM)) - v = rb_big_plus(i, v); - else if (RB_TYPE_P(i, T_RATIONAL)) { - if (r == Qundef) - r = i; - else - r = rb_rational_plus(r, i); - } - else { - if (n != 0) { - v = rb_fix_plus(LONG2FIX(n), v); - n = 0; - } - if (r != Qundef) { - /* r can be an Integer when mathn is loaded */ - if (FIXNUM_P(r)) - v = rb_fix_plus(r, v); - else if (RB_TYPE_P(r, T_BIGNUM)) - v = rb_big_plus(r, v); - else - v = rb_rational_plus(r, v); - 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; - } + if (isnan(f)) { + return; } - else if (RB_FLOAT_TYPE_P(v)) { - /* - * Kahan-Babuska balancing compensated summation algorithm - * See http://link.springer.com/article/10.1007/s00607-005-0139-x - */ - double x, t; - - float_value: - if (RB_FLOAT_TYPE_P(i)) - x = RFLOAT_VALUE(i); - else if (FIXNUM_P(i)) - x = FIX2LONG(i); - else if (RB_TYPE_P(i, T_BIGNUM)) - x = rb_big2dbl(i); - else if (RB_TYPE_P(i, T_RATIONAL)) - x = rb_num2dbl(i); - else { - v = DBL2NUM(f); - memo->float_value = 0; - goto some_value; - } - - if (isnan(f)) return; - if (isnan(x)) { - memo->v = i; - memo->f = x; - return; - } - if (isinf(x)) { - if (isinf(f) && signbit(x) != signbit(f)) { - memo->f = NAN; - memo->v = DBL2NUM(f); - } - else { - memo->f = x; - memo->v = i; - } - return; + else if (! isfinite(x)) { + if (isinf(x) && isinf(f) && signbit(x) != signbit(f)) { + i = DBL2NUM(f); + x = nan(""); } - if (isinf(f)) return; - - t = f + x; - if (fabs(f) >= fabs(x)) - c += ((f - t) + x); - else - c += ((x - t) + f); - f = t; + memo->v = i; + memo->f = x; + return; + } + else if (isinf(f)) { + return; + } + double c = memo->c; + double t = f + x; + if (fabs(f) >= fabs(x)) { + c += ((f - t) + x); } else { - some_value: - v = rb_funcallv(v, idPLUS, 1, &i); + c += ((x - t) + f); } - - memo->v = v; - memo->n = n; - memo->r = r; + f = t; memo->f = f; 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 -- cgit v1.2.3