//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; double Faccum = ACCUM_DEFAULT; u64int u64; bool inexact = false; int forcetype = -1; sl_v arg; sl_numtype pt; void *a; sl_cv *cv; u32int i, j; FOR_ARGS(i, 0, arg, args){ if(isfixnum(arg)) x = numval(arg); else{ if(isubnum(arg)){ pt = ubnumtype(arg); u64 = ubnumval(arg); a = ubnumptr(u64, pt); }else if(iscvalue(arg)){ cv = ptr(arg); a = cv_data(cv); pt = cv_numtype(cv); }else{typeerr: mpfree(Maccum); mpfree(m); type_error(nil, "num", arg); } switch(pt){ case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_F32: 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_P32: if(forcetype < T_P32) forcetype = T_P32; // fall through case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; case T_P64: if(forcetype < T_P64) forcetype = T_P64; // fall through case T_U64: u64 = *(u64int*)a; if(u64 > INT64_MAX){ x = ACCUM_DEFAULT; goto overflow; } x = u64; break; case T_BIG: 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(forcetype >= 0){forcedptr: if(inexact) lerrorf(sl_errarg, "arithmetic on a mix of ptr and inexact types"); switch(forcetype){ case T_P32: return mk_p32(Saccum); case T_P64: return mk_p64(Saccum); default: abort(); } } if(inexact) return mk_f64(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(isubnum(arg)){ pt = ubnumtype(arg); u64 = ubnumval(arg); a = ubnumptr(u64, pt); }else if(iscvalue(arg)){ cv = ptr(arg); a = cv_data(cv); pt = cv_numtype(cv); }else{ goto typeerr; } switch(pt){ case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue; case T_F32: 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_P32: if(forcetype < T_P32) forcetype = T_P32; // fall through case T_U32: x = *(u32int*)a; break; case T_S64: x = *(s64int*)a; break; case T_P64: if(forcetype < T_P64) forcetype = T_P64; // fall through case T_U64: uvtomp(*(u64int*)a, m); MP_OP(Maccum, m, Maccum); continue; case T_BIG: MP_OP(Maccum, *(mpint**)a, Maccum); continue; default: goto typeerr; } vtomp(x, m); MP_OP(Maccum, m, Maccum); } if(forcetype >= 0){ Saccum = mptouv(Maccum); goto forcedptr; } 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_bignum(Maccum); }down: mpfree(m); Saccum = mptov(Maccum); mpfree(Maccum); if(inexact) return mk_f64(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
//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;
double Faccum = ACCUM_DEFAULT;
u64int u64;
bool inexact = false;
int forcetype = -1;
sl_v arg;
sl_numtype pt;
void *a;
sl_cv *cv;
u32int i, j;
FOR_ARGS(i, 0, arg, args){
if(isfixnum(arg))
x = numval(arg);
else{
if(isubnum(arg)){
pt = ubnumtype(arg);
u64 = ubnumval(arg);
a = ubnumptr(u64, pt);
}else if(iscvalue(arg)){
cv = ptr(arg);
a = cv_data(cv);
pt = cv_numtype(cv);
}else{
typeerr:
mpfree(Maccum);
mpfree(m);
type_error(nil, "num", arg);
}
switch(pt){
case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
case T_F32: 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_P32: if(forcetype < T_P32) forcetype = T_P32;
// fall through
case T_U32: x = *(u32int*)a; break;
case T_S64: x = *(s64int*)a; break;
case T_P64: if(forcetype < T_P64) forcetype = T_P64;
// fall through
case T_U64:
u64 = *(u64int*)a;
if(u64 > INT64_MAX){
x = ACCUM_DEFAULT;
goto overflow;
}
x = u64;
break;
case T_BIG:
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(forcetype >= 0){
forcedptr:
if(inexact)
lerrorf(sl_errarg, "arithmetic on a mix of ptr and inexact types");
switch(forcetype){
case T_P32: return mk_p32(Saccum);
case T_P64: return mk_p64(Saccum);
default: abort();
}
}
if(inexact)
return mk_f64(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(isubnum(arg)){
pt = ubnumtype(arg);
u64 = ubnumval(arg);
a = ubnumptr(u64, pt);
}else if(iscvalue(arg)){
cv = ptr(arg);
a = cv_data(cv);
pt = cv_numtype(cv);
}else{
goto typeerr;
}
switch(pt){
case T_F64: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
case T_F32: 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_P32: if(forcetype < T_P32) forcetype = T_P32;
// fall through
case T_U32: x = *(u32int*)a; break;
case T_S64: x = *(s64int*)a; break;
case T_P64: if(forcetype < T_P64) forcetype = T_P64;
// fall through
case T_U64:
uvtomp(*(u64int*)a, m);
MP_OP(Maccum, m, Maccum);
continue;
case T_BIG:
MP_OP(Maccum, *(mpint**)a, Maccum);
continue;
default:
goto typeerr;
}
vtomp(x, m);
MP_OP(Maccum, m, Maccum);
}
if(forcetype >= 0){
Saccum = mptouv(Maccum);
goto forcedptr;
}
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_bignum(Maccum);
}
down:
mpfree(m);
Saccum = mptov(Maccum);
mpfree(Maccum);
if(inexact)
return mk_f64(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