Right argument narrowing for numeric Bins

This commit is contained in:
Marshall Lochbaum 2023-07-09 19:31:04 -04:00
parent 9511598aa3
commit 492e97e2ca
2 changed files with 60 additions and 10 deletions

View File

@ -27,8 +27,8 @@
// 4-byte branchless binary search, 4-byte output
// SHOULD support fast character searches
// Boolean 𝕨 or 𝕩: lookup table (single binary search on boolean 𝕨)
// Different widths: widen narrower argument
// SHOULD narrow wider-type 𝕩 if it isn't much shorter
// Different widths: generally widen narrower argument
// Narrow wider-type 𝕩 instead if it isn't much shorter
// SHOULD trim wider-type 𝕨 and possibly narrow
// Same-width numbers:
// Output type based on ≠𝕨
@ -393,8 +393,10 @@ static u64 CAT(bit_boundary,GRADE_UD(up,dn))(u64* x, u64 n) {
return b + POPC(v);
}
extern B CAT(GRADE_UD(le,ge),c2)(B,B,B);
#define LE_C2 CAT(GRADE_UD(le,ge),c2)
extern B LE_C2(B,B,B);
extern B select_c2(B t, B w, B x);
extern B mul_c2(B, B, B);
B GRADE_CAT(c2)(B t, B w, B x) {
if (isAtm(w) || RNK(w)==0) thrM(GRADE_CHR": 𝕨 must have rank≥1");
@ -421,7 +423,7 @@ B GRADE_CAT(c2)(B t, B w, B x) {
B c = IGet(w, 0);
if (LIKELY(we<el_B & xe<el_B)) {
decG(w);
return CAT(GRADE_UD(le,ge),c2)(m_f64(0), c, x);
return LE_C2(m_f64(0), c, x);
} else {
SLOW2("𝕨"GRADE_CHR"𝕩", w, x); // Could narrow for mixed types
u64* rp; r = m_bitarrc(&rp, x);
@ -445,7 +447,10 @@ B GRADE_CAT(c2)(B t, B w, B x) {
}
if (LIKELY(we<el_B & xe<el_B)) {
if (elNum(we)) { // number
#if SINGELI
B mult = bi_N;
#endif
if (elNum(we)) {
if (elNum(xe)) {
if (RARE(we==el_bit | xe==el_bit)) {
if (we==el_bit) {
@ -470,10 +475,30 @@ B GRADE_CAT(c2)(B t, B w, B x) {
return r;
}
#if SINGELI
u8 ze = we>xe? we : xe;
if (ze > we) { switch (ze) { default:UD; case el_i16:w=toI16Any(w);break; case el_i32:w=toI32Any(w);break; case el_f64:w=toF64Any(w);break; } }
if (ze > xe) { switch (ze) { default:UD; case el_i16:x=toI16Any(x);break; case el_i32:x=toI32Any(x);break; case el_f64:x=toF64Any(x);break; } }
we = ze;
#define WIDEN(E, X) switch (E) { default:UD; case el_i16:X=toI16Any(X);break; case el_i32:X=toI32Any(X);break; case el_f64:X=toF64Any(X);break; }
if (xe > we) {
if (xia/4 < wia) { // Narrow x
assert(el_i8 <=we && we<=el_i32);
assert(el_i16<=xe && xe<=el_f64);
i32 pre = -1; pre<<=(8<<(we-el_i8))-1;
pre = GRADE_UD(pre,-1-pre); // Smallest value of w's type
i32 w0 = o2iG(IGetU(w,0));
// Saturation is correct except it can move low values past
// pre. Post-adjust with mult×r
if (w0 == pre) mult = LE_C2(m_f64(0), m_i32(pre), incG(x));
// Narrow x with saturating conversion
B xn; void *xp = m_tyarrc(&xn, elWidth(we), x, el2t(we));
u8 ind = xe<el_f64 ? (we-el_i8)+(xe-el_i16)
: 3 + 2*(we-el_i8) + GRADE_UD(0,1);
si_saturate[ind](xp, tyany_ptr(x), xia);
decG(x); x = xn;
} else {
WIDEN(xe, w)
we = xe;
}
}
if (we > xe) WIDEN(we, x)
#undef WIDEN
#else
if (!elInt(we) | !elInt(xe)) goto gen;
w=toI32Any(w); x=toI32Any(x);
@ -484,7 +509,7 @@ B GRADE_CAT(c2)(B t, B w, B x) {
for (u64 i=0; i<xia; i++) rp[i]=wia;
goto done;
}
} else { // character
} else { // w is character
if (elNum(xe)) {
Arr* ra=allZeroes(xia); arr_shCopy(ra, x);
r=taga(ra); goto done;
@ -499,6 +524,7 @@ B GRADE_CAT(c2)(B t, B w, B x) {
u8 rl = wia<128 ? 0 : wia<(1<<15) ? 1 : wia<(1<<31) ? 2 : 3;
void *rp = m_tyarrc(&r, 1<<rl, x, el2t(el_i8+rl));
si_bins[k*2 + GRADE_UD(0,1)](tyany_ptr(w), wia, tyany_ptr(x), xia, rp, rl);
if (!q_N(mult)) r = mul_c2(m_f64(0), mult, r);
#else
i32* rp; r = m_i32arrc(&rp, x);
i32* wi = tyany_ptr(w);
@ -536,6 +562,7 @@ done:
return r;
}
#undef GRADE_CHR
#undef LE_C2
#undef LT
#undef FOR

View File

@ -374,3 +374,26 @@ exportT{
'si_bins',
join{table{bins, tup{i8,i16,i32,f64}, tup{1,0}}}
}
# Utility for narrowing binary search right argument
include './f64'
require{'math.h'}
fn saturate{F,T,...up}(dst:*void, src:*void, n:u64) : void = {
# Auto-vectorizes, although not that well for f64
def a = minvalue{T}; af := cast_i{F,a}
def b = maxvalue{T}; bf := cast_i{F,b}
@for (d in *T~~dst, xf in *F~~src over n) {
x := if (F==f64) (if (tupsel{0,up}) floor else ceil){xf} else xf
d = cast_i{T, x}
if (x<af) d = a
if (x>bf) d = b
}
}
exportT{
'si_saturate',
each{{a}=>saturate{...a}, merge{
tup{tup{i16,i8}, tup{i32,i8}, tup{i32,i16}},
join{table{bind{tup,f64}, tup{i8,i16,i32}, tup{1,0}}}
}}
}