#include "../core.h" #include "../utils/each.h" #include static f64 pfmod(f64 a, f64 b) { f64 r = fmod(a, b); if (a<0 != b<0 && r!=0) r+= b; return r; } static f64 bqn_or(f64 w, f64 x) { return (w+x)-(w*x); } B add_c2(B, B, B); B ceil_c2(B, B, B); B sub_c2(B, B, B); B div_c2(B, B, B); B not_c2(B, B, B); B pow_c2(B, B, B); B mul_c2(B, B, B); B root_c2(B, B, B); B and_c2(B, B, B); B stile_c2(B, B, B); B or_c2 (B, B, B); B log_c2(B, B, B); B floor_c2(B, B, B); #if SINGELI #define BCALL(N, X) N(b(X)) #define interp_f64(X) b(X).f #include "../singeli/c/arithdDispatch.c" #endif #define ARITH_SLOW(N) SLOWIF((!isArr(w) || TI(w,elType)!=el_B) && (!isArr(x) || TI(x,elType)!=el_B)) SLOW2("arithd " #N, w, x) #define P2(N) { if(isArr(w)|isArr(x)) { ARITH_SLOW(N); \ return arith_recd(N##_c2, w, x); \ }} #if !TYPED_ARITH #define AR_I_TO_ARR(NAME) P2(NAME) #define AR_F_TO_ARR AR_I_TO_ARR #else static NOINLINE u8 iMakeEq(B* w, B* x, u8 we, u8 xe) { B* p = wexv?xv:wv, 2, {}) AR_I_AA("⌈", ceil , wv>xv?wv:xv, 1, {}) AR_I_AA("+", add, wv+xv, 0, {}) AR_I_AA("-", sub, wv-xv, 0, { if (we==el_c32 && xe==el_i32) { u32* wp = c32any_ptr(w); usz wia = IA(w); u32* rp; r = m_c32arrc(&rp, w); i32* xp = i32any_ptr(x); for (usz i = 0; i < wia; i++) { rp[i] = (u32)((i32)wp[i] - (i32)xp[i]); if (rp[i]>CHR_MAX) thrM("-: Invalid character"); // safe - see add } goto dec_ret; } }) #undef AR_I_AA #define AR_I_AS(CHR, NAME, EXPR, DO_AS, EXTRA) NOINLINE B NAME##_AS(B t, B w, B x) { \ B r; u8 we=TI(w,elType); EXTRA \ if (isF64(x)) { usz ia=IA(w); DO_AS(NAME,EXPR) } \ ARITH_SLOW(CHR); return arith_recd(NAME##_c2, w, x); \ dec_ret: decG(w); return r; \ } #define AR_I_SA(CHR, NAME, EXPR, DO_SA, EXTRA) NOINLINE B NAME##_SA(B t, B w, B x) { \ B r; u8 xe=TI(x,elType); EXTRA \ if (isF64(w)) { usz ia=IA(x); DO_SA(NAME,EXPR) } \ ARITH_SLOW(CHR); return arith_recd(NAME##_c2, w, x); \ dec_ret: decG(x); return r; \ } static NOINLINE B bit_sel1Fn(BBB2B f, B w, B x, bool bitX) { // consumes both B b = bitX? x : w; u64* bp = bitarr_ptr(b); usz ia = IA(b); bool b0 = ia? bp[0]&1 : 0; bool both = false; for (usz i = 0; i < ia; i++) if (bitp_get(bp,i) != b0) { both=true; break; } B e0=m_f64(0), e1=m_f64(0); // initialized to have something to decrement later bool h0=both || b0==0; if (h0) e0 = bitX? f(bi_N, inc(w), m_f64(0)) : f(bi_N, m_f64(0), inc(x)); bool h1=both || b0==1; if (h1) e1 = bitX? f(bi_N, w, m_f64(1)) : f(bi_N, m_f64(1), x); // non-bitarr arg has been consumed B r = bit_sel(b, e0, e1); // and now the bitarr arg is consumed too dec(e0); dec(e1); return r; } AR_I_SA("-", sub, wv-xv, SI_SA, {}) AR_I_SA("×", mul, wv*xv, SI_SA, {}) AR_I_SA("∧", and, wv*xv, REG_SA, {}) AR_I_SA("∨", or , (wv+xv)-(wv*xv), REG_SA, {}) AR_I_SA("⌊", floor, wv>xv?xv:wv, REG_SA, {}) AR_I_SA("⌈", ceil , wv>xv?wv:xv, REG_SA, {}) AR_I_SA("+", add, wv+xv, SI_SA, { if (isC32(w) && xe==el_i32) { u32 wv = o2cG(w); i32* xp = i32any_ptr(x); usz xia = IA(x); u32* rp; r = m_c32arrc(&rp, x); for (usz i = 0; i < xia; i++) { rp[i] = (u32)(xp[i]+(i32)wv); if (rp[i]>CHR_MAX) thrM("+: Invalid character"); // safe to only check this as wv already must be below CHR_MAX, which is less than U32_MAX/2 } goto dec_ret; } }) #undef AR_I_SA AR_I_AS("-", sub, wv-xv, SI_AS, { if (we==el_c32 && isC32(x)) { i32 xv = (i32)o2cG(x); u32* wp = c32any_ptr(w); usz wia = IA(w); i32* rp; r = m_i32arrc(&rp, w); for (usz i = 0; i < wia; i++) rp[i] = (i32)wp[i] - xv; goto dec_ret; } }) #undef AR_I_AS #endif // !SINGELI #define add_AS(T, W, X) add_SA(T, X, W) #define mul_AS(T, W, X) mul_SA(T, X, W) #define and_AS(T, W, X) and_SA(T, X, W) #define or_AS(T, W, X) or_SA(T, X, W) #define floor_AS(T, W, X) floor_SA(T, X, W) #define ceil_AS(T, W, X) ceil_SA(T, X, W) #define AR_F_TO_ARR(NAME) return NAME##_c2_arr(t, w, x); #define AR_I_TO_ARR(NAME) \ if (isArr(x)) { \ if (isArr(w)) return NAME##_AA(t, w, x); \ else return NAME##_SA(t, w, x); \ } else if (isArr(w)) return NAME##_AS(t, w, x); #endif // TYPED_ARITH #define AR_I_SCALAR(CHR, NAME, EXPR, MORE) B NAME##_c2(B t, B w, B x) { \ if (isF64(w) & isF64(x)) return m_f64(EXPR); \ MORE \ AR_I_TO_ARR(NAME) \ thrM(CHR ": Unexpected argument types"); \ } #define AR_F_SCALAR(CHR, NAME, EXPR) B NAME##_c2(B t, B w, B x) { \ if (isF64(w) & isF64(x)) return m_f64(EXPR); \ AR_F_TO_ARR(NAME) \ thrM(CHR ": Unexpected argument types"); \ } AR_I_SCALAR("+", add, w.f+x.f, { if (isC32(w) & isF64(x)) { u64 r = (u64)(o2cG(w)+o2i64(x)); if(r>CHR_MAX)thrM("+: Invalid character"); return m_c32((u32)r); } if (isF64(w) & isC32(x)) { u64 r = (u64)(o2cG(x)+o2i64(w)); if(r>CHR_MAX)thrM("+: Invalid character"); return m_c32((u32)r); } }); AR_I_SCALAR("-", sub, w.f-x.f, { if (isC32(w) & isF64(x)) { u64 r = (u64)((i32)o2cG(w)-o2i64(x)); if(r>CHR_MAX)thrM("-: Invalid character"); return m_c32((u32)r); } if (isC32(w) & isC32(x)) return m_f64((i32)(u32)w.u - (i32)(u32)x.u); }) AR_I_SCALAR("×", mul, w.f*x.f, {}) AR_I_SCALAR("∧", and, w.f*x.f, {}) AR_I_SCALAR("∨", or , bqn_or(w.f, x.f), {}) AR_I_SCALAR("⌊", floor, w.f>x.f?x.f:w.f, {}) AR_I_SCALAR("⌈", ceil , w.f>x.f?w.f:x.f, {}) #undef AR_I_SCALAR B not_c2(B t, B w, B x) { return add_c2(m_f64(1), m_f64(1), sub_c2(t, w, x)); } AR_F_SCALAR("÷", div , w.f/x.f) AR_F_SCALAR("⋆", pow , pow(w.f, x.f)) AR_F_SCALAR("√", root , pow(x.f, 1.0/w.f)) AR_F_SCALAR("|", stile, pfmod(x.f, w.f)) AR_F_SCALAR("⋆⁼",log , log(x.f)/log(w.f)) #undef AR_F_SCALAR #undef P2