Skip to content

Commit caeaa52

Browse files
committed
Fix +/\ +/\. (+/%#)/\ with NaNs
1 parent 13c4bb7 commit caeaa52

9 files changed

Lines changed: 174 additions & 66 deletions

File tree

jsrc/ap.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,17 +734,22 @@ static DF2(jtinfixd){F12IP;A z;C*x,*y;I c=0,d,k,m,n,p,q,r,*s,wr,*ws,wt,zc;
734734
#define SETZ {s=yv; DQ(c, *zv++=*s++; );}
735735
#define SETZD {s=yv; DQ(c, *zv++=*s++/d;);}
736736

737+
// check for infinity/NaN, EVNAN if so
738+
#define CKINFB(addr)
739+
#define CKINFI(addr)
740+
#define CKINFD(addr) ASSERT(((US*)(addr))[3]&0x7ffc!=0x7ffc,EVNAN)
741+
737742
#define MOVSUMAVG(Tw,Ty,ty,Tz,tz,xd,SET) \
738743
{Tw*u,*v;Ty*s,x=0,*yv;Tz*zv; \
739744
GATVS(z,tz,c*(1+p),AR(w),AS(w),tz##SIZE,GACOPYSHAPE,R 0); AS(z)[0]=1+p; \
740745
zv=(Tz*)AV(z); u=v=(Tw*)AV(w); \
741746
if(1==c){ \
742-
DQ(m, x+=*v++;); *zv++=xd; \
743-
DQ(p, x+=(Ty)*v++-(Ty)*u++; *zv++=xd;); \
747+
DQ(m, CKINF##Tw(v) x+=*v++;); *zv++=xd; \
748+
DQ(p, CKINF##Tw(v) x+=(Ty)*v++-(Ty)*u++; *zv++=xd;); \
744749
}else{ \
745750
GATVS(y,ty,c,1,0,ty##SIZE,GACOPYSHAPE0,R 0); s=yv=(Ty*)AV1(y); DQ(c, *s++=0;); \
746-
DQ(m, s=yv; DQ(c, *s+++=*v++;);); SET; \
747-
DQ(p, s=yv; DQ(c, x=*s+++=(Ty)*v++-(Ty)*u++; *zv++=xd;);); \
751+
DQ(m, s=yv; DQ(c, CKINF##Tw(v) *s+++=*v++;);); SET; \
752+
DQ(p, s=yv; DQ(c, CKINF##Tw(v) x=*s+++=(Ty)*v++-(Ty)*u++; *zv++=xd;);); \
748753
}}
749754

750755
static A jtmovsumavg1(J jt,I m,A w,A fs,B avg){A y,z;D d=(D)m;I c,p,wt;

jsrc/as.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,9 @@ static DF2(jtofxinv){F12IP;A f,fs,z;C c;I t;V*v;
354354
F2RANKW(0,RMAX,jtofxinv,self);
355355
fs=FAV(self)->fgh[0]; f=FAV(fs)->fgh[0]; v=FAV(f); c=v->id; t=AT(w); // self = f/\. fs = f/ f = f v = verb info for f
356356
if(!(c==CPLUS||c==CBDOT&&t&INT||((c&-2)==CEQ)&&t&B01))R outfix(a,w,self); // if not +/\. or m b./\. or =/\. or ~:/\.
357-
A z0,z1; z=irs2(dfv1(z0,w,fs),dfv2(z1,a,w,bslash(fs)),c==CPLUS?ds(CMINUS):f, RMAX,-1L,jtatomic2);
358-
if(jt->jerr==EVNAN){RESETERR; R outfix(a,w,self);}else R z;
357+
A z0; RZ(dfv1(z0,w,fs)) if(t&FL&&unlikely(!all0(jtisnan(jt,z0)))){RESETERR; R outfix(a,w,self);} // take u/ y; if FL, see if result contains NaN, failover if so to slow version
358+
A z1; z=irs2(z0,dfv2(z1,a,w,bslash(fs)),c==CPLUS?ds(CMINUS):f, RMAX,-1L,jtatomic2); // x u/\. y = (u/ y) uinv x u/\ y
359+
if(jt->jerr==EVNAN){RESETERR; R outfix(a,w,self);}else R z; // failover if NaN
359360
} /* a f/\. w where f has an "undo" */
360361

361362
static DF2(jtofxassoc){F12IP;A f,i,j,p,s,x,z;C id,*zv;I c,d,k,kc,m,r,t;V*v;VA2 adocv;

jsrc/j.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,6 +2084,7 @@ if(likely(type _i<3)){z=(type _i<1)?1:(type _i==1)?_zzt[0]:_zzt[0]*_zzt[1];}else
20842084
// PRODX takes the product of init and v[0..n-1], generating error if overflow, but waiting till the end so no error if there is a 0 in the product
20852085
// overflow sets z to the error value of 0; if we see a multiplicand of 0 we stop right away so we can skip the error
20862086
// This is written to be branchless for rank < 3
2087+
// n may be negative
20872088
#if SY_64
20882089
// I have been unable to make clang produce a simple loop that doesn't end with a backward branch. So I am going to handle ranks 0-2 here and call a subroutine for the rest
20892090
#define PRODX(z,n,v,init) \

jsrc/ja.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ extern void jfree4gmp(void*,size_t);
920920
#define raincr(x) __atomic_fetch_add(&AC(x),1,__ATOMIC_ACQ_REL)
921921
#define rasv(x) {I c=AC(x); if(likely(!ACISPERM(c))){if(c<0)AC(x)=(I)((UI)c+(ACINPLACE+ACUC1));else raincr(x); radescend(x,sv)}} // better a misbranch than an atomic instruction if c<0. Could avoid recur check if AC>1
922922
#define ra(x) {I c=AC(x); if(likely(!ACISPERM(c))){if(c<0)AC(x)=(I)((UI)c+(ACINPLACE+ACUC1));else raincr(x); radescend(x)}} // better a misbranch than an atomic instruction if c<0. Could avoid recur check if AC>1
923+
#define raN(x,n) {I c=AC(x); if(likely(!ACISPERM(c))){if(c<0)AC(x)=(I)((UI)c+(ACINPLACE+(n)));else __atomic_fetch_add(&AC(x),(n),__ATOMIC_ACQ_REL); radescend(x)}} // add N to usecount all at once
923924
#define racontents(x) {I c=AC(x); if(MEMAUDIT!=0&&c<0)SEGFAULT; if(likely(!ACISPERM(c))){raincr(x); radescend(x)}} // Used on contents of box, which cannot have AC<0
924925
#define rareccontents(x) {I c=AC(x); if(MEMAUDIT!=0&&c<0)SEGFAULT; if(likely(!ACISPERM(c))){raincr(x);}} // Used on contents of recursive box, which cannot have AC<0 and does not need recursion
925926
#define raname(x) {if(likely(!ACISPERM(AC(x))))raincr(x);} // NAME is not inplaceable, seldom local; just add 1. No traverse needed on ra

jsrc/vcat.c

Lines changed: 106 additions & 48 deletions
Large diffs are not rendered by default.

jsrc/vf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ F2(jtsetfv){F12IP;A q=jt->fill;
2222
jt->fillv=CAV(q); jt->fillvlen=bpnoun(t); // jt->fillv points to the fill atom
2323
}else{fillv0(t);} // empty or no fill. create std fill in fillv0 and point jt->fillv at it
2424
w=TYPESEQ(t,AT(w))?w:cvt(t,w); // convert w to dest type. note if w is boxed and nonempty this won't change it
25-
if(w==0&&jt->jerr==EVDOMAIN)jt->jerr=EVINHOMO; // if we got an error here (always called DOMAIN), show it as EVHOMO when we eformat
25+
if(unlikely(w==0)&&jt->jerr==EVDOMAIN)jt->jerr=EVINHOMO; // if we got an error here (always called DOMAIN), show it as EVHOMO when we eformat
2626
R w;
2727
}
2828
// simpler version when there is only w. We make AT(w) an argument to save a fetch

jsrc/vt.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@ F1(jtcurtail){F12IP; R jtdrop(jtfg,num(-1),w);}
1010

1111
F1(jtshift1){F12IP;R drop(num(-1),over(num(1),w));}
1212

13-
static A jttk0(J jt,B b,A a,A w){A z;I k,m=0,n,p,r,*s,*u;
13+
// take empty or from empty, a=take shape, w=takefrom. b=1 if a DOES NOT contain a 0
14+
// scaf* pass n and u as args
15+
static INLINE A jttk0(J jt,B b,A a,A w){A z;I k,m=0,n,p,r,*s,*u;
1416
r=AR(w); n=AN(a); u=AV(a);
1517
if(!b){PRODX(m,n,u,1) ASSERT(m>IMIN,EVLIMIT); PRODX(m,r-n,n+AS(w),ABS(m))}
1618
GA(z,AT(w),m,r,AS(w));
19+
// scaf* if take not empty, set fill; if take empty, return
1720
s=AS(z); DO(n, p=u[i]; ASSERT(p>IMIN,EVLIMIT); *s++=ABS(p););
1821
if(m){k=bpnoun(AT(w)); mvc(k*m,AVn(r,z),k,jt->fillv);}
1922
R z;
2023
}
2124

22-
static F2(jttks){F12IP;PROLOG(0092);A a1,q,x,y,z;B b,c;I an,m,r,*s,*u,*v;P*wp,*zp;
25+
// scaf* pass an and u as args
26+
static INLINE F2(jttks){F12IP;PROLOG(0092);A a1,q,x,y,z;B b,c;I an,m,r,*s,*u,*v;P*wp,*zp;
2327
an=AN(a); u=AV(a); r=AR(w); s=AS(w);
2428
GASPARSE(z,AT(w),1,r,s); v=AS(z); DO(an, v[i]=ABS(u[i]););
2529
zp=PAV(z); wp=PAV(w);
@@ -48,12 +52,16 @@ static F2(jttks){F12IP;PROLOG(0092);A a1,q,x,y,z;B b,c;I an,m,r,*s,*u,*v;P*wp,*z
4852
EPILOG(z);
4953
} /* take on sparse array w */
5054

51-
// general take routine. a is result frame followed by signed take values i. e. shape of result, w is array
52-
static F2(jttk){F12IP;PROLOG(0093);A y,z;B b=0;C*yv,*zv;I c,d,dy,dz,e,i,k,m,n,p,q,r,*s,t,*u;
55+
// general take/drop routine. a is result frame followed by signed take values i. e. shape of result, w is array
56+
// scaf* pass n and u as args
57+
static F2(jttk){F12IP;PROLOG(0093);A y,z;C*yv,*zv;I c,d,dy,dz,e,i,k,m,n,p,q,r,*s,t,*u;
5358
n=AN(a); u=AV(a); r=AR(w); s=AS(w); t=AT(w);
5459
if(unlikely(ISSPARSE(t)))R tks(a,w);
55-
DO(n, if(!u[i]){b=1; break;}); if(!b)DO(r-n, if(!s[n+i]){b=1; break;}); // if empty take, or take from empty cell, set b
56-
if(((b-1)&AN(w))==0)R tk0(b,a,w); // this handles empty w, so PROD OK below b||!AN(w)
60+
// obsolete DO(n, if(!u[i]){b=1; break;}); if(!b)DO(r-n, if(!s[n+i]){b=1; break;}); // if empty take, or take from empty cell, set b
61+
DO(n, if(!u[i])goto emptytake;); DO(r-n, if(!s[n+i])goto emptytake;); // if empty take, or take from empty cell, set b
62+
if(unlikely(AN(w)==0)){B b=0; if(0){emptytake: b=1;} R tk0(b,a,w);}
63+
// obsolete if(((b-1)&AN(w))==0)R tk0(b,a,w); // this handles empty w, so PROD OK below b||!AN(w)
64+
#if 1 // obsolete
5765
k=bpnoun(t); z=w; c=q=1; // c will be #cells for this axis
5866
// process take one axis at a time
5967
for(i=0;i<n;++i){I itemsize;
@@ -62,23 +70,25 @@ static F2(jttk){F12IP;PROLOG(0093);A y,z;B b=0;C*yv,*zv;I c,d,dy,dz,e,i,k,m,n,p,
6270
PROD(itemsize,r-i-1,s+i+1); // size of item of cell
6371
DPMULDE(c*itemsize,q,d); GA(y,t,d,r,AS(z)); AS(y)[i]=q; // this catches q=IMIN: mult error or GA error d=#cells*itemsize*#taken items
6472
if(q>m)mvc(k*AN(y),CAVn(r,y),k,jt->fillv); // overtake - fill the whole area
65-
itemsize *= k; e=itemsize*MIN(m,q); // itemsize=in bytes; e=total bytes moved per item
73+
itemsize*=k; e=itemsize*MIN(m,q); // itemsize=in bytes; e=total bytes moved per item
6674
dy=itemsize*q; yv=CAV(y);
6775
dz=itemsize*m; zv=CAV(z);
6876
m-=q; I yzdiff=dy-dz; yv+=REPSGN(p&m)&yzdiff; zv-=REPSGN(p&-m)&yzdiff;
6977
DQ(c, MC(yv,zv,e); yv+=dy; zv+=dz;);
7078
z=y;
7179
}
7280
}
81+
#else
82+
// scaf* set fill if needed
83+
#endif
7384
EPILOG(z);
7485
}
7586

7687
F2(jttake){F12IP;A s;I acr,af,ar,n,*v,wcr,wf,wr;
77-
7888
ARGCHK2(a,w); I wt=AT(w); // wt=type of w
7989
acr=jt->ranks>>RANKTX; wcr=(RANKT)jt->ranks; RESETRANK; // save ranks before they are destroyed
8090
if(unlikely(ISSPARSE(AT(a))))RZ(a=denseit(a)); //if a is empty this destroys jt->ranks
81-
if(likely(!ISSPARSE(wt)))RZ(w=jtsetfv1(jt,w,AT(w))); // pity to do this before we know we need fill
91+
if(likely(!ISSPARSE(wt)))RZ(w=jtsetfv1(jt,w,AT(w))); // scaf* wrong to do this before we know we need fill
8292
ar=AR(a); acr=ar<acr?ar:acr; af=ar-acr; // ?r=rank, ?cr=cell rank, ?f=length of frame
8393
wr=AR(w); wcr=wr<wcr?wr:wcr; wf=wr-wcr;
8494
if(((af-1)&(acr-2))>=0){
@@ -99,6 +109,7 @@ F2(jttake){F12IP;A s;I acr,af,ar,n,*v,wcr,wf,wr;
99109
if(i<AN(s)){
100110
s=ca(s); if(!ISDENSETYPE(AT(a),FL))RZ(a=ccvt(FL,a,0)); // copy area we are going to change; put a in a form where we can recognize infinity
101111
for(;i<AN(s);++i){if(DAV(a)[i]==IMIN)IAV(s)[i]=IMIN;else if(INF(DAV(a)[i]))IAV(s)[i]=wcr?ws[wf+i]:1;} // kludge. The problem is which huge values to consider infinite. This is how it was done
112+
// scaf what's this IMIN business? 32-bit? avoid all the conversions
102113
}
103114
}
104115
a=s;
@@ -107,7 +118,7 @@ F2(jttake){F12IP;A s;I acr,af,ar,n,*v,wcr,wf,wr;
107118
I tklen = IAV(a)[0]; // get the one number in a, the take amount
108119
I tkasign = REPSGN(tklen); // 0 if tklen nonneg, ~0 if neg
109120
I nitems = ws[0]; // number of items of w
110-
I tkabs = (tklen^tkasign)-tkasign; // ABS(tklen)
121+
I tkabs = (tklen^tkasign)-tkasign; // (UI)ABS(tklen)
111122
if((UI)tkabs<=(UI)nitems) { // if this is not an overtake... (unsigned to handle overflow, if tklen=IMIN).
112123
// calculate offset
113124
I woffset = tkasign&(tklen + nitems); // x+#y if x neg, 0 if x pos
@@ -191,7 +202,7 @@ static F1(jtrsh0){F12IP;A x,y;I wcr,wf,wr,*ws;
191202
}
192203

193204
F1(jthead){F12IP;I wcr,wf,wr;
194-
205+
195206
ARGCHK1(w);
196207
wr=AR(w); wcr=(RANKT)jt->ranks; wcr=wr<wcr?wr:wcr; wf=wr-wcr; // no RESETRANK so that we can pass rank into other code
197208
if(unlikely(!wcr)){RETF(RETARG(w)) // {."0, a NOP

test/g320.ijs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,34 @@ xx =: i. 1e6 1 1
664664
NB. fill not used if not needed
665665
1: (i. 2 3 2 5 6) ,!.'a'"3 i. 2 5 6
666666

667+
NB. x fill t v y, checking ,!.fill"v
668+
t =: {{ xx =: x [ yy =: y [ mm =: m [ nn =: n
669+
if. 0=#m do. assert. (x {{ x , y }}"n y) -: x ,"n y else. assert. (x m {{ x ,!.m y }}"n y) -: x ,!.m"n y end. }}
670+
671+
NB. try all ranks of x/y, and with a 0 at each position
672+
tt =: {{
673+
xxx =: x [ yyy =: y
674+
cr =: x ,&#&$ y NB. x and y are always a cell of result
675+
x (m t _) y NB. check the single cell
676+
for_r. ,/ ,"0/~ 0 1 2 do.
677+
'prefx prefy' =: pref =: {.&(?5 5)&.> r
678+
xs =. (prefx , $x) ($!.'',) y [ ys =. (prefy , $y) ($!.'',) x
679+
xs (m t cr) ys NB. check rank without 0 insertion
680+
for_s. ,/ x ,"0/&i.&#&$ y do. NB. insert 0 in each position
681+
'sx sy' =: s
682+
((($!.'',)~ prefx , 0 sx} $) x) (m t cr) ((($!.'',)~ prefy , 0 sy} $) y)
683+
end.
684+
end.
685+
1
686+
}}
687+
688+
(>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100) ('' tt) (>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
689+
(>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100) (100 tt) (>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
690+
(>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100x) ('' tt) (>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
691+
(>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100x) (100x tt) (>: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
692+
(<"0 >: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100) ('' tt) (<"0 >: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
693+
(<"0 >: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100) ((<5) tt) (<"0 >: ((>: 0.2 0.5 0.8 I. ? 0) ?@$ 8) ?@$ 100)
694+
667695

668696
randfini''
669697

test/g430.ijs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,9 @@ a =: i. 1000 1000
581581
(7!:2 '; 2 (<@(]@]/)\) a') > 1.5 * 7!:2 '2 ;@:(<@(]@]/)\) a'
582582
(; 2 (<@(]@]/)\) a) -: 2 ;@:(<@(]@]/)\) a
583583

584+
6 _. _. _. 15 (= +. *.&(128!:5))"0 (3) +/\ 1 2 3 _. 4 5 6
585+
2 _. _. _. 5 (= +. *.&(128!:5))"0 (3) (+/%#)\ 1 2 3 _. 4 5 6
586+
584587

585588
randfini''
586589

0 commit comments

Comments
 (0)