diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 36bbf8a6..4806992f 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -339,8 +339,33 @@ B rand_range_c2(B t, B w, B x) { f64* rp; r = m_f64arrp(&rp, am); for (usz i = 0; i < am; i++) rp[i] = wy2u0k(wyrand(&seed), max); } else { - i32* rp; r = m_i32arrp(&rp, am); - for (usz i = 0; i < am; i++) rp[i] = wy2u0k(wyrand(&seed), max); + u8 t; usz u64am; + + if (max>128) { + if (max>32768) { u64am = (am+ 1)>>1; t=t_i32arr; } + else { u64am = (am+ 3)>>2; t=t_i16arr; } + } else if (max!=2) { u64am = (am+ 7)>>3; t=t_i8arr; } + else { u64am = (am+63)>>6; t=t_bitarr; } + + assert((u64am<<3) >= (t==t_bitarr? BIT_N(am)<<3 : am<a; + if (max & (max-1)) { // not power of two + if (t==t_i32arr) for (usz i = 0; i < am; i++) ((i32*)rp)[i] = wy2u0k(wyrand(&seed), max); + else if (t==t_i16arr) for (usz i = 0; i < am; i++) ((i16*)rp)[i] = wy2u0k(wyrand(&seed), max); + else if (t==t_i8arr) for (usz i = 0; i < am; i++) (( i8*)rp)[i] = wy2u0k(wyrand(&seed), max); + else UD; // bitarr will be max==2, i.e. a power of two + } else { + u64 mask; + if (t==t_bitarr) { mask = ~0L; goto end; } + mask = max-1; + mask|= mask<<32; + if (t==t_i32arr) goto end; mask|= mask<<16; + if (t==t_i16arr) goto end; mask|= mask<<8; + + end: + for (usz i = 0; i < u64am; i++) ((u64*)rp)[i] = wyrand(&seed) & mask; + } } RAND_END; diff --git a/src/core/arrFns.h b/src/core/arrFns.h index f80df18d..c1379437 100644 --- a/src/core/arrFns.h +++ b/src/core/arrFns.h @@ -21,19 +21,33 @@ static void* tyany_ptr(B x) { assert(IS_ARR(v(x)->type) || IS_SLICE(v(x)->type)) return IS_SLICE(t)? c(TySlice,x)->a : c(TyArr,x)->a; } -#define M_TYARR(OVER, MID, RV, PRE) { PRE \ - Arr* r = m_arr(TYARR_SZW(w, ia) OVER, type, ia); \ - MID \ - *rp = RV; \ - return ((TyArr*)r)->a; \ +#define M_TYARR(WM, OVER, MID, RV, PRE) { PRE \ + Arr* r = m_arr((offsetof(TyArr, a) + ( \ + WM==0? ((u64)ia)*w \ + : WM==1? ((u64)ia)<>3) \ + ) OVER, type, ia); \ + MID \ + *rp = RV; \ + return ((TyArr*)r)->a; \ } -// width in bytes for m_tyarr*; overalloc is a byte count -static void* m_tyarrp (Arr** rp, usz w, usz ia, u8 type ) M_TYARR( , , r, ) -static void* m_tyarrpO(Arr** rp, usz w, usz ia, u8 type, usz over) M_TYARR(+over, , r, ) -static void* m_tyarrv (B* rp, usz w, usz ia, u8 type ) M_TYARR( , arr_shVec((Arr*)r);, taga(r), ) -static void* m_tyarrvO(B* rp, usz w, usz ia, u8 type, usz over) M_TYARR(+over, arr_shVec((Arr*)r);, taga(r), ) -static void* m_tyarrc (B* rp, usz w, B x, u8 type ) M_TYARR( , arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) -static void* m_tyarrcO(B* rp, usz w, B x, u8 type, usz over) M_TYARR(+over, arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) +// width in bytes; overalloc is a byte count +static void* m_tyarrp (Arr** rp, usz w, usz ia, u8 type ) M_TYARR(0, , , r, ) +static void* m_tyarrpO(Arr** rp, usz w, usz ia, u8 type, usz over) M_TYARR(0,+over, , r, ) +static void* m_tyarrv (B* rp, usz w, usz ia, u8 type ) M_TYARR(0, , arr_shVec((Arr*)r);, taga(r), ) +static void* m_tyarrvO(B* rp, usz w, usz ia, u8 type, usz over) M_TYARR(0,+over, arr_shVec((Arr*)r);, taga(r), ) +static void* m_tyarrc (B* rp, usz w, B x, u8 type ) M_TYARR(0, , arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) +static void* m_tyarrcO(B* rp, usz w, B x, u8 type, usz over) M_TYARR(0,+over, arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) + +// width in log2(bytes) +static void* m_tyarrlp(Arr** rp, usz w, usz ia, u8 type) M_TYARR(1, , , r, ) +static void* m_tyarrlv(B* rp, usz w, usz ia, u8 type) M_TYARR(1, , arr_shVec((Arr*)r);, taga(r), ) +static void* m_tyarrlc(B* rp, usz w, B x, u8 type) M_TYARR(1, , arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) + +// width in log2(bits) +static void* m_tyarrlbp(Arr** rp, usz w, usz ia, u8 type) M_TYARR(2, , , r, ) +static void* m_tyarrlbv(B* rp, usz w, usz ia, u8 type) M_TYARR(2, , arr_shVec((Arr*)r);, taga(r), ) +static void* m_tyarrlbc(B* rp, usz w, B x, u8 type) M_TYARR(2, , arr_shCopy((Arr*)r,x);, taga(r), usz ia = a(x)->ia;) extern u8 elType2type[]; #define el2t(X) elType2type[X] // TODO maybe reorganize array types such that this can just be addition? diff --git a/test/README.md b/test/README.md index 87b3bbdc..ce26a358 100644 --- a/test/README.md +++ b/test/README.md @@ -14,6 +14,7 @@ test/moreCfgs.sh path/to/mlochbaum/BQN // run "2+2" in a bunch of configurations ./BQN test/squeezeValid.bqn // fuzz-test squeezing giving a correct result; requires a CBQN build with -DEEQUAL_NEGZERO ./BQN test/squeezeExact.bqn // fuzz-test squeezing giving the exact smallest result; requires a CBQN build with -DEEQUAL_NEGZERO ./BQN test/various.bqn // tests for various small things +./BQN test/random.bqn // test (•MakeRand n).Range make -C test/ffi // test FFI functionality; expects both regular and shared library CBQN builds to already exist legacy utilities: diff --git a/test/random.bqn b/test/random.bqn new file mode 100644 index 00000000..ff9b2a4f --- /dev/null +++ b/test/random.bqn @@ -0,0 +1,41 @@ +u ← ⌊100×(•UnixTime+1|100וMonoTime)@ + +Range ← (•MakeRand •Show u).Range + +ExpectedRangeStep ← { n‿len𝕊depth‿max: + ls ← {𝕊:len Range max}¨↕n + maxGot ← ⌈´⌈´¨ls + ! maxGotn×len÷20) ∨ maxGot=max-1? @; •Out ∾⟨"Maximum ", •Repr max-1, " likely should have been encountered, but max was ", •Repr maxGot, "; n=", •Repr n," len=", •Repr len, " range=", •Repr max⟩} + + # some very very crappy statistics + sumExp ← n×len÷2 + sumGot ← +´ +´¨ ls + {𝕊: sumGot ↩ max÷˜ (2÷˜n×len) + sumGot}⍟⊢ max≠0 + diff ← sumGot-sumExp + dev ← diff ÷ √12÷˜ n×len + {𝕊: + depth≥4? •Out ∾⟨"Unlikely sum (dev=", •Repr dev, ": expected ", •Repr sumExp, ", got ", •Repr sumGot, "; n=", •Repr n," len=", •Repr len, " range=", •Repr max⟩; + n‿len ExpectedRangeStep ⟨depth+1, max⟩ + }⍟⊢ 2 < |dev + dev +} + +ExpectedRange ← ExpectedRangeStep⟜(0⊸⋈) + +# for whatever reason, the following don't all evaluate to the same number; but they're close enough so ¯\_(ツ)_/¯ +# •Show (+´÷≠) |{𝕊: 100‿1000 ExpectedRange 2 }¨↕10000 +# •Show (+´÷≠) |{𝕊: 10‿1000 ExpectedRange 3 }¨↕10000 +# •Show (+´÷≠) |{𝕊: 10‿1000 ExpectedRange 1e3}¨↕10000 +# •Show (+´÷≠) |{𝕊: 10‿1000 ExpectedRange 1e6}¨↕10000 + +am ← 10000 +•Out "general" +(100‿128∾˜↕20) {(⌊(10×am)÷𝕨⌈1)‿𝕨 ExpectedRange 𝕩}⌜ 3‿10‿100‿1000‿10000‿100000‿1e8‿1e15∾2⋆2↓↕34 +(↕10) {! ∧´0=𝕩 Range 1}⌜ ↕200 + +•Out "bit boolean" +{⟨5×am,𝕩⟩ ExpectedRange 2}¨ ⥊31‿32‿33×⌜↕100 +•Out "float" +{⟨2×am,𝕩⟩ ExpectedRange 0}¨ ↕100