ref: a70379d7e4b822f532fb0a8ccdd1624a90b64a68
dir: /src/sl_arith_any.h/
//sl_v //sl_*_any(sl_v *args, u32int nargs) // input: ACCUM_DEFAULT ARITH_OP(a,b) MP_OP ARITH_OVERFLOW // add: 0 a+b mpadd sadd_overflow_64 // mul: 1 a*b mpmul smul_overflow_64 mpint *Maccum = nil, *m = nil; s64int Saccum = ACCUM_DEFAULT, x; u64int u64; double Faccum = ACCUM_DEFAULT; bool inexact = false; sl_v arg; sl_numtype pt; void *a; sl_cprim *cp; sl_cv *cv; u32int i, j; FOR_ARGS(i, 0, arg, args){ if(isfixnum(arg)) x = numval(arg); else{ if(iscprim(arg)){ cp = ptr(arg); a = cp_data(cp); pt = cp_numtype(cp); }else if(iscvalue(arg)){ cv = ptr(arg); a = cv_data(cv); pt = cv_numtype(cv); }else{ typeerr: mpfree(Maccum); mpfree(m); type_error("num", arg); } switch(pt){ case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_FLOAT: Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue; case T_S8: x = *(s8int*)a; break; case T_U8: x = *(u8int*)a; break; case T_S16: x = *(s16int*)a; break; case T_U16: x = *(u16int*)a; break; case T_S32: x = *(s32int*)a; break; case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; case T_U64: u64 = *(u64int*)a; if(u64 > INT64_MAX){ x = ACCUM_DEFAULT; goto overflow; } x = u64; break; case T_MP: x = ACCUM_DEFAULT; u64 = ACCUM_DEFAULT; m = mpcopy(*(mpint**)a); goto overflow; default: goto typeerr; } } s64int accu; if(ARITH_OVERFLOW(Saccum, x, &accu)){ u64 = ACCUM_DEFAULT; goto overflow; } Saccum = accu; } if(inexact) return mk_double(ARITH_OP(Faccum, Saccum)); if(fits_fixnum(Saccum)) return fixnum((sl_fx)Saccum); u64 = ACCUM_DEFAULT; x = ACCUM_DEFAULT; overflow: i++; if(Maccum == nil) Maccum = vtomp(Saccum, nil); if(m == nil) m = u64 != ACCUM_DEFAULT ? uvtomp(u64, nil) : vtomp(x, nil); MP_OP(Maccum, m, Maccum); FOR_ARGS(j, i, arg, args){ if(isfixnum(arg)){ vtomp(numval(arg), m); MP_OP(Maccum, m, Maccum); continue; } if(iscprim(arg)){ cp = ptr(arg); a = cp_data(cp); pt = cp_numtype(cp); }else if(iscvalue(arg)){ cv = ptr(arg); a = cv_data(cv); pt = cv_numtype(cv); }else{ goto typeerr; } switch(pt){ case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_FLOAT: Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue; case T_S8: x = *(s8int*)a; break; case T_U8: x = *(u8int*)a; break; case T_S16: x = *(s16int*)a; break; case T_U16: x = *(u16int*)a; break; case T_S32: x = *(s32int*)a; break; case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; case T_U64: uvtomp(*(u64int*)a, m); MP_OP(Maccum, m, Maccum); continue; case T_MP: MP_OP(Maccum, *(mpint**)a, Maccum); continue; default: goto typeerr; } vtomp(x, m); MP_OP(Maccum, m, Maccum); } int n = mpsignif(Maccum); if(n >= FIXNUM_BITS){ if(inexact){ dtomp(Faccum, m); MP_OP(Maccum, m, Maccum); n = mpsignif(Maccum); if(n < FIXNUM_BITS){ inexact = false; goto down; } } mpfree(m); return mk_mp(Maccum); } down: mpfree(m); Saccum = mptov(Maccum); mpfree(Maccum); if(inexact) return mk_double(ARITH_OP(Faccum, Saccum)); assert(fits_fixnum(Saccum)); return fixnum((sl_fx)Saccum); #undef ACCUM_DEFAULT #undef ARITH_OP #undef MP_OP #undef ARITH_OVERFLOW