diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/module.c | 16 | ||||
| -rw-r--r-- | core/module.h | 1 | ||||
| -rw-r--r-- | core/test-module.c | 28 |
3 files changed, 44 insertions, 1 deletions
diff --git a/core/module.c b/core/module.c index 71a0a25..052528c 100644 --- a/core/module.c +++ b/core/module.c @@ -130,7 +130,7 @@ static const struct { unsigned char pops, in[3], out; unsigned short where; unsi /* LOOP takes its low and high, two numbers or two i64s (the operands are its argument's). */ [PURE_OP_LOOP] = {0, {0}, 0, IN_HANDLER | IN_COMPUTE, A_LOOP, O_ANY}, [PURE_OP_BREAK] = {0, {0}, 0, IN_HANDLER | IN_COMPUTE, A_NONE, O_ANY}, - [PURE_OP_FLOOR] = NUMS(1), [PURE_OP_MOD] = NUMS(2), + [PURE_OP_FLOOR] = NUMS(1), [PURE_OP_MOD] = NUMS(2), [PURE_OP_FLOORDIV] = NUMS(2), [PURE_OP_I64_ADD] = I64S(2), [PURE_OP_I64_SUB] = I64S(2), [PURE_OP_I64_MUL] = I64S(2), [PURE_OP_I64_DIV] = I64S(2), [PURE_OP_I64_MOD] = I64S(2), [PURE_OP_I64_NEG] = I64S(1), [PURE_OP_I64_MIN] = I64S(2), [PURE_OP_I64_MAX] = I64S(2), [PURE_OP_I64_COMPARE] = {2, {T_I64, T_I64}, T_BOOL, READ, A_RELATION, O_ANY}, @@ -1526,6 +1526,16 @@ static uint32_t nesting_of(const PureModule *m) { return most; } +/* a // b for numbers as Python's float floor division: the quotient of a less its floored remainder, rounded to the + * nearest whole (it is one but for rounding), a zero with the sign of a / b (027's stage 5). b is not 0. */ +static double floor_divide(double a, double b) { + double mod = fmod(a, b), quotient = (a - mod) / b; + if (mod != 0 && (b < 0) != (mod < 0)) quotient -= 1.0; + if (quotient == 0) return copysign(0.0, a / b); + double whole = floor(quotient); + return quotient - whole > 0.5 ? whole + 1.0 : whole; +} + /* A name and its place among those of one namespace, in order of name and then of place. */ typedef struct { const char *name; size_t index; } Named; static int by_name(const void *a, const void *b) { @@ -4510,6 +4520,10 @@ static inline __attribute__((always_inline)) int step(Frame *frame, const PureOp if (value != 0 && (value < 0) != (b < 0)) value += b; else if (value == 0) value = copysign(0.0, b); break; + case PURE_OP_FLOORDIV: /* MOD's quotient, exactly (027's stage 5): a less its remainder, divided, as Python's // */ + if (b == 0) { kind = PURE_FAULT_DIVIDE; FAILED; } + value = floor_divide(a, b); + break; default: value = maximum(a, b); break; } if (!isfinite(value)) { kind = PURE_FAULT_NON_FINITE; FAILED; } diff --git a/core/module.h b/core/module.h index 8a84ddb..ce8cebf 100644 --- a/core/module.h +++ b/core/module.h @@ -47,6 +47,7 @@ typedef enum { PURE_OP_BYTES_SLICE, PURE_OP_BYTE, PURE_OP_BYTES_LOAD, PURE_OP_BYTES_STORE, PURE_OP_LIST_VALUE, PURE_OP_LIST_BIND, PURE_OP_APPEND_IN, PURE_OP_NUM_PARSE, PURE_OP_CALL, PURE_OP_RETURN, PURE_OP_CHAR_AT, PURE_OP_CHAR, + PURE_OP_FLOORDIV, PURE_OP_COUNT } PureOpcode; /* 027's 4c: an anchor is a place in a text or a list that follows its edits. A text's (a cursor) is a gap between diff --git a/core/test-module.c b/core/test-module.c index cb8e228..36722d2 100644 --- a/core/test-module.c +++ b/core/test-module.c @@ -6962,6 +6962,33 @@ static void timers(void) { CHECK(load(bad, &module_b) == PURE_INVALID && strstr(error, "view with an effect")); } +/* Floor division of numbers (027's stage 5): as Python's //, the quotient MOD's remainder leaves, exactly (1 // 0.1 is 9: + * 0.1 is a little more than a tenth), its zero signed as a / b; by zero it fails as divide. */ +static void floor_division(void) { + enum { FDIV = PURE_OP_FLOORDIV }; + static const S nums[] = {{"a", 0}, {"b", 0}, {"c", 0}, {"d", 0}, {"e", 0}, {"f", 0}}; + static const I inputs[] = {KEY("go", "KeyG"), KEY("zero", "KeyZ")}; + static const O code[] = { + {C, 0, 7}, {C, 0, 2}, {FDIV, 0, 0}, {ST, 0, 0}, {C, 0, -7}, {C, 0, 2}, {FDIV, 0, 0}, {ST, 1, 0}, + {C, 0, 7}, {C, 0, -2}, {FDIV, 0, 0}, {ST, 2, 0}, {C, 0, 1}, {C, 0, 0.1}, {FDIV, 0, 0}, {ST, 3, 0}, + {C, 0, 0}, {C, 0, -3}, {FDIV, 0, 0}, {ST, 4, 0}, {C, 0, 1e300}, {C, 0, 7}, {FDIV, 0, 0}, {ST, 5, 0}, + {C, 0, 1}, {C, 0, 0}, {FDIV, 0, 0}, {ST, 0, 0}, + }; + static const H handlers[] = {{1, 0, 24}, {3, 24, 4}}; + static const V none[] = {{"v", 0, 1}}; + Spec spec = SPEC(nums, inputs, none, handlers, code); + spec.nv = 0; + if (load(spec, &module_a) != PURE_OK) { fprintf(stderr, "floor division: %s\n", error); abort(); } + PureApp app; + CHECK(pure_app_start(&app, &module_a, (PureData){0}) == PURE_OK && press(&app, 0) == PURE_OK); + double huge = 1e300, quotient = (huge - fmod(huge, 7)) / 7; + CHECK(app.values[0].num == 3 && app.values[1].num == -4 && app.values[2].num == -4 && app.values[3].num == 9 && + app.values[4].num == 0 && signbit(app.values[4].num) && app.values[5].num == floor(quotient)); + CHECK(press(&app, 1) == PURE_INVALID && app.fault == PURE_FAULT_DIVIDE && app.values[0].num == 3); + pure_app_stop(&app); + printf("{\"floor_division\":6}\n"); +} + /* A number is written with the fewest digits that read back as it, the * digits %g gives (with its exponent's leading zeros dropped): the same * text as that search over precisions, for values of every kind. */ @@ -7312,6 +7339,7 @@ int main(void) { bytes_fields(); anchors(); list_views(); + floor_division(); memory_budget(); work_budget(); fold_mutations(); |
