native depth2⊏𝕩

This commit is contained in:
dzaima 2025-07-04 21:00:29 +03:00
parent 3a8d0be5a4
commit 7cf17cdad6
3 changed files with 283 additions and 31 deletions

View File

@ -29,7 +29,10 @@
// Generic cell size 𝕩:
// Computes a function that copies the necessary amount of bytes/bits
// Specializes over i8/i16/i32 𝕨
// SHOULD implement nested 𝕨
// Nested 𝕨:
// Recognizes a trailing element of a+↕b
// Converts remaining indices to single select indices via +⌜
// COULD have specialized select that skips OOB/negative checks
// Under Select - F⌾(i⊸⊏) 𝕩
// Specialized for rank-1 numeric 𝕩
@ -172,8 +175,218 @@ static NOINLINE B select_list_cell(usz wi, B x) { // guarantees returning new ar
return rb;
}
static NOINLINE void select_depth2_bad(B w, B x) {
usz wia = IA(w);
if (IA(x)==0 && wia>0) {
u8 we;
w = squeeze_numTry(w, &we, SQ_NUM);
if (elNum(we)) {
thrF("𝕨⊏𝕩: Indexing out-of-bounds (%B∊𝕨, %s≡≠𝕩)", IGetU(w,0), *SH(x));
}
}
if (RNK(w) > 1) thrF("𝕨⊏𝕩: Compound 𝕨 must have rank at most 1 (%H ≡ ≢𝕨)", w);
SGetU(w)
bool depth1 = depth(w)==1;
for (ux i = 0; i < wia; i++) {
B wc = GetU(w,i);
if (depth1) {
if (isAtm(wc) && !isNum(wc)) thrF("𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained %S)", genericDesc(wc));
} else {
if (isAtm(wc)) thrF("𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and %S)", genericDesc(wc));
}
}
}
static NOINLINE NORETURN void select_depth2_bad_inds(B cw, ux axis, B x) {
assert(axis < RNK(x) && isArr(cw));
SGetU(cw)
usz ia = IA(cw);
ux len = SH(x)[axis];
for (ux i = 0; i < ia; i++) {
f64 c = o2fG(GetU(cw,i));
if (!q_fi64(c)) thrF("𝕨⊏𝕩: Bad index: %f along axis %z", c, axis);
WRAP(c, len, thrF("𝕨⊏𝕩: Indexing out-of-bounds along axis %z (%f ∊ %z⊑𝕨, %H≡≢𝕩)", axis, c, axis, x));
}
fatal("select_depth2_bad_inds should've errored");
}
B add_c2(B,B,B);
B mul_c2(B,B,B);
B lt_c2(B,B,B);
typedef struct {
B inds; // array (rank≤1) of elNum arrays
ux prod; // ×´⥊≠∘⥊¨inds
ux left; // (=x) - ≠𝕨
ux rank; // =w⊏x
bool lastMaybeRange; // whether ¯1⊑r may be an a+↕b
} Depth2Inds;
Depth2Inds select_depth2_parse_inds(B w, B x) { // consumes w; checks that w of w⊏x is valid, and, if so, returns a depth-2 array of number arrays (i.e. `squeeze_numTry¨ ((≠w)↑≢x) | w`)
assert(isArr(w) && isArr(x));
usz wia = IA(w);
assert(wia > 0);
if (RNK(w) > 1) { select_depth2_bad(w,x); fatal("should've errored"); }
SGetU(w)
if (wia > RNK(x)) { select_depth2_bad(w,x); thrF("𝕨⊏𝕩: Compound 𝕨 must not be longer than 𝕩 (%s ≡ ≠𝕨, %H ≡ ≢𝕩)", wia, x); }
Depth2Inds r;
HArr_p inds = m_harr0v(wia);
r.inds = inds.b;
r.prod = 1;
r.rank = r.left = RNK(x) - wia;
usz* xsh = SH(x);
i64 bounds[2];
ux lastIA;
for (ux i = 0; i < wia; i++) {
B c = GetU(w, i);
if (!isArr(c)) { select_depth2_bad(w,x); thrF("𝕨⊏𝕩: Elements of compound 𝕨 must be arrays (encountered %S)", genericDesc(c)); }
r.rank+= RNK(c);
u8 ce;
c = squeeze_numTry(incG(c), &ce, SQ_NUM);
lastIA = IA(c);
r.prod*= lastIA;
if (lastIA>0) {
if (!elNum(ce)) { select_depth2_bad(w,x); thrM("𝕨⊏𝕩: Elements of compound 𝕨 must be arrays of numbers"); }
if (!getRange_fns[ce](tyany_ptr(c), bounds, lastIA) || bounds[0] < -(i64)xsh[i] || bounds[1] >= xsh[i]) {
select_depth2_bad(w,x);
select_depth2_bad_inds(c, i, x);
}
if (bounds[0] < 0) {
c = C2(add, c, C2(mul, m_f64(xsh[i]), C2(lt, incG(c), m_f64(0))));
}
}
inds.a[i] = c;
}
decG(w);
if (r.rank > UR_MAX) thrM("𝕨⊏𝕩: Result rank too large");
r.lastMaybeRange = lastIA!=0 && (bounds[0]<0 || bounds[1]+1-bounds[0] == lastIA);
return r;
}
B tbl_c2(Md1D* d, B w, B x);
B mul_c2(B, B, B);
B ud_c1(B, B);
B shape_c1(B, B);
typedef struct {
B starts; // unspecified shape
ux span, mul, add;
} Spans;
Spans select_depth2_inds(B w, B x, bool lastMaybeRange) { // doesn't consume; assumes w is a result of select_depth2_parse_inds; (⥊w⊏x) ≡ ⥊((mul×⥊starts)+⌜add+↕span)⊏x
ur xr = RNK(x);
usz wia = IA(w);
assert(xr>0 && wia>=2 && wia<=xr);
usz* xsh = SH(x);
ux add = 0;
ux span = shProd(xsh, wia, xr);
ux mul = span;
if (MAY_T(lastMaybeRange) && wia>=2) {
B l = IGetU(w, wia-1);
usz lia = IA(l);
assert(lia!=0);
if (HEURISTIC(lia <= 3)) goto lastNotRange; // TODO improve heuristic
SGetU(l)
usz l0 = o2sG(GetU(l,0));
for (ux i = 1; i < lia; i++) if (o2sG(GetU(l,i)) != l0+i) goto lastNotRange; // TODO do in a less bad way
add = l0*mul;
span*= lia;
mul*= xsh[wia-1];
wia--;
}
lastNotRange:;
SGet(w)
B c = Get(w, 0);
for (ux i = 1; i < wia; i++) {
c = C2(mul, c, m_f64(xsh[i]));
c = M1C2(tbl, add, c, Get(w, i));
}
return (Spans) {c, span, mul, add};
}
#define WRAP_SELECT_ONE(VAL, LEN, FMT, ARG) WRAP(VAL, LEN, thrF("𝕨⊏𝕩: Indexing out-of-bounds (" FMT "∊𝕨, %s≡≠𝕩)", ARG, LEN))
static NOINLINE B select_depth2_select(Spans ws, B x) { // consumes ws.starts
B wst = ws.starts;
ux span = ws.span;
B r0;
if (span != 1) {
u8 xe = TI(x,elType);
ux sia = IA(wst);
UntaggedArr r = m_arrp_copyFill(x, sia*span);
SGetU(wst)
ux ro = 0;
if (xe != el_B) {
void* xp = tyany_ptr(x);
u8 ewb = elwBitLog(xe);
CFRes f = cf_get(span, 1<<ewb);
for (ux i = 0; i < sia; i++) {
ux xi = ws.add + ws.mul*o2sG(GetU(wst,i));
cf_call(f, r.data, ro, xp, xi*f.mul);
ro+= span*f.mul;
}
} else {
for (ux i = 0; i < sia; i++) {
ux xi = ws.add + ws.mul*o2sG(GetU(wst,i));
COPY_TO(r.data, xe, ro, x, xi, span);
ro+= span;
}
NOGC_E;
}
decG(wst);
r0 = taga(r.obj);
} else {
if (ws.mul != 1) wst = C2(mul, wst, m_f64(ws.mul));
// if (span != 1) wst = M1C2(tbl, add, wst, C1(ud, m_f64(span)));
if (ws.add != 0) wst = C2(add, wst, m_f64(ws.add));
r0 = C2(select, wst, C1(shape, incG(x)));
}
assert(reusable(r0));
return r0;
}
static B select_depth2_impl(ux wia, B w, B x) { // wia<=1 only if invalid; or if x is empty, w may also be a number list
Depth2Inds wi = select_depth2_parse_inds(w, x);
assert(IA(w)>=2); // invalid cases thrown out above
w = wi.inds;
ux rr = wi.rank;
B r0;
if (wi.prod==0) {
r0 = taga(emptyArr(x, rr));
} else {
assert(IA(x)!=0);
Spans ws = select_depth2_inds(w, x, wi.lastMaybeRange);
r0 = select_depth2_select(ws, x);
}
if (rr >= 2) {
ShArr* rsh = m_shArr(rr);
arr_shReplace(a(r0), rr, rsh);
usz* rshc = rsh->a;
SGetU(w)
for (ux i = 0; i < wia; i++) {
B wc = GetU(w, i);
ur wcr = RNK(wc);
shcpy(rshc, SH(wc), wcr);
rshc+= wcr;
}
shcpy(rshc, SH(x)+wia, wi.left);
assert(rshc+wi.left == rsh->a+rr);
} else {
arr_shErase(a(r0), rr); // may re-write the rank of bi_emptyHVec/bi_emptyIVec/bi_emptyCVec/bi_emptySVec. ¯\_(ツ)_/¯
}
decG(w); decG(x);
return r0;
}
B select_c2(B t, B w, B x) {
if (isAtm(x)) thrM("𝕨⊏𝕩: 𝕩 cannot be an atom");
ur xr = RNK(x);
@ -193,7 +406,7 @@ B select_c2(B t, B w, B x) {
usz wia = IA(w);
Arr* r;
ur wr = RNK(w);
i32 rr = xr+wr-1;
i32 rr = xr+wr-1; // only for depth-1 w
if (wia <= 1) {
if (wia == 0) {
emptyRes:
@ -236,14 +449,14 @@ B select_c2(B t, B w, B x) {
if (elNum(w0e)) return C2(select, w0, x);
w0 = squeeze_numTry(w0, &w0e, SQ_MSGREQ(SQ_NUM));
if (elNum(w0e)) return C2(select, w0, x);
w = m_vec1(w0);
w = m_vec1(w0); // erroneous, speed doesn't matter
}
goto base;
goto depth2;
}
B xf = getFillR(x);
usz xn = *SH(x);
if (xn==0) goto def_xf_base; // empty x, non-empty w; error
if (xn==0) goto error_dec_xf; // empty x, non-empty w; error
usz csz = arr_csz(x);
u8 xl = cellWidthLog(x);
usz ria = wia * csz;
@ -380,16 +593,15 @@ B select_c2(B t, B w, B x) {
w = squeeze_numTry(w, &we, SQ_MSGREQ(SQ_NUM));
if (RANDOMIZE_HEURISTICS && we==el_f64) goto generic_l; // avoid infinite loop
if (elNum(we)) goto retry;
goto def_xf_base;
goto error_dec_xf; // erroneous input
}
}
#undef CASE
#undef CASEW
def_xf_base:;
error_dec_xf:;
dec(xf);
base:;
return c2rt(select, w, x);
depth2: return select_depth2_impl(wia, w, x);
generic_l: {
if (xia==0) goto emptyRes;

View File

@ -38,7 +38,7 @@
!"𝕨/𝕩: Length of compound 𝕨 must be at most rank of 𝕩" % (<0)/˘(5)<"ab"
!"𝕨⊏𝕩: Indexing out-of-bounds (24∊𝕨, 4≡≠𝕩)" % 124144
!"𝕨⊏𝕩: Indexing out-of-bounds (4∊𝕨, 4≡≠𝕩)" % 1˜6424
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % 0@¯11 520.5
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained character)" % 0@¯11 520.5
!"Expected integer, got ¯5.25" % ¯5.25˘424
!"𝕨⊏𝕩: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % 001 ˘(˘) 10000×3
!"𝕨⊏𝕩: 𝕩 cannot be a unit" % 0˘5<"a"

View File

@ -165,19 +165,18 @@ w←1‿1⥊1 ⋄ x←2⥊1 ⋄ w‿x <¨↩ ⋄ {! (∾⟨"𝕨",•Repr𝕩,
)
000 1310 %% 33012
¨ (203451)98070 08070 (23041)10 %% 20345807,0807,2304
!"𝕨⊏𝕩: Indices out of range" % %USE evar 00 _evar 0
!"𝕨⊏𝕩: Indices out of range" % %USE evar 00 _evar 021
!"𝕨⊏𝕩: Indices out of range" % %USE evar [00,00] _evar 0
!"𝕨⊏𝕩: Indices out of range" % %USE evar [00,00] _evar 001
!"𝕨⊏𝕩: Indices out of range" % %USE evar 00 _evar 021
!"𝕨⊏𝕩: Indices out of range" % %USE evar 00 _evar 0
!"𝕨⊏𝕩: Indices out of range" % %USE evar 00,00 _evar 201
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 00 _evar 0
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 00 _evar 021
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar [00,00] _evar 0
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar [00,00] _evar 001
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 00 _evar 021
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 00 _evar 0
!"𝕨⊏𝕩: Indexing out-of-bounds along axis 1 (0 ∊ 1⊑𝕨, 2‿0≡≢𝕩)" % %USE evar 00,00 _evar 201
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 0 _evar 0
!"𝕨⊏𝕩: Indexing out-of-bounds (0∊𝕨, 0≡≠𝕩)" % %USE evar 0 _evar 0
!"𝕨⊏𝕩: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % ˜(2001)1
!"𝕨⊏𝕩: Indexing out-of-bounds (24∊𝕨, 4≡≠𝕩)" % %USE evar 124 _evar 44
!"𝕨⊏𝕩: Indexing out-of-bounds (¯24∊𝕨, 4≡≠𝕩)" % %USE evar 1¯24 _evar 44
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % %USE evar (1¯26@) _evar @5
!"𝕨⊏𝕩: Indexing out-of-bounds (¯26∊𝕨, 5≡≠𝕩)" % %USE evar ¯26_evar 5
!"Expected integer, got ¯26.5" % %USE evar ¯26.5_evar 5
!"𝕨⊏𝕩: Indexing out-of-bounds (¯26∊𝕨, 5≡≠𝕩)" % %USE evar 1¯26 _evar 5
@ -190,24 +189,65 @@ w←1‿1⥊1 ⋄ x←2⥊1 ⋄ w‿x <¨↩ ⋄ {! (∾⟨"𝕨",•Repr𝕩,
!"𝕨⊏𝕩: Indexing out-of-bounds (4000∊𝕨, 1001≡≠𝕩)" % %USE evar ( 1000×14201056) _evar 1001101
!"𝕨⊏𝕩: Indexing out-of-bounds (¯4000∊𝕨, 1001≡≠𝕩)" % %USE evar (¯1000×14201056) _evar 1001101
!"𝕨⊏𝕩: Indexing out-of-bounds (3∊𝕨, 2≡≠𝕩)" % %USE evar (4) _evar "ab"
!"Expected integer, got namespace" % %USE eqerr {}, <{} _eqerr 10, 1010100
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % %USE eqerr evar {%USE evar evar} {}, <<<4, 4, 1.5{} _evar _eqerr 10, 1010100
!"𝕨⊏𝕩: Compound 𝕨 must have rank at most 1" % %USE eqerr 5 _eqerr 10, 1010100
!"Expected integer, got namespace" % %USE eqerr {}, {} _eqerr 10, 1010100
%USE eqvar (4) _eqvar 10×10 %% 3020100
%USE eqvar (40) _eqvar 403020 %% 440
%USE eqvar 100 _eqvar "ab"(01) 2 %% "baa"
%USE eqvar (4) _eqvar "abcdefgh" %% "dcba"
(<3) "hello" %% "hel"
(<<4) "hello" %% <'o'
!"𝕨⊏𝕩: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % %USE eqerr evar {%USE evar evar} _evar´ _eqerr 01, 0 01, "?" 01, 01
a2 ! "e" (10){baaaaaaaaaa 𝕨"e"𝕩}12,34 ! 01 a
%USE eqvar {1¯1 {r𝕨𝕩 ! 𝕩 •internal.ElType r r}_eqvar 𝕩}¨ 2, 4, "hello", "ab", "cd", "ef", 4
!"𝕨⊏𝕩: 𝕩 cannot be a unit" % %USE eqerr 0, _eqerr <"a", <5, <{}
!"𝕨⊏𝕩: 𝕩 cannot be an atom" % %USE eqerr 0, _eqerr 5, {}
!"Expected integer, got 1.5" % 1.5 "ab""cd"
!"𝕨⊏𝕩: Indexing out-of-bounds (10∊𝕨, 2≡≠𝕩)" % 10 "ab""cd"
{𝕩 ! 20𝕩•rand.Range 2}¨ (70)(64×12345)+¯1013060
%USE eqvar {1¯1 {r𝕨𝕩 ! 𝕩 •internal.ElType r r}_eqvar 𝕩}¨ 2, 4, "hello", "ab", "cd", "ef", 4
%USE tvar !¨ {𝕨 {𝕊:•CurrentError@} _tvar 𝕩}´¨ 01, 0 01, "?" 01, 01
a2 ! "e" (10){baaaaaaaaaa 𝕨"e"𝕩}12,34 ! 01 a
!"Expected integer, got character" % %USE eqerr @, <@ _eqerr 10, 1010100
!"Expected integer, got namespace" % %USE eqerr {}, <{} _eqerr 10, 1010100
!"Expected integer, got namespace" % %USE eqerr {}, {} _eqerr 10, 1010100
%USE eqvar (4) _eqvar 10×10 %% 3020100
%USE eqvar (40) _eqvar 403020 %% 440
%USE eqvar 100 _eqvar "ab"(01) 2 %% "baa"
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained character)" % %USE evar 1,¯26,@ _evar 5
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and number)" % %USE evar 1,¯26,@ _evar 5
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and number)" % %USE eqerr evar {%USE evar evar} ( 1,<1) _evar _eqerr 1010100
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained function)" % %USE eqerr evar {%USE evar evar} 1.5{} _evar _eqerr 10, 1010100
!"𝕨⊏𝕩: Elements of compound 𝕨 must be arrays of numbers" % %USE eqerr evar {%USE evar evar} <<<4 _evar _eqerr 10, 1010100
!"𝕨⊏𝕩: Elements of compound 𝕨 must be arrays of numbers" % %USE eqerr evar {%USE evar evar} {} _evar _eqerr 10, 1010100
!"𝕨⊏𝕩: Elements of compound 𝕨 must be arrays of numbers" % %USE eqerr evar {%USE evar evar} 4 _evar _eqerr 10, 1010100
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained character)" % @,@,@ 331
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and number)" % 2,1 10102
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and number)" % 2,1,@ 331
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and character)" % 2,@,1 331
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such (𝕨 contained both an array and number)" % 99, 1 10102
!"𝕨⊏𝕩: Compound 𝕨 must have rank at most 1 (1‿1 ≡ ≢𝕨)" % %USE eqerr 5 _eqerr 10, 1010100
!"𝕨⊏𝕩: Compound 𝕨 must have rank at most 1 (2‿2 ≡ ≢𝕨)" % [1,2, 3,4] 10102
!"𝕨⊏𝕩: Compound 𝕨 must not be longer than 𝕩 (2 ≡ ≠𝕨, ⟨10⟩ ≡ ≢𝕩)" % , 10
!"𝕨⊏𝕩: Compound 𝕨 must not be longer than 𝕩 (2 ≡ ≠𝕨, ⟨10⟩ ≡ ≢𝕩)" % 2,2 10
!"𝕨⊏𝕩: Compound 𝕨 must not be longer than 𝕩 (2 ≡ ≠𝕨, ⟨4⟩ ≡ ≢𝕩)" % 2,2 4
!"𝕨⊏𝕩: Indexing out-of-bounds (4∊𝕨, 4≡≠𝕩)" % 4 41
!"𝕨⊏𝕩: Indexing out-of-bounds (¯5∊𝕨, 4≡≠𝕩)" % ¯5 41
!"𝕨⊏𝕩: Indexing out-of-bounds along axis 0 (4 ∊ 0⊑𝕨, 4‿5≡≢𝕩)" % 4,0 451
!"𝕨⊏𝕩: Indexing out-of-bounds along axis 1 (¯6 ∊ 1⊑𝕨, 4‿5≡≢𝕩)" % 0,¯6 451
!"𝕨⊏𝕩: Bad index: 1.5 along axis 0" % 1.5,¯6 451
1¯1, 2232¯3¯4 24324 %% 2223212223181920151617121314212223181920151617121314
224 %% 020
,224 %% 000
,"",<222312 %% 000
34101 236 %% (3433) + 34303
, 031, 4022 222343 %% 003402340
, 031, 4022, <0 112343 %% 00340240
23, 22412¯3, <2 57332999 %% 22232 336, 282, 300, 336, 462, 408, 426, 462 + 6
<0,<1,<0 232599 %% 1011121314
<0,<1,<0,432 232599 %% 141312
<1,<2,<0,<4 232599 %% <54
!"𝕨⊏𝕩: Indexing out-of-bounds along axis 3 (4 ∊ 3⊑𝕨, 2‿2‿2‿3‿4≡≢𝕩)" % , 031, 4022, <4, 222343
({(𝕩1)0}¨ 20055) 22 0 %% ( 2551)0
({(𝕩1)0}¨ 20054) 2240 %% (4˜2541)0
!"𝕨⊏𝕩: Result rank too large" % ({(𝕩1)0}¨ 20155) 220
!"𝕨⊏𝕩: Result rank too large" % ({(𝕩1)0}¨ 20154) 2240
%USE eqvar (4) _eqvar "abcdefgh" %% "dcba"
%USE eqvar 4+5, 2+4 _eqvar 1010100 %% 544243444552535455626364657273747582838485
%USE eqvar 4+5, 2+4 _eqvar 1010100 %% 544243444552535455626364657273747582838485
%USE eqvar 4+2, 2+5 _eqvar 10103300 %% 253126127128129130131132133134135136137138139140156157158159160161162163164165166167168169170
(<3) "hello" %% "hel"
(<<4) "hello" %% <'o'
# 𝕨⊑𝕩
!"𝕨⊑𝕩: 𝕨 contained a non-integer" % 0.13