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:
parent
5e96054519
commit
d060ebf83c
Notes:
git
2020-06-29 11:07:08 +09:00
192
enum.c
192
enum.c
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user