| @@ -34,7 +34,7 @@ conv_to_double(sl_v v, void *data, sl_numtype tag) · 33 unmodified lines |
| 34 | 34 | case T_U32: case T_P32: return *(u32int*)data; |
| 35 | 35 | case T_S64: |
| 36 | 36 | d = *(s64int*)data; |
| 37 | | − if(d > 0 && *(s64int*)data < 0) // can happen! |
| 37 | + if(d > 0 && *(s64int*)data < 0) // can happen! |
| 38 | 38 | d = -d; |
| 39 | 39 | return d; |
| 40 | 40 | case T_U64: case T_P64: return *(u64int*)data; |
| @@ -103,7 +103,7 @@ conv_to_u64(sl_v v, void *data, sl_numtype tag) · 62 unmodified lines |
| 103 | 103 | cthrow(type_error(nil, "num", v), v); |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | | −sl_purefn |
| 106 | +static sl_purefn |
| 107 | 107 | bool |
| 108 | 108 | cmp_same_lt(void *a, void *b, sl_numtype tag) |
| 109 | 109 | { |
| @@ -117,13 +117,13 @@ cmp_same_lt(void *a, void *b, sl_numtype tag) · 7 unmodified lines |
| 117 | 117 | case T_S64: return *(s64int*)a < *(s64int*)b; |
| 118 | 118 | case T_U64: case T_P64: return *(u64int*)a < *(u64int*)b; |
| 119 | 119 | case T_BIG: return mpcmp(*(mpint**)a, *(mpint**)b) < 0; |
| 120 | | − case T_F32: return *(float*)a < *(float*)b; |
| 121 | | − case T_F64: return *(double*)a < *(double*)b; |
| 120 | + case T_F32: return *(float*)a < *(float*)b && !isnan(*(float*)a) && !isnan(*(float*)b); |
| 121 | + case T_F64: return *(double*)a < *(double*)b && !isnan(*(double*)a) && !isnan(*(double*)b); |
| 122 | 122 | } |
| 123 | 123 | return false; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | | −sl_purefn |
| 126 | +static sl_purefn |
| 127 | 127 | bool |
| 128 | 128 | cmp_same_eq(void *a, void *b, sl_numtype tag) |
| 129 | 129 | { |
| @@ -137,8 +137,8 @@ cmp_same_eq(void *a, void *b, sl_numtype tag) · 7 unmodified lines |
| 137 | 137 | case T_S64: return *(s64int*)a == *(s64int*)b; |
| 138 | 138 | case T_U64: case T_P64: return *(u64int*)a == *(u64int*)b; |
| 139 | 139 | case T_BIG: return mpcmp(*(mpint**)a, *(mpint**)b) == 0; |
| 140 | | − case T_F32: return *(float*)a == *(float*)b && !isnan(*(float*)a); |
| 141 | | − case T_F64: return *(double*)a == *(double*)b && !isnan(*(double*)b); |
| 140 | + case T_F32: return *(float*)a == *(float*)b && !isnan(*(float*)a) && !isnan(*(float*)b); |
| 141 | + case T_F64: return *(double*)a == *(double*)b && !isnan(*(double*)a) && !isnan(*(double*)b); |
| 142 | 142 | } |
| 143 | 143 | return false; |
| 144 | 144 | } |
| @@ -146,120 +146,86 @@ cmp_same_eq(void *a, void *b, sl_numtype tag) · 1 unmodified line |
| 146 | 146 | /* FIXME one is allocated for all compare ops */ |
| 147 | 147 | static mpint *cmpmpint; |
| 148 | 148 | |
| 149 | | −bool |
| 150 | | −cmp_lt(void *a, sl_numtype atag, void *b, sl_numtype btag) |
| 149 | +static sl_numtype |
| 150 | +promote(void *x, sl_numtype nt, void *d, mpint **m) |
| 151 | 151 | { |
| 152 | | − if(atag == btag) |
| 153 | | − return cmp_same_lt(a, b, atag); |
| 154 | | − |
| 155 | | − double da = conv_to_double(sl_nil, a, atag); |
| 156 | | − double db = conv_to_double(sl_nil, b, btag); |
| 157 | | − |
| 158 | | − if(isnan(da) || isnan(db)) |
| 159 | | − return false; |
| 160 | | − |
| 161 | | − // casting to double will only get the wrong answer for big int64s |
| 162 | | − // that differ in low bits |
| 163 | | − if(da < db) |
| 164 | | − return true; |
| 165 | | − if(db < da) |
| 166 | | − return false; |
| 167 | | − |
| 168 | | − if(cmpmpint == nil && (atag == T_BIG || btag == T_BIG)) |
| 169 | | − cmpmpint = mpnew(0); |
| 170 | | − |
| 171 | | − if(atag == T_U64){ |
| 172 | | − if(btag == T_S64) |
| 173 | | − return *(s64int*)b >= 0 && *(u64int*)a < (u64int)*(s64int*)b; |
| 174 | | − if(btag == T_F64) |
| 175 | | − return db >= 0 ? *(u64int*)a < (u64int)*(double*)b : 0; |
| 176 | | − if(btag == T_BIG) |
| 177 | | − return mpcmp(uvtomp(*(u64int*)a, cmpmpint), *(mpint**)b) < 0; |
| 178 | | − } |
| 179 | | − if(atag == T_S64){ |
| 180 | | − if(btag == T_U64) |
| 181 | | − return *(s64int*)a >= 0 && (u64int)*(s64int*)a < *(u64int*)b; |
| 182 | | − if(btag == T_F64) |
| 183 | | − return *(s64int*)a < (s64int)*(double*)b; |
| 184 | | − if(btag == T_BIG) |
| 185 | | − return mpcmp(vtomp(*(s64int*)a, cmpmpint), *(mpint**)b) < 0; |
| 186 | | − } |
| 187 | | − if(btag == T_U64){ |
| 188 | | − if(atag == T_F64) |
| 189 | | − return da >= 0 ? *(u64int*)b > (u64int)*(double*)a : 0; |
| 190 | | − if(atag == T_BIG) |
| 191 | | − return mpcmp(*(mpint**)a, uvtomp(*(u64int*)b, cmpmpint)) < 0; |
| 192 | | − } |
| 193 | | − if(btag == T_S64){ |
| 194 | | − if(atag == T_F64) |
| 195 | | − return *(s64int*)b > (s64int)*(double*)a; |
| 196 | | − if(atag == T_BIG) |
| 197 | | − return mpcmp(*(mpint**)a, vtomp(*(s64int*)b, cmpmpint)) < 0; |
| 198 | | − } |
| 199 | | − return false; |
| 152 | + if(nt >= T_F32){ |
| 153 | + *(double*)d = conv_to_double(sl_nil, x, nt); |
| 154 | + nt = T_F64; |
| 155 | + }else if(is_nt_uint(nt)){ |
| 156 | + *(u64int*)d = conv_to_u64(sl_nil, x, nt); |
| 157 | + nt = T_U64; |
| 158 | + }else if(is_nt_sint(nt)){ |
| 159 | + *(s64int*)d = conv_to_s64(sl_nil, x, nt); |
| 160 | + nt = T_S64; |
| 161 | + }else if(nt == T_BIG){ |
| 162 | + if(cmpmpint == nil) |
| 163 | + cmpmpint = mpnew(128); |
| 164 | + *m = *(mpint**)x; |
| 165 | + }else |
| 166 | + abort(); |
| 167 | + return nt; |
| 200 | 168 | } |
| 201 | 169 | |
| 202 | | −bool |
| 203 | | −cmp_eq(void *a, sl_numtype atag, void *b, sl_numtype btag, bool equalnans) |
| 170 | +int |
| 171 | +cmp_numeric(void *ap, sl_numtype ant, void *bp, sl_numtype bnt) |
| 204 | 172 | { |
| 205 | | − union { |
| 206 | | − double d; |
| 207 | | − s64int i64; |
| 208 | | − }u, v; |
| 209 | | − |
| 210 | | − if(atag == btag && (!equalnans || atag < T_F32)) |
| 211 | | − return cmp_same_eq(a, b, atag); |
| 212 | | − |
| 213 | | − double da = conv_to_double(sl_nil, a, atag); |
| 214 | | − double db = conv_to_double(sl_nil, b, btag); |
| 173 | + if(ant == bnt){ |
| 174 | + if(cmp_same_eq(ap, bp, ant)) |
| 175 | + return 0; |
| 176 | + return cmp_same_lt(ap, bp, ant) ? -1 : 1; |
| 177 | + } |
| 215 | 178 | |
| 216 | | − if((int)atag >= T_F32 && (int)btag >= T_F32){ |
| 217 | | − if(equalnans){ |
| 218 | | − u.d = da; v.d = db; |
| 219 | | − return u.i64 == v.i64; |
| 179 | + union{ |
| 180 | + u64int u; |
| 181 | + s64int s; |
| 182 | + double d; |
| 183 | + mpint *m; |
| 184 | + }a, b; |
| 185 | + ant = promote(ap, ant, &a.u, &a.m); |
| 186 | + bnt = promote(bp, bnt, &b.u, &b.m); |
| 187 | + |
| 188 | + switch(ant){ |
| 189 | + case T_U64: |
| 190 | + switch(bnt){ |
| 191 | + case T_U64: return a.u < b.u ? -1 : (a.u == b.u ? 0 : 1); |
| 192 | + case T_S64: return a.u < b.u && b.s > 0 ? -1 : (a.u == b.u && b.s >= 0 ? 0 : 1); |
| 193 | + case T_F64: return isnan(b.d) ? 1 : (a.u < b.d && b.d > 0 ? -1 : (a.u == b.d && b.d >= 0 ? 0 : 1)); |
| 194 | + case T_BIG: return mpcmp(uvtomp(a.u, cmpmpint), b.m); |
| 195 | + default: break; |
| 196 | + } |
| 197 | + break; |
| 198 | + case T_S64: |
| 199 | + switch(bnt){ |
| 200 | + case T_S64: return a.s < b.s ? -1 : (a.s == b.s ? 0 : 1); |
| 201 | + case T_U64: return (a.s < 0 || a.u < b.u) ? -1 : (a.u == b.u && a.s >= 0 ? 0 : 1); |
| 202 | + case T_F64: return isnan(b.d) ? 1 : (a.s < b.d ? -1 : (a.s == b.d ? 0 : 1)); |
| 203 | + case T_BIG: return mpcmp(vtomp(a.s, cmpmpint), b.m); |
| 204 | + default: break; |
| 205 | + } |
| 206 | + break; |
| 207 | + case T_F64: |
| 208 | + if(isnan(a.d)) |
| 209 | + return 1; |
| 210 | + switch(bnt){ |
| 211 | + case T_F64: return isnan(b.d) ? 1 : (a.d < b.d ? -1 : (a.d == b.d ? 0 : 1)); |
| 212 | + case T_U64: return (a.d < 0 || a.d < b.u) ? -1 : (a.d == b.u ? 0 : 1); |
| 213 | + case T_S64: return a.d < b.s ? -1 : (a.d == b.s ? 0 : 1); |
| 214 | + case T_BIG: return mpcmp(dtomp(a.d, cmpmpint), b.m); |
| 215 | + default: break; |
| 220 | 216 | } |
| 221 | | − return da == db; |
| 217 | + break; |
| 218 | + case T_BIG: |
| 219 | + switch(bnt){ |
| 220 | + case T_U64: return mpcmp(a.m, uvtomp(b.u, cmpmpint)); |
| 221 | + case T_S64: return mpcmp(a.m, vtomp(b.s, cmpmpint)); |
| 222 | + case T_F64: return isnan(b.d) ? 1 : mpcmp(a.m, dtomp(b.d, cmpmpint)); |
| 223 | + default: break; |
| 224 | + } |
| 225 | + break; |
| 226 | + default: |
| 227 | + break; |
| 222 | 228 | } |
| 223 | 229 | |
| 224 | | − if(da != db) |
| 225 | | − return false; |
| 226 | | − |
| 227 | | − if(cmpmpint == nil && (atag == T_BIG || btag == T_BIG)) |
| 228 | | − cmpmpint = mpnew(0); |
| 229 | | − |
| 230 | | − if(atag == T_U64){ |
| 231 | | − // this is safe because if a had been bigger than INT64_MAX, |
| 232 | | − // we would already have concluded that it's bigger than b. |
| 233 | | − if(btag == T_S64) |
| 234 | | − return *(s64int*)b >= 0 && *(u64int*)a == *(u64int*)b; |
| 235 | | − if(btag == T_F64) |
| 236 | | − return *(double*)b >= 0 && *(u64int*)a == (u64int)*(double*)b; |
| 237 | | − if(btag == T_BIG) |
| 238 | | − return mpcmp(uvtomp(*(u64int*)a, cmpmpint), *(mpint**)b) == 0; |
| 239 | | − } |
| 240 | | − if(atag == T_S64){ |
| 241 | | − if(btag == T_U64) |
| 242 | | − return *(s64int*)a >= 0 && *(u64int*)a == *(u64int*)b; |
| 243 | | − if(btag == T_F64) |
| 244 | | − return *(s64int*)a == (s64int)*(double*)b; |
| 245 | | − if(btag == T_BIG) |
| 246 | | − return mpcmp(vtomp(*(s64int*)a, cmpmpint), *(mpint**)b) == 0; |
| 247 | | − } |
| 248 | | − if(btag == T_U64){ |
| 249 | | − if(atag == T_S64) |
| 250 | | − return *(s64int*)a >= 0 && *(u64int*)b == *(u64int*)a; |
| 251 | | − if(atag == T_F64) |
| 252 | | − return *(double*)a >= 0 && *(u64int*)b == (u64int)*(double*)a; |
| 253 | | − if(atag == T_BIG) |
| 254 | | − return mpcmp(*(mpint**)a, uvtomp(*(u64int*)b, cmpmpint)) == 0; |
| 255 | | − } |
| 256 | | − if(btag == T_S64){ |
| 257 | | − if(atag == T_U64) |
| 258 | | − return *(s64int*)b >= 0 && *(u64int*)b == *(u64int*)a; |
| 259 | | − if(atag == T_F64) |
| 260 | | − return *(s64int*)b == (s64int)*(double*)a; |
| 261 | | − if(atag == T_BIG) |
| 262 | | − return mpcmp(*(mpint**)a, vtomp(*(s64int*)b, cmpmpint)) == 0; |
| 263 | | − } |
| 264 | | − return true; |
| 230 | + abort(); |
| 265 | 231 | } |