X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a..HEAD:/math/mptext.c diff --git a/math/mptext.c b/math/mptext.c index 5d4640ef..a5c77db0 100644 --- a/math/mptext.c +++ b/math/mptext.c @@ -31,6 +31,8 @@ #include #include +#include + #include "mp.h" #include "mptext.h" #include "paranoia.h" @@ -60,7 +62,7 @@ #define DEPTH (CHAR_BIT * sizeof(size_t) + 10) -/*----- Main code ---------------------------------------------------------*/ +/*----- Input -------------------------------------------------------------*/ /* --- @mp_read@ --- * * @@ -96,112 +98,31 @@ * bizarre syntax. */ -mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p) +static int char_digit(int ch, int radix) { - int ch; /* Current char being considered */ - unsigned f = 0; /* Flags about the current number */ - int r; /* Radix to switch over to */ - mpw rd; /* Radix as an @mp@ digit */ - mp rr; /* The @mp@ for the radix */ - unsigned nf = m ? m->f & MP_BURN : 0; /* New @mp@ flags */ - - /* --- Stacks --- */ - - mp *pow[DEPTH]; /* List of powers */ - unsigned pows; /* Next index to fill */ - struct { unsigned i; mp *m; } s[DEPTH]; /* Main stack */ - unsigned sp; /* Current stack pointer */ - - /* --- Flags --- */ - -#define f_neg 1u -#define f_ok 2u -#define f_start 4u - - /* --- Initialize the stacks --- */ - - mp_build(&rr, &rd, &rd + 1); - pow[0] = &rr; - pows = 1; - - sp = 0; - - /* --- Initialize the destination number --- */ - - if (m) - MP_DROP(m); - - /* --- Read an initial character --- */ - - ch = ops->get(p); - if (radix >= 0) { - while (isspace(ch)) - ch = ops->get(p); - } - - /* --- Handle an initial sign --- */ - - if (radix >= 0 && (ch == '-' || ch == '+')) { - if (ch == '-') - f |= f_neg; - do ch = ops->get(p); while isspace(ch); - } - - /* --- If the radix is zero, look for leading zeros --- */ - - if (radix > 0) { - assert(((void)"ascii radix must be <= 62", radix <= 62)); - rd = radix; - r = -1; - } else if (radix < 0) { - rd = -radix; - assert(((void)"binary radix must fit in a byte", rd <= UCHAR_MAX)); - r = -1; - } else if (ch != '0') { - rd = 10; - r = 0; - } else { - ch = ops->get(p); - switch (ch) { - case 'x': - rd = 16; - goto prefix; - case 'o': - rd = 8; - goto prefix; - case 'b': - rd = 2; - goto prefix; - prefix: - ch = ops->get(p); - break; - default: - rd = 8; - f |= f_ok; - } - r = -1; - } - - /* --- Use fast algorithm for binary radix --- * - * - * This is the restart point after having parsed a radix number from the - * input. We check whether the radix is binary, and if so use a fast - * algorithm which just stacks the bits up in the right order. - */ + int r = radix < 0 ? -radix : radix; + int d; + + if (ch < 0) return (-1); + if (radix < 0) d = ch; + else if ('0' <= ch && ch <= '9') d = ch - '0'; + else if ('a' <= ch && ch <= 'z') d = ch - 'a' + 10; + else if ('A' <= ch && ch <= 'Z') d = ch - 'A' + (radix > 36 ? 36 : 10); + else return (-1); + if (d >= r) return (-1); + return (d); +} -restart: - switch (rd) { - unsigned bit; - - case 2: bit = 1; goto bin; - case 4: bit = 2; goto bin; - case 8: bit = 3; goto bin; - case 16: bit = 4; goto bin; - case 32: bit = 5; goto bin; - case 64: bit = 6; goto bin; - case 128: bit = 7; goto bin; - default: - break; +static mp *read_binary(int radix, unsigned bit, unsigned nf, + const mptext_ops *ops, void *p) +{ + mpw a = 0; + unsigned b = MPW_BITS; + int any = 0, nz = 0; + int ch, d; + size_t len, n; + mpw *v; + mp *m; /* --- The fast binary algorithm --- * * @@ -212,250 +133,299 @@ restart: * bit-shift when we know where the end of the number is. */ - bin: { - mpw a = 0; - unsigned b = MPW_BITS; - size_t len, n; - mpw *v; - - m = mp_dest(MP_NEW, 1, nf); - len = n = m->sz; - n = len; - v = m->v + n; - for (;; ch = ops->get(p)) { - unsigned x; + m = mp_dest(MP_NEW, 1, nf); + len = n = m->sz; + n = len; + v = m->v + n; - if (ch < 0) - break; + for (;;) { + ch = ops->get(p); + if ((d = char_digit(ch, radix)) < 0) break; - /* --- Check that the character is a digit and in range --- */ + /* --- Ignore leading zeroes, but notice that the number is valid --- */ - if (radix < 0) - x = ch % rd; - else { - if (!isalnum(ch)) - break; - if (ch >= '0' && ch <= '9') - x = ch - '0'; - else { - if (rd <= 36) - ch = tolower(ch); - if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */ - x = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'Z') - x = ch - 'A' + 36; - else - break; - } - } - if (x >= rd) - break; - - /* --- Feed the digit into the accumulator --- */ - - f |= f_ok; - if (!x && !(f & f_start)) - continue; - f |= f_start; - if (b > bit) { - b -= bit; - a |= MPW(x) << b; - } else { - a |= MPW(x) >> (bit - b); - b += MPW_BITS - bit; - *--v = MPW(a); - n--; - if (!n) { - n = len; - len <<= 1; - v = mpalloc(m->a, len); - memcpy(v + n, m->v, MPWS(n)); - mpfree(m->a, m->v); - m->v = v; - v = m->v + n; - } - a = (b < MPW_BITS) ? MPW(x) << b : 0; - } - } + any = 1; + if (!d && !nz) continue; + nz = 1; - /* --- Finish up --- */ + /* --- Feed the digit into the accumulator --- */ - if (!(f & f_ok)) { - mp_drop(m); - m = 0; + if (b > bit) { + b -= bit; + a |= MPW(d) << b; } else { - *--v = MPW(a); - n--; - m->sz = len; - m->vl = m->v + len; - m->f &= ~MP_UNDEF; - m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b); + a |= MPW(d) >> (bit - b); + b += MPW_BITS - bit; + *--v = MPW(a); n--; + if (!n) { + n = len; len <<= 1; + v = mpalloc(m->a, len); + memcpy(v + n, m->v, MPWS(n)); + mpfree(m->a, m->v); + m->v = v; v = m->v + n; + } + a = (b < MPW_BITS) ? MPW(d) << b : 0; } - ops->unget(ch, p); - goto done; - }} + } - /* --- Time to start --- */ + /* --- Finish up --- */ - for (;; ch = ops->get(p)) { - unsigned x; + ops->unget(ch, p); + if (!any) { mp_drop(m); return (0); } - if (ch < 0) - break; + *--v = MPW(a); n--; + m->sz = len; + m->vl = m->v + len; + m->f &= ~MP_UNDEF; + m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b); - /* --- An underscore indicates a numbered base --- */ + return (m); +} - if (ch == '_' && r > 0 && r <= 62) { - unsigned i; +struct readstate { - /* --- Clear out the stacks --- */ + /* --- State for the general-base reader --- * + * + * There are two arrays. The @pow@ array is set so that @pow[i]@ contains + * %$R^{2^i}$% for @i < pows@. The stack @s@ contains partial results: + * each entry contains a value @m@ corresponding to %$2^i$% digits. + * Inductively, an empty stack represents zero; if a stack represents %$x$% + * then pushing a new entry on the top causes the stack to represent + * %$R^{2^i} x + m$%. + * + * It is an invariant that each entry has a strictly smaller @i@ than the + * items beneath it. This is achieved by coaslescing entries at the top if + * they have equal %$i$% values: if the top items are %$(m, i)$%, and + * %$(M', i)$%, and the rest of the stack represents the integer %$x$%, + * then %$R^{2^i} (R^{2^i} x + M) + m = R^{2^{i+1}} x + (R^{2^i} M + m)$%, + * so we replace the top two items by %$((R^{2^i} M + m), i + 1)$%, and + * repeat if necessary. + */ - for (i = 1; i < pows; i++) - MP_DROP(pow[i]); - pows = 1; - for (i = 0; i < sp; i++) - MP_DROP(s[i].m); - sp = 0; + unsigned pows, sp; + struct { unsigned i; mp *m; } s[DEPTH]; + mp *pow[DEPTH]; +}; - /* --- Restart the search --- */ +static void ensure_power(struct readstate *rs) +{ + /* --- Make sure we have the necessary %$R^{2^i}$% computed --- */ - rd = r; - r = -1; - f &= ~f_ok; - ch = ops->get(p); - goto restart; - } + if (rs->s[rs->sp].i >= rs->pows) { + assert(rs->pows < DEPTH); + rs->pow[rs->pows] = mp_sqr(MP_NEW, rs->pow[rs->pows - 1]); + rs->pows++; + } +} - /* --- Check that the character is a digit and in range --- */ +static void read_digit(struct readstate *rs, unsigned nf, int d) +{ + mp *m = mp_new(1, nf); + m->v[0] = d; - if (radix < 0) - x = ch % rd; - else { - if (!isalnum(ch)) - break; - if (ch >= '0' && ch <= '9') - x = ch - '0'; - else { - if (rd <= 36) - ch = tolower(ch); - if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */ - x = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'Z') - x = ch - 'A' + 36; - else - break; - } - } + /* --- Put the new digit on top --- */ - /* --- Sort out what to do with the character --- */ + assert(rs->sp < DEPTH); + rs->s[rs->sp].m = m; + rs->s[rs->sp].i = 0; - if (x >= 10 && r >= 0) - r = -1; - if (x >= rd) - break; + /* --- Restore the stack invariant --- */ - if (r >= 0) - r = r * 10 + x; + while (rs->sp && rs->s[rs->sp - 1].i <= rs->s[rs->sp].i) { + assert(rs->sp > 0); + ensure_power(rs); + rs->sp--; - /* --- Stick the character on the end of my integer --- */ + m = rs->s[rs->sp].m; + m = mp_mul(m, m, rs->pow[rs->s[rs->sp + 1].i]); + m = mp_add(m, m, rs->s[rs->sp + 1].m); + MP_DROP(rs->s[rs->sp + 1].m); + rs->s[rs->sp].m = m; + rs->s[rs->sp].i++; + } - assert(((void)"Number is too unimaginably huge", sp < DEPTH)); - s[sp].m = m = mp_new(1, nf); - m->v[0] = x; - s[sp].i = 0; + /* --- Leave the stack pointer at an empty item --- */ - /* --- Now grind through the stack --- */ + rs->sp++; +} - while (sp > 0 && s[sp - 1].i == s[sp].i) { +static mp *read_general(int radix, unsigned t, unsigned nf, + const mptext_ops *ops, void *p) +{ + struct readstate rs; + unsigned char v[4]; + unsigned i; + mpw r; + int any = 0; + int ch, d; + mp rr; + mp *m, *z, *n; + + /* --- Prepare the stack --- */ + + r = radix < 0 ? -radix : radix; + mp_build(&rr, &r, &r + 1); + rs.pow[0] = &rr; + rs.pows = 1; + rs.sp = 0; + + /* --- If we've partially parsed some input then feed it in --- * + * + * Unfortunately, what we've got is backwards. Fortunately there's a + * fairly tight upper bound on how many digits @t@ might be, since we + * aborted that loop once it got too large. + */ - /* --- Combine the top two items --- */ + if (t) { + i = 0; + while (t) { assert(i < sizeof(v)); v[i++] = t%r; t /= r; } + while (i) read_digit(&rs, nf, v[--i]); + any = 1; + } - sp--; - m = s[sp].m; - m = mp_mul(m, m, pow[s[sp].i]); - m = mp_add(m, m, s[sp + 1].m); - s[sp].m = m; - MP_DROP(s[sp + 1].m); - s[sp].i++; + /* --- Read more stuff --- */ - /* --- Make a new radix power if necessary --- */ + for (;;) { + ch = ops->get(p); + if ((d = char_digit(ch, radix)) < 0) break; + read_digit(&rs, nf, d); any = 1; + } + ops->unget(ch, p); - if (s[sp].i >= pows) { - assert(((void)"Number is too unimaginably huge", pows < DEPTH)); - pow[pows] = mp_sqr(MP_NEW, pow[pows - 1]); - pows++; - } - } - f |= f_ok; - sp++; + /* --- Stitch all of the numbers together --- * + * + * This is not the same code as @read_digit@. In particular, here we must + * cope with the partial result being some inconvenient power of %$R$%, + * rather than %$R^{2^i}$%. + */ + + if (!any) return (0); + m = MP_ZERO; z = MP_ONE; + while (rs.sp) { + rs.sp--; + ensure_power(&rs); + n = rs.s[rs.sp].m; + n = mp_mul(n, n, z); + m = mp_add(m, m, n); + z = mp_mul(z, z, rs.pow[rs.s[rs.sp].i]); + MP_DROP(n); } + for (i = 0; i < rs.pows; i++) MP_DROP(rs.pow[i]); + MP_DROP(z); + return (m); +} - ops->unget(ch, p); +mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p) +{ + unsigned t = 0; + unsigned nf = 0; + int ch, d, rd; + + unsigned f = 0; +#define f_neg 1u +#define f_ok 2u + + /* --- We don't actually need a destination so throw it away --- * + * + * But note the flags before we lose it entirely. + */ - /* --- If we're done, compute the rest of the number --- */ + if (m) { + nf = m->f & MP_BURN; + MP_DROP(m); + } - if (f & f_ok) { - if (!sp) - return (MP_ZERO); - else { - mp *z = MP_ONE; - sp--; + /* --- Maintain a lookahead character --- */ - while (sp > 0) { + ch = ops->get(p); - /* --- Combine the top two items --- */ + /* --- If we're reading text, skip leading space, and maybe a sign --- */ - sp--; - m = s[sp].m; - z = mp_mul(z, z, pow[s[sp + 1].i]); - m = mp_mul(m, m, z); - m = mp_add(m, m, s[sp + 1].m); - s[sp].m = m; - MP_DROP(s[sp + 1].m); + if (radix >= 0) { + while (ISSPACE(ch)) ch = ops->get(p); + switch (ch) { + case '-': f |= f_neg; /* and on */ + case '+': do ch = ops->get(p); while (ISSPACE(ch)); + } + } - /* --- Make a new radix power if necessary --- */ + /* --- If we don't have a fixed radix, then parse one from the input --- * + * + * This is moderately easy if the input starts with `0x' or similar. If it + * starts with `0' and something else, then it might be octal, or just a + * plain old zero. Finally, it might start with a leading `NN_', in which + * case we carefully collect the decimal number until we're sure it's + * either a radix prefix (in which case we accept it and start over) or it + * isn't (in which case it's actually the start of a large number we need + * to read). + */ - if (s[sp].i >= pows) { - assert(((void)"Number is too unimaginably huge", pows < DEPTH)); - pow[pows] = mp_sqr(MP_NEW, pow[pows - 1]); - pows++; - } + if (radix == 0) { + if (ch == '0') { + ch = ops->get(p); + switch (ch) { + case 'x': case 'X': radix = 16; goto fetch; + case 'o': case 'O': radix = 8; goto fetch; + case 'b': case 'B': radix = 2; goto fetch; + fetch: ch = ops->get(p); break; + default: radix = 8; f |= f_ok; break; + } + } else { + if ((d = char_digit(ch, 10)) < 0) { ops->unget(ch, p); return (0); } + for (;;) { + t = 10*t + d; + ch = ops->get(p); + if (t > 52) break; + if ((d = char_digit(ch, 10)) < 0) break; + } + if (ch != '_' || t > 52) radix = 10; + else { + radix = t; t = 0; + ch = ops->get(p); } - MP_DROP(z); - m = s[0].m; } - } else { - unsigned i; - for (i = 0; i < sp; i++) - MP_DROP(s[i].m); } - /* --- Clear the radix power list --- */ + /* --- We're now ready to dispatch to the correct handler --- */ - { - unsigned i; - for (i = 1; i < pows; i++) - MP_DROP(pow[i]); + rd = radix < 0 ? -radix : radix; + ops->unget(ch, p); + switch (rd) { + case 2: m = read_binary(radix, 1, nf, ops, p); break; + case 4: m = read_binary(radix, 2, nf, ops, p); break; + case 8: m = read_binary(radix, 3, nf, ops, p); break; + case 16: m = read_binary(radix, 4, nf, ops, p); break; + case 32: m = read_binary(radix, 5, nf, ops, p); break; + case 64: m = read_binary(radix, 6, nf, ops, p); break; + case 128: m = read_binary(radix, 7, nf, ops, p); break; + default: m = read_general(radix, t, nf, ops, p); break; } - /* --- Bail out if the number was bad --- */ + /* --- That didn't work --- * + * + * If we've already read something then return that. Otherwise it's an + * error. + */ -done: - if (!(f & f_ok)) - return (0); + if (!m) { + if (f & f_ok) return (MP_ZERO); + else return (0); + } - /* --- Set the sign and return --- */ + /* --- Negate the result if we should do that --- */ + + if (f & f_neg) m = mp_neg(m, m); + + /* --- And we're all done --- */ - if (f & f_neg) - m->f |= MP_NEG; - MP_SHRINK(m); return (m); -#undef f_start #undef f_neg #undef f_ok } +/*----- Output ------------------------------------------------------------*/ + /* --- @mp_write@ --- * * * Arguments: @mp *m@ = pointer to a multi-precision integer @@ -468,6 +438,14 @@ done: * Use: Writes a large integer in textual form. */ +static int digit_char(int d, int radix) +{ + if (radix < 0) return (d); + else if (d < 10) return (d + '0'); + else if (d < 26) return (d - 10 + 'a'); + else return (d - 36 + 'A'); +} + /* --- Simple case --- * * * Use a fixed-sized buffer and single-precision arithmetic to pick off @@ -477,35 +455,23 @@ done: * enough real digits. */ -static int simple(mpw n, int radix, unsigned z, - const mptext_ops *ops, void *p) +static int write_simple(mpw n, int radix, unsigned z, + const mptext_ops *ops, void *p) { int rc = 0; char buf[64]; unsigned i = sizeof(buf); int rd = radix > 0 ? radix : -radix; + mpw x; do { - int ch; - mpw x; - - x = n % rd; - n /= rd; - if (radix < 0) - ch = x; - else if (x < 10) - ch = '0' + x; - else if (x < 36) /* Ascii specific */ - ch = 'a' + x - 10; - else - ch = 'A' + x - 36; - buf[--i] = ch; - if (z) - z--; + x = n % rd; n /= rd; + buf[--i] = digit_char(x, radix); + if (z) z--; } while (i && n); if (n) - rc = simple(n, radix, z, ops, p); + rc = write_simple(n, radix, z, ops, p); else { char zbuf[32]; memset(zbuf, (radix < 0) ? 0 : '0', sizeof(zbuf)); @@ -513,11 +479,9 @@ static int simple(mpw n, int radix, unsigned z, rc = ops->put(zbuf, sizeof(zbuf), p); z -= sizeof(zbuf); } - if (!rc && z) - rc = ops->put(zbuf, z, p); + if (!rc && z) rc = ops->put(zbuf, z, p); } - if (!rc) - rc = ops->put(buf + i, sizeof(buf) - i, p); + if (!rc) rc = ops->put(buf + i, sizeof(buf) - i, p); BURN(buf); return (rc); } @@ -530,29 +494,26 @@ static int simple(mpw n, int radix, unsigned z, * leading zeroes on the remainder part, because they're deeply significant. */ -static int complicated(mp *m, int radix, mp **pr, unsigned i, unsigned z, - const mptext_ops *ops, void *p) +static int write_complicated(mp *m, int radix, mp **pr, + unsigned i, unsigned z, + const mptext_ops *ops, void *p) { int rc = 0; mp *q = MP_NEW; unsigned d = 1 << i; if (MP_LEN(m) < 2) - return (simple(MP_LEN(m) ? m->v[0] : 0, radix, z, ops, p)); + return (write_simple(MP_LEN(m) ? m->v[0] : 0, radix, z, ops, p)); assert(i); mp_div(&q, &m, m, pr[i]); - if (MP_ZEROP(q)) - d = z; + if (MP_ZEROP(q)) d = z; else { - if (z > d) - z -= d; - else - z = 0; - rc = complicated(q, radix, pr, i - 1, z, ops, p); + if (z > d) z -= d; + else z = 0; + rc = write_complicated(q, radix, pr, i - 1, z, ops, p); } - if (!rc) - rc = complicated(m, radix, pr, i - 1, d, ops, p); + if (!rc) rc = write_complicated(m, radix, pr, i - 1, d, ops, p); mp_drop(q); return (rc); } @@ -562,7 +523,8 @@ static int complicated(mp *m, int radix, mp **pr, unsigned i, unsigned z, * Special case for binary output. Goes much faster. */ -static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) +static int write_binary(mp *m, int bit, int radix, + const mptext_ops *ops, void *p) { mpw *v; mpw a; @@ -573,15 +535,13 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) unsigned f = 0; char buf[8], *q; unsigned x; - int ch; #define f_out 1u /* --- Work out where to start --- */ n = mp_bits(m); - if (n % bit) - n += bit - (n % bit); + if (n % bit) n += bit - (n % bit); b = n % MPW_BITS; n /= MPW_BITS; @@ -604,43 +564,23 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) } else { x = a << (bit - b); b += MPW_BITS - bit; - if (v == m->v) - break; + if (v == m->v) break; a = *--v; - if (b < MPW_BITS) - x |= a >> b; + if (b < MPW_BITS) x |= a >> b; } x &= mask; - if (!x && !(f & f_out)) - continue; - - if (radix < 0) - ch = x; - else if (x < 10) - ch = '0' + x; - else if (x < 36) - ch = 'a' + x - 10; /* Ascii specific */ - else - ch = 'A' + x - 36; - *q++ = ch; + if (!x && !(f & f_out)) continue; + + *q++ = digit_char(x, radix); if (q >= buf + sizeof(buf)) { - if ((rc = ops->put(buf, sizeof(buf), p)) != 0) - goto done; + if ((rc = ops->put(buf, sizeof(buf), p)) != 0) goto done; q = buf; } f |= f_out; } x &= mask; - if (radix < 0) - ch = x; - else if (x < 10) - ch = '0' + x; - else if (x < 36) - ch = 'a' + x - 10; /* Ascii specific */ - else - ch = 'A' + x - 36; - *q++ = ch; + *q++ = digit_char(x, radix); rc = ops->put(buf, q - buf, p); done: @@ -655,6 +595,10 @@ done: int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) { int rc; + mp *pr[DEPTH]; + size_t target; + unsigned i = 0; + mp *z; if (MP_EQ(m, MP_ZERO)) return (ops->put(radix > 0 ? "0" : "\0", 1, p)); @@ -677,27 +621,26 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) if (MP_NEGP(m)) { assert(radix > 0); - if (ops->put("-", 1, p)) - return (EOF); + if (ops->put("-", 1, p)) return (EOF); m->f &= ~MP_NEG; } /* --- Handle binary radix --- */ switch (radix) { - case 2: case -2: return (binary(m, 1, radix, ops, p)); - case 4: case -4: return (binary(m, 2, radix, ops, p)); - case 8: case -8: return (binary(m, 3, radix, ops, p)); - case 16: case -16: return (binary(m, 4, radix, ops, p)); - case 32: case -32: return (binary(m, 5, radix, ops, p)); - case -64: return (binary(m, 6, radix, ops, p)); - case -128: return (binary(m, 7, radix, ops, p)); + case 2: case -2: return (write_binary(m, 1, radix, ops, p)); + case 4: case -4: return (write_binary(m, 2, radix, ops, p)); + case 8: case -8: return (write_binary(m, 3, radix, ops, p)); + case 16: case -16: return (write_binary(m, 4, radix, ops, p)); + case 32: case -32: return (write_binary(m, 5, radix, ops, p)); + case -64: return (write_binary(m, 6, radix, ops, p)); + case -128: return (write_binary(m, 7, radix, ops, p)); } /* --- If the number is small, do it the easy way --- */ if (MP_LEN(m) < 2) - rc = simple(MP_LEN(m) ? m->v[0] : 0, radix, 0, ops, p); + rc = write_simple(MP_LEN(m) ? m->v[0] : 0, radix, 0, ops, p); /* --- Use a clever algorithm --- * * @@ -709,10 +652,8 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) */ else { - mp *pr[DEPTH]; - size_t target = (MP_LEN(m) + 1) / 2; - unsigned i = 0; - mp *z = mp_new(1, 0); + target = (MP_LEN(m) + 1) / 2; + z = mp_new(1, 0); /* --- Set up the exponent table --- */ @@ -721,19 +662,17 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) for (;;) { assert(((void)"Number is too unimaginably huge", i < DEPTH)); pr[i++] = z; - if (MP_LEN(z) > target) - break; + if (MP_LEN(z) > target) break; z = mp_sqr(MP_NEW, z); } /* --- Write out the answer --- */ - rc = complicated(m, radix, pr, i - 1, 0, ops, p); + rc = write_complicated(m, radix, pr, i - 1, 0, ops, p); /* --- Tidy away the array --- */ - while (i > 0) - mp_drop(pr[--i]); + while (i > 0) mp_drop(pr[--i]); } /* --- Tidying up code --- */ @@ -768,7 +707,7 @@ static int verify(dstr *v) ok = 0; } else { mp_writedstr(m, &d, ob); - if (d.len != v[3].len || memcmp(d.buf, v[3].buf, d.len) != 0) { + if (d.len != v[3].len || MEMCMP(d.buf, !=, v[3].buf, d.len)) { fprintf(stderr, "*** failed read or write\n" "*** input [%2i] = ", ib); if (ib < 0) @@ -809,7 +748,7 @@ static int verify(dstr *v) } if (v[1].len - off != v[4].len || - memcmp(v[1].buf + off, v[4].buf, v[4].len) != 0) { + MEMCMP(v[1].buf + off, !=, v[4].buf, v[4].len)) { fprintf(stderr, "*** leftovers incorrect\n" "*** input [%2i] = ", ib); if (ib < 0)