fix float normalization from a •bit._cast result mutating the original
This commit is contained in:
parent
ea4da381f2
commit
03a28e4e34
@ -375,6 +375,50 @@ B count_c2(B t, B w, B x) {
|
|||||||
return reduceI32Width(r, wia);
|
return reduceI32Width(r, wia);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if nanBad and input contains a NaN, doesn't consume and returns m_f64(0)
|
||||||
|
// otherwise, consumes and returns an array with -0 (and NaNs if !nanBad) normalized
|
||||||
|
B asNormalized(B x, usz n, bool nanBad) {
|
||||||
|
f64* fp = f64any_ptr(x);
|
||||||
|
ux i = 0;
|
||||||
|
#if SINGELI_SIMD
|
||||||
|
i = simd_search_normalizable(fp, n);
|
||||||
|
if (i!=n) goto some;
|
||||||
|
#else
|
||||||
|
for (; i < n; i++) if (r_f64u(fp[i])==r_f64u(-0.0) || fp[i]!=fp[i]) goto some;
|
||||||
|
#endif
|
||||||
|
return x;
|
||||||
|
|
||||||
|
some:;
|
||||||
|
f64* rp;
|
||||||
|
B r;
|
||||||
|
if (TY(x)==t_f64arr && reusable(x)) {
|
||||||
|
rp = fp;
|
||||||
|
r = x;
|
||||||
|
} else {
|
||||||
|
r = m_f64arrc(&rp, x);
|
||||||
|
COPY_TO(rp, el_f64, 0, x, 0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nanBad) {
|
||||||
|
#if SINGELI_SIMD
|
||||||
|
if (RARE(simd_copy_ordered(rp+i, fp+i, n-i))) goto bad;
|
||||||
|
#else
|
||||||
|
for (; i < n; i++) {
|
||||||
|
if (RARE(fp[i]!=fp[i])) goto bad;
|
||||||
|
rp[i] = fp[i]+0.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
for (; i < n; i++) rp[i] = normalizeFloat(fp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r.u!=x.u) decG(x);
|
||||||
|
return r;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
if (r.u!=x.u) mm_free(v(r));
|
||||||
|
return m_f64(0);
|
||||||
|
}
|
||||||
|
|
||||||
void search_init(void) {
|
void search_init(void) {
|
||||||
{ u64* p; Arr* a=m_bitarrp(&p, 1); arr_shAtm(a); *p= 0; gc_add(enclosed_0=taga(a)); }
|
{ u64* p; Arr* a=m_bitarrp(&p, 1); arr_shAtm(a); *p= 0; gc_add(enclosed_0=taga(a)); }
|
||||||
|
|||||||
@ -77,16 +77,15 @@ static inline B shift_ne(B x, usz n, u8 lw, bool r0) { // consumes x
|
|||||||
decG(x); return r;
|
decG(x); return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canCompare64_norm(B x, usz n) {
|
B asNormalized(B x, usz n, bool nanBad); // from search.c
|
||||||
u8 e = TI(x,elType);
|
SHOULD_INLINE bool canCompare64_norm(B* x, void** xp, usz n) {
|
||||||
|
u8 e = TI(*x,elType);
|
||||||
if (e == el_B) return 0;
|
if (e == el_B) return 0;
|
||||||
if (e == el_f64) {
|
if (e == el_f64) {
|
||||||
f64* pf = f64any_ptr(x);
|
B r = asNormalized(*x, n, true);
|
||||||
for (usz i = 0; i < n; i++) {
|
if (r.u == m_f64(0).u) return 0;
|
||||||
f64 f = pf[i];
|
*x = r;
|
||||||
if (f!=f) return 0;
|
*xp = tyany_ptr(r);
|
||||||
pf[i] = f==0? 0 : f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -285,7 +284,7 @@ B memberOf_c1(B t, B x) {
|
|||||||
RADIX_LOOKUP_32(1, =0)
|
RADIX_LOOKUP_32(1, =0)
|
||||||
return taga(cpyBitArr(r));
|
return taga(cpyBitArr(r));
|
||||||
}
|
}
|
||||||
if (lw == 6 && canCompare64_norm(x, n)) {
|
if (lw==6 && canCompare64_norm(&x, &xv, n)) {
|
||||||
if (n<20) { BRUTE(64); }
|
if (n<20) { BRUTE(64); }
|
||||||
i8* rp; B r = m_i8arrv(&rp, n);
|
i8* rp; B r = m_i8arrv(&rp, n);
|
||||||
HASHTAB(u64, 64, 0, n, sz==msz? 0 : sz>=(1<<18)? 0 : sz>=(1<<14)? 3 : 5)
|
HASHTAB(u64, 64, 0, n, sz==msz? 0 : sz>=(1<<18)? 0 : sz>=(1<<14)? 3 : 5)
|
||||||
@ -397,7 +396,7 @@ B count_c1(B t, B x) {
|
|||||||
RADIX_LOOKUP_32(0, ++)
|
RADIX_LOOKUP_32(0, ++)
|
||||||
return num_squeeze(r);
|
return num_squeeze(r);
|
||||||
}
|
}
|
||||||
if (lw == 6 && canCompare64_norm(x, n)) {
|
if (lw==6 && canCompare64_norm(&x, &xv, n)) {
|
||||||
if (n<20) { BRUTE(64); }
|
if (n<20) { BRUTE(64); }
|
||||||
i32* rp; B r = m_i32arrv(&rp, n);
|
i32* rp; B r = m_i32arrv(&rp, n);
|
||||||
HASHTAB(u64, 64, 0, n, sz==msz? 0 : sz>=(1<<18)? 0 : sz>=(1<<14)? 3 : 5)
|
HASHTAB(u64, 64, 0, n, sz==msz? 0 : sz>=(1<<18)? 0 : sz>=(1<<14)? 3 : 5)
|
||||||
@ -502,7 +501,7 @@ B indexOf_c1(B t, B x) {
|
|||||||
HASHTAB(u32, 32, sz==msz? 0 : sz>=(1<<18)? 1 : sz>=(1<<14)? 4 : 6)
|
HASHTAB(u32, 32, sz==msz? 0 : sz>=(1<<18)? 1 : sz>=(1<<14)? 4 : 6)
|
||||||
decG(r); // Fall through
|
decG(r); // Fall through
|
||||||
}
|
}
|
||||||
if (lw==6 && canCompare64_norm(x, n)) {
|
if (lw==6 && canCompare64_norm(&x, &xv, n)) {
|
||||||
if (n<16) { BRUTE(64); }
|
if (n<16) { BRUTE(64); }
|
||||||
i32* rp; B r = m_i32arrv(&rp, n);
|
i32* rp; B r = m_i32arrv(&rp, n);
|
||||||
u64* xp = tyany_ptr(x);
|
u64* xp = tyany_ptr(x);
|
||||||
|
|||||||
@ -61,6 +61,8 @@ def __gt{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,30}; def __gt{a:T,b:T & T==[4]f64}
|
|||||||
def __ge{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,29}; def __ge{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,29}
|
def __ge{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,29}; def __ge{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,29}
|
||||||
def __lt{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,17}; def __lt{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,17}
|
def __lt{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,17}; def __lt{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,17}
|
||||||
def __le{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,18}; def __le{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,18}
|
def __le{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,18}; def __le{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,18}
|
||||||
|
def unord{a:T,b:T & T==[8]f32} = f32cmpAVX{a,b,3}
|
||||||
|
def unord{a:T,b:T & T==[4]f64} = f64cmpAVX{a,b,3}
|
||||||
|
|
||||||
# f32 arith
|
# f32 arith
|
||||||
def __add{a:T,b:T & T==[8]f32} = emit{T, '_mm256_add_ps', a, b}
|
def __add{a:T,b:T & T==[8]f32} = emit{T, '_mm256_add_ps', a, b}
|
||||||
|
|||||||
@ -25,8 +25,7 @@ def findFirst{C, M, F, ...v1} = {
|
|||||||
F{...args}
|
F{...args}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search{A, E}(l:*void, e0:A, n:u64) : u64 = {
|
def search{E, x, n:u64, OP} = {
|
||||||
def e = if (A==E) e0 else cast_i{E, e0}
|
|
||||||
def bulk = arch_defvw/width{E}
|
def bulk = arch_defvw/width{E}
|
||||||
def VT = [bulk]E
|
def VT = [bulk]E
|
||||||
def end = makeBranch{
|
def end = makeBranch{
|
||||||
@ -35,7 +34,7 @@ fn search{A, E}(l:*void, e0:A, n:u64) : u64 = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
muLoop{bulk, tern{arch_defvw>=256, 1, 2}, n, {is, M} => {
|
muLoop{bulk, tern{arch_defvw>=256, 1, 2}, n, {is, M} => {
|
||||||
eq:= eachx{==, loadBatch{*E~~l, is, VT}, VT**e}
|
eq:= each{OP, loadBatch{*E~~x, is, VT}}
|
||||||
if (homAny{M{tree_fold{|, eq}}}) {
|
if (homAny{M{tree_fold{|, eq}}}) {
|
||||||
findFirst{
|
findFirst{
|
||||||
{i,c} => homAny{c},
|
{i,c} => homAny{c},
|
||||||
@ -48,7 +47,31 @@ fn search{A, E}(l:*void, e0:A, n:u64) : u64 = {
|
|||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
export{'simd_search_u8', search{u64, u8}}
|
fn searchOne{A, E}(x:*void, e0:A, len:u64) : u64 = {
|
||||||
export{'simd_search_u16', search{u64, u16}}
|
def e = if (A==E) e0 else cast_i{E, e0}
|
||||||
export{'simd_search_u32', search{u64, u32}}
|
search{E, x, len, {c:VT} => c == VT**e}
|
||||||
export{'simd_search_f64', search{f64, f64}}
|
}
|
||||||
|
|
||||||
|
def isNegZero{x:T} = to_el{u64,x} == to_el{u64, T ** -f64~~0}
|
||||||
|
fn searchNormalizable{}(x:*f64, len:u64) : u64 = {
|
||||||
|
search{f64, x, len, {c:VT} => isNegZero{c} | (c!=c)}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copyOrdered{}(r:*f64, x:*f64, len:u64) : u1 = {
|
||||||
|
def E = f64
|
||||||
|
def bulk = arch_defvw/width{E}
|
||||||
|
def VT = [bulk]E
|
||||||
|
maskedLoop{bulk, len, {i, M} => {
|
||||||
|
c:= loadBatch{x, i, VT}
|
||||||
|
if (homAny{M{c!=c}}) return{1}
|
||||||
|
storeBatch{r, i, c + VT**0, M}
|
||||||
|
}}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
export{'simd_search_u8', searchOne{u64, u8}}
|
||||||
|
export{'simd_search_u16', searchOne{u64, u16}}
|
||||||
|
export{'simd_search_u32', searchOne{u64, u32}}
|
||||||
|
export{'simd_search_f64', searchOne{f64, f64}}
|
||||||
|
export{'simd_search_normalizable', searchNormalizable{}}
|
||||||
|
export{'simd_copy_ordered', copyOrdered{}}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
|
|
||||||
|
B asNormalized(B x, usz n, bool nanBad); // from search.c
|
||||||
NOINLINE u64 bqn_hashObj(B x, const u64 secret[4]) { // TODO manual separation of atom & arr probably won't be worth it when there are actually sane typed array hashing things
|
NOINLINE u64 bqn_hashObj(B x, const u64 secret[4]) { // TODO manual separation of atom & arr probably won't be worth it when there are actually sane typed array hashing things
|
||||||
if (isArr(x)) {
|
if (isArr(x)) {
|
||||||
usz xia = IA(x);
|
usz xia = IA(x);
|
||||||
@ -18,12 +18,13 @@ NOINLINE u64 bqn_hashObj(B x, const u64 secret[4]) { // TODO manual separation o
|
|||||||
void* data;
|
void* data;
|
||||||
u64 bytes;
|
u64 bytes;
|
||||||
switch(xe) { default: UD;
|
switch(xe) { default: UD;
|
||||||
case el_bit: bcl(x,xia); data = bitarr_ptr(x); bytes = (xia+7)>>3; break;
|
case el_bit: bcl(x,xia); bytes = (xia+7)>>3; data = bitarr_ptr(x); break;
|
||||||
case el_i8: case el_c8: data = tyany_ptr(x); bytes = xia*1; break;
|
case el_i8: case el_c8: bytes = xia*1; data = tyany_ptr(x); break;
|
||||||
case el_i16: case el_c16: data = tyany_ptr(x); bytes = xia*2; break;
|
case el_i16: case el_c16: bytes = xia*2; data = tyany_ptr(x); break;
|
||||||
case el_i32: case el_c32: data = tyany_ptr(x); bytes = xia*4; break;
|
case el_i32: case el_c32: bytes = xia*4; data = tyany_ptr(x); break;
|
||||||
case el_f64: data = f64any_ptr(x); bytes = xia*8;
|
case el_f64: bytes = xia*8;
|
||||||
for (ux i = 0; i < xia; i++) ((f64*)data)[i] = normalizeFloat(((f64*)data)[i]);
|
x = asNormalized(x, xia, false);
|
||||||
|
data = f64any_ptr(x);
|
||||||
break;
|
break;
|
||||||
case el_B:;
|
case el_B:;
|
||||||
data = TALLOCP(u64, xia);
|
data = TALLOCP(u64, xia);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user