docs(adr): ADR 005 sets K = 8 on the user's second answer to question 16 (improvise-l2b8)
Revision 8. "Ok, let's drop K back to 8" supersedes "let's do k = 32". Figures re-derived from the appendix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
76fc5a19ff
commit
e258599d1c
@@ -1,7 +1,7 @@
|
||||
# ADR 005 — Exact decimal arithmetic: a three-level numeric tower for formulas
|
||||
|
||||
**Status:** proposed. Only the user accepts an ADR. All sixteen numbered questions are
|
||||
answered (question 16 in revision 7); the ADR waits for the user's "Approved". ·
|
||||
answered (question 16 last, in revision 8, K = 8); the ADR waits for the user's "Approved". ·
|
||||
**Ticket:** improvise-l2b8 (parent improvise-felo) ·
|
||||
**Direction from:** the user, 2026-09-22 (below) ·
|
||||
**Relates to:** ADR 009 (incremental evaluation, improvise-felo.4, PR #309), which now
|
||||
@@ -72,16 +72,26 @@ for question 15. It answers the review of `33833f28` (issuecomment-5836990563):
|
||||
It also corrects when a last-bit miss is visible to `=`. The bound is on the **terms**,
|
||||
not the total, as ADR 009 now says at `4973845f` (Codex on #309).
|
||||
|
||||
**Revision 7** folds in **the user's answer to question 16**, left inline on `b232c5a9`
|
||||
at 03:37 UTC on 2026-10-09: "let's do k = 32". K is **32**, which is option (a) and not
|
||||
the recommendation (b), K = 8. Every question 1–16 is now answered, and the ADR stays
|
||||
**Revision 7** folded in **the user's first answer to question 16**, left inline on
|
||||
`b232c5a9` at 03:37 UTC on 2026-10-09: "let's do k = 32". It made K **32**, option (a).
|
||||
**Revision 8 supersedes that answer** (below). Every question 1–16 was then answered, and the ADR stayed
|
||||
**proposed** until the user says "Approved". The change is confined to the value of K
|
||||
and the text that waited on it; the figures that depend on K were re-derived from the
|
||||
appendix's own measurements and none is new (question 16's "Re-derived under K = 32"
|
||||
note lists them). The revision also adds "Relations to other ADRs", a note on what ADRs
|
||||
appendix's own measurements and none is new (question 16's "Re-derived" notes list them, now for K = 8). The revision also adds "Relations to other ADRs", a note on what ADRs
|
||||
007, 008 and 009 ask of this one since it was written. It changes none of the user's
|
||||
decisions, and it lists the places where the other ADRs' text and this one's disagree.
|
||||
|
||||
**Revision 8** folds in **the user's second answer to question 16**, a PR-conversation
|
||||
comment at 04:04 UTC on 2026-10-09: "Ok, let's drop K back to 8". It **supersedes** "let's
|
||||
do k = 32": K is **8**, option (b), which was the recommendation of question 16. The
|
||||
earlier answer stays on the record, quoted in "What the user decided". The comment came
|
||||
about a minute after revision 7's relations note put the `Eager` exposure of K = 32 on
|
||||
the PR (`76fc5a19`, committed 04:03:29Z); the comment gives no reason, and the ADR does
|
||||
not supply one. Every dependent figure was re-derived from the appendix's own
|
||||
measurements (question 16 lists them), and none is new. The K = 8 cutoff is still the
|
||||
second exception to "exact iff it fits" (question 13), and still overrides
|
||||
representability.
|
||||
|
||||
## What the user decided
|
||||
|
||||
The user answered inline on `e4acf643`, one comment per question. Each answer is quoted
|
||||
@@ -178,7 +188,7 @@ stored bound. One figure changed after the answer, and it is flagged here: the e
|
||||
read was an estimate of 16–34 µs at K = 32, and it measures **0.67–1.9 ms** in the worst
|
||||
case (option (d), "What that costs"). K is a constant inside `numtower`, not a format
|
||||
or wire fact, so its value was split out as question 16 rather than reopening this one.
|
||||
The user then decided K = 32 there.
|
||||
The user decided K = 8 there (first K = 32, then K = 8; the later answer governs).
|
||||
|
||||
**11. The `MIN`/`MAX` tie-break.**
|
||||
> "Yeah, exact."
|
||||
@@ -200,8 +210,8 @@ Clause 12 defines the one number language this uses.
|
||||
Decided: **(b)**. The bound applies to the **stored** result, and every intermediate
|
||||
inside one formula evaluation is unbounded up to the ceiling. The ceiling is the first
|
||||
of two exceptions to "exact iff it fits", sized to the grouped read (question 13). The
|
||||
second, added by revision 7, is the K = 32 cutoff on a `SUM` (question 13, "The K
|
||||
cutoff").
|
||||
second, added by revision 7, is the K cutoff on a `SUM`, K = 8 since revision 8
|
||||
(question 13, "The K cutoff").
|
||||
|
||||
**14. The numeric crate's name.**
|
||||
> "this is fine"
|
||||
@@ -215,19 +225,24 @@ Decided: **(a)**, in `numtower`, beside the exact decimal accumulator. ADR 009's
|
||||
crate adapts it to `zset`'s group trait through a newtype, and `numtower` can land
|
||||
holding `ExactSum` alone, ahead of this ADR (clause 14).
|
||||
|
||||
**16. The value of K.**
|
||||
**16. The value of K.** The user answered twice. Both are quoted verbatim.
|
||||
|
||||
First, inline on `b232c5a9`, on question 16's options (2026-10-09T03:37:34Z, comment
|
||||
4226381911):
|
||||
> "let's do k = 32"
|
||||
|
||||
(Left on `b232c5a9`, on question 16's options, 2026-10-09T03:37:34Z; comment
|
||||
4226381911.)
|
||||
Then, in a PR-conversation comment (2026-10-09T04:04:36Z, comment 6074029223):
|
||||
> "Ok, let's drop K back to 8"
|
||||
|
||||
Decided: **(a), K = 32.** This is the value revision 5 proposed and question 10 was
|
||||
answered with, and it is **not** the recommendation of question 16, which was K = 8.
|
||||
The worst-case exact read stays at **0.67–1.9 ms**, the measured figure the question put
|
||||
to the user (0.67 ms is the lcm method, the one `numtower` uses; 1.9 ms reduces after
|
||||
every add). The ceiling stays at 8,192 bits, which already covers K = 32 (4,320 bits
|
||||
needed). K remains a constant inside `numtower`, so it can still be tuned later against
|
||||
the evaluator benchmark without a new ADR.
|
||||
Decided: **(b), K = 8.** The later answer governs, and the first is superseded, not
|
||||
deleted. K = 8 is the recommendation of question 16, and not the value revision 5
|
||||
proposed and question 10 was answered with. The worst-case exact read is **52–127 µs**
|
||||
(52 µs is the lcm method, the one `numtower` uses; 127 µs reduces after every add). The
|
||||
combined numerator is at most K·127 + 256 = 1,272 bits, which the 8,192-bit ceiling
|
||||
clears by 6,920. A `SUM` over more than 8 distinct non-decimal denominators is
|
||||
inexact, and the cutoff overrides representability (question 13). K remains a constant
|
||||
inside `numtower`, so it can still be tuned later against the evaluator benchmark
|
||||
without a new ADR.
|
||||
|
||||
## The decision this ADR writes down
|
||||
|
||||
@@ -841,7 +856,7 @@ further to `inf` only at the inexact level.
|
||||
- **The result is exact if every value was exact** and the exact total fits the stored
|
||||
bound: a `Decimal`, or, under option (d), an `i128` fraction (a sum of fractions can
|
||||
fit the fraction arm without fitting a `Decimal`). **A second condition applies to
|
||||
fractions:** if the sum holds more than K = 32 non-decimal denominator groups it reads
|
||||
fractions:** if the sum holds more than K = 8 non-decimal denominator groups it reads
|
||||
the inexact f64 accumulator, so it is inexact **even when its exact total would have
|
||||
fitted** (clause 8's recommendation below, question 16). Otherwise it is inexact. **It must not be a fold with contagion part-way through.**
|
||||
Such a fold switches to f64 at the first inexact value in store order, so the answer
|
||||
@@ -908,9 +923,10 @@ each group is an integer:
|
||||
- a group's numerator is at most `i128` × an `i64` weight × 2⁶⁴ terms, so **256 bits**
|
||||
per group;
|
||||
- the only unbounded step is the **read**, which combines the groups over their lcm;
|
||||
- with at most K = 32 groups that lcm is at most about 4,100 bits, or 2,030 at K = 16,
|
||||
and the combined numerator at most K·127 + 256 ≈ 4,320 bits (measured: 3,924 and
|
||||
4,053 bits for 32 random 126-bit denominators and 250-bit numerators).
|
||||
- with at most K = 8 groups that lcm is at most about 1,016 bits (K·127), or 2,030 at
|
||||
K = 16 and 4,100 at K = 32, and the combined numerator at most K·127 + 256 ≈ 1,272
|
||||
bits at K = 8 (measured lcm: 988 bits for 8 random 126-bit denominators; 1,957 at 16
|
||||
and 3,924 at 32; the combined numerator was measured only at K = 32, 4,053 bits).
|
||||
|
||||
Under question 13 (b) that read runs in a bigint rational (`num-bigint`), so it needs no
|
||||
fixed register at all. Its result is then held to the stored bound: it is exact if it
|
||||
@@ -1395,7 +1411,7 @@ integer and reads in O(1). The review proposed a mitigation, and it is adopted:
|
||||
accumulator alone, and is converted to f64 **once, at an f64 read** (only when there
|
||||
are more than K non-decimal groups). So a pure-decimal `SUM` pays nothing for (d).
|
||||
- **Read exactly only when the current number of non-decimal groups is at most
|
||||
K = 32** (decided, question 16). Otherwise read the f64 accumulator, and the result is inexact. The count is
|
||||
K = 8** (decided, question 16; revision 8). Otherwise read the f64 accumulator, and the result is inexact. The count is
|
||||
a function of the current state, not of history, so the choice is independent of
|
||||
order.
|
||||
|
||||
@@ -1427,7 +1443,7 @@ integer and reads in O(1). The review proposed a mitigation, and it is adopted:
|
||||
should do that.
|
||||
- Denominators a person produces (`/ 3`, `/ 12`, a percentage) are small, and the read
|
||||
is then far cheaper. The table is the bound, not the common case. The value of K is
|
||||
32, decided in question 16.
|
||||
8, decided in question 16.
|
||||
- **f64 read:** ADR 009's 0.6–1.1 µs.
|
||||
- **Memory is still O(distinct denominators)**, because the map must survive
|
||||
retraction to know when the count falls back under K. For a 90k-record margin sum
|
||||
@@ -1438,11 +1454,10 @@ integer and reads in O(1). The review proposed a mitigation, and it is adopted:
|
||||
This keeps (d)'s wins, because `SUM(v / 3)`, averages and percentages have one or a
|
||||
handful of denominators, and it bounds the rest. The sum of margins reads the f64
|
||||
accumulator and is inexact, as under (a). Its exact combination would overflow by the
|
||||
6th term anyway (below). The 32 was a judgement: large enough for a `/ N` over a few
|
||||
different Ns, and small enough to bound the read. It was not tuned. The read's measured
|
||||
cost above is why question 16 recommended a smaller one (K = 8), and the user chose 32
|
||||
anyway, so 0.67–1.9 ms is the accepted worst case. It is paid per read, and under ADR 009
|
||||
per edit, by a maintained `SUM` that holds between 2 and 32 distinct non-decimal
|
||||
6th term anyway (below). The 32 of revisions 5 to 7 was a judgement and was not tuned. The read's measured cost
|
||||
above is why question 16 recommended a smaller one (K = 8). The user first chose 32
|
||||
and then 8, so **52–127 µs is the accepted worst case**. It is paid per read, and under
|
||||
ADR 009 per edit, by a maintained `SUM` that holds between 2 and 8 distinct non-decimal
|
||||
denominators near `i128` size; a sum with more groups reads the f64 accumulator, and one
|
||||
with few or small denominators is far cheaper (the table is the bound).
|
||||
|
||||
@@ -1717,14 +1732,14 @@ open. Nothing is renumbered.
|
||||
denominators, with no bigint on the read;
|
||||
- **(c)** `Decimal`'s own `+`, accepting demotion that depends on order.
|
||||
|
||||
*Recommendation:* (a), with K = 32. The user confirmed the value in question 16.
|
||||
*Recommendation:* (a), with K = 32 as proposed here. Question 16 later set K = 8.
|
||||
- A fixed register cannot be generic for fractions at any width.
|
||||
- 2,048 bits pays 256 bytes per summed group for a combination that rarely fits the
|
||||
stored bound anyway.
|
||||
- The bigint read is paid only when a sum holds 2 to K distinct fraction
|
||||
denominators: about 16–34 µs at K = 32, an estimate. (Revision 6 measured it:
|
||||
0.67–1.9 ms at K = 32 in the worst case, and the user kept K = 32. See
|
||||
question 16.)
|
||||
0.67–1.9 ms at K = 32 in the worst case, 52–127 µs at K = 8, and the user chose
|
||||
K = 8. See question 16.)
|
||||
- (c) breaks order-independence (revision 2).
|
||||
|
||||
11. **The `MIN`/`MAX` tie-break.** **Decided (the user): prefer the exact value**
|
||||
@@ -1752,7 +1767,7 @@ open. Nothing is renumbered.
|
||||
can overflow in one spelling and not the other, so one is exact and the other a
|
||||
demoted f64. Under (b) the rule is one sentence: **a stored value is exact if and
|
||||
only if it fits.** Algebraically equal formulas give equal values. (Two stated
|
||||
exceptions: the ceiling below, and a `SUM` of more than K = 32 non-decimal
|
||||
exceptions: the ceiling below, and a `SUM` of more than K = 8 non-decimal
|
||||
denominator groups, which reads inexact by question 16 whatever its value.)
|
||||
|
||||
**The rule has two exceptions, and they are stated rather than hedged** (the ceiling
|
||||
@@ -1760,23 +1775,24 @@ open. Nothing is renumbered.
|
||||
`be9de2ee`):
|
||||
- **The ceiling.** Widening carries a size ceiling so that a pathological
|
||||
expression cannot grow a bigint without limit. It must be at least
|
||||
K·127 + 256 bits, so that the grouped read (below) never reaches it: 4,320 bits
|
||||
at K = 32. Revision 5's example of 4,096 bits was below that, and a worst-case
|
||||
K = 32 read would have hit it (the review of `33833f28`). Proposed: **8,192
|
||||
bits**, which covers K = 32 with room, and costs nothing until a value is that
|
||||
large. Past it, the
|
||||
K·127 + 256 bits, so that the grouped read (below) never reaches it: 1,272 bits
|
||||
at K = 8 (it was 4,320 at K = 32). Revision 5's example of 4,096 bits was below the
|
||||
K = 32 figure, and a worst-case K = 32 read would have hit it (the review of
|
||||
`33833f28`). Proposed: **8,192 bits**, which covers K = 8 by 6,920 bits and
|
||||
K = 32 as well, and costs nothing until a value is that large. A smaller ceiling
|
||||
would now suffice; 8,192 is kept because question 13 was decided against it. Past it, the
|
||||
intermediate demotes, and by contagion the stored result is inexact **even when
|
||||
the exact result would fit**. That is spelling-dependent, so distributivity fails
|
||||
past the ceiling. It is the first exception to "exact iff it fits", and no ledger
|
||||
reaches it. `POW` checks its result size **before** computing (clause 5), so the
|
||||
ceiling is never reached by allocating first.
|
||||
- **The K cutoff, which does override representability.** A `SUM` holding more than
|
||||
K = 32 non-decimal denominator groups reads the inexact f64 accumulator, so its
|
||||
K = 8 non-decimal denominator groups reads the inexact f64 accumulator, so its
|
||||
stored result is inexact **even when the exact total would fit** the bound. That
|
||||
is the second exception. It is a policy about the read's cost (question 16), not
|
||||
about whether the value is representable, and it is the consequence of the user's
|
||||
K = 32. **Flagged reading (revision 7):** the user decided K = 32 on question 16's
|
||||
text, which says "Above it the read is the inexact f64 accumulator", and answered
|
||||
K = 8. **Flagged reading (revision 7, restated in revision 8):** the user decided K
|
||||
on question 16's text, which says "Above it the read is the inexact f64 accumulator", and answered
|
||||
question 10 (a) with "at most K groups". No "What the user decided" item says in
|
||||
terms that the cutoff overrides representability. That sentence is the ADR's
|
||||
reading of those two answers, so approval confirms it.
|
||||
@@ -1814,7 +1830,9 @@ open. Nothing is renumbered.
|
||||
`ExactSum` alone, ahead of this ADR, so ADR 009 does not wait for it (clause 14).
|
||||
This question is shared with ADR 009 (PR #309).
|
||||
|
||||
16. **The value of K.** **Decided (the user): (a), K = 32** ("let's do k = 32"). Added
|
||||
16. **The value of K.** **Decided (the user): (b), K = 8** ("Ok, let's drop K back to 8",
|
||||
superseding an earlier "let's do k = 32"; both quoted under "What the user
|
||||
decided"). Added
|
||||
in revision 6, and put as follows. K is the most non-decimal groups a
|
||||
`SUM` reads exactly (question 10). Above it the read is the inexact f64
|
||||
accumulator. Revision 5 proposed K = 32 on an estimate of 16–34 µs per read, and
|
||||
@@ -1822,12 +1840,13 @@ open. Nothing is renumbered.
|
||||
ADR 009 a maintained `SUM` reads after every edit that touches it, so that is a
|
||||
per-edit cost, paid by each such cell.
|
||||
- **(a)** K = 32, as decided with question 10: worst case 0.67–1.9 ms per read.
|
||||
Chosen first, then **superseded**.
|
||||
- **(b)** K = 8: worst case 52–127 µs per read. A `SUM` over more than 8 distinct
|
||||
denominators is inexact.
|
||||
denominators is inexact. **Chosen (the later answer).**
|
||||
- **(c)** K = 16: worst case 174–448 µs per read.
|
||||
|
||||
*Recommendation (not taken):* **(b), K = 8**, with the read combining over the lcm
|
||||
and reducing once (the lower figure in each range). The user chose (a).
|
||||
*Recommendation (taken in the end):* **(b), K = 8**, with the read combining over the
|
||||
lcm and reducing once (the lower figure in each range). The user chose (a), then (b).
|
||||
- The ceiling (question 13) stays at 8,192 bits under any of the three.
|
||||
- The common sums keep exactness under K = 8: `SUM(v / 3)` has one denominator, and
|
||||
an average or a percentage has a handful.
|
||||
@@ -1836,18 +1855,19 @@ open. Nothing is renumbered.
|
||||
- K is a constant inside `numtower`, not a format or wire fact, so it can be tuned
|
||||
later against the evaluator benchmark (migration step 1) without a new ADR.
|
||||
|
||||
**Re-derived under K = 32** (revision 7), from this ADR's own measurements, with
|
||||
nothing new measured:
|
||||
- **Read cost:** the K = 32 row of the table, **0.67 ms** (lcm, then one reduce) to
|
||||
**1.9 ms** (reduce after every add). `numtower` reads by the first method, so the
|
||||
**Re-derived under K = 8** (revision 8), from this ADR's own measurements, with
|
||||
nothing new measured (the K = 32 figures of revision 7 are superseded):
|
||||
- **Read cost:** the K = 8 row of the table, **52 µs** (lcm, then one reduce) to
|
||||
**127 µs** (reduce after every add). `numtower` reads by the first method, so the
|
||||
lower figure is the working number. The 16–34 µs of revision 5 stays withdrawn.
|
||||
- **Combined width:** lcm up to about 4,100 bits (measured 3,924), numerator up to
|
||||
K·127 + 256 = **4,320 bits** (measured 4,053).
|
||||
- **Ceiling:** 8,192 bits, which clears 4,320 by 3,872. Unchanged, so question 13
|
||||
- **Combined width:** lcm up to K·127 = 1,016 bits (measured 988), numerator up to
|
||||
K·127 + 256 = **1,272 bits**. The combined numerator was measured only at K = 32
|
||||
(4,053 bits), so 1,272 is a bound and not a measurement.
|
||||
- **Ceiling:** 8,192 bits, which clears 1,272 by 6,920. Unchanged, so question 13
|
||||
is untouched.
|
||||
- **Memory:** O(distinct denominators), which K does not change (clause 8).
|
||||
- **Not re-derived:** an end-to-end per-edit latency for a maintained `SUM`. The
|
||||
benchmark times the read alone. Whether 0.67–1.9 ms per edit is acceptable on a
|
||||
benchmark times the read alone. Whether 52–127 µs per edit is acceptable on a
|
||||
page of such cells is a question for the evaluator benchmark, not a figure here.
|
||||
|
||||
## Relations to other ADRs
|
||||
@@ -1901,22 +1921,24 @@ don't need to reinvent integers > safe size", makes a grid position a bigint abo
|
||||
can land holding it alone, so ADR 009 does not wait for this ADR.
|
||||
- **`Sum` is exact only under ADR 009's question 3 (c) or under this ADR's wide
|
||||
accumulator.** This ADR's accumulator is exact for decimals (320 bits) and for up to
|
||||
K = 32 fraction denominators (clause 8). For **f64** terms the exact accumulator is
|
||||
K = 8 fraction denominators (clause 8). For **f64** terms the exact accumulator is
|
||||
ADR 009's `ExactSum`. A mixed sum is read from both (clause 8), so "exact under this
|
||||
ADR" holds for decimal and bounded-fraction data, not for f64 data.
|
||||
- **The per-edit cost is a lower bound, and the larger exposure is `Eager`.** ADR 009
|
||||
reads a maintained `SUM` after every edit that touches it. With K = 32 (question 16)
|
||||
the read alone is up to 0.67–1.9 ms for a cell holding many large distinct
|
||||
denominators (see "Re-derived under K = 32"), and the update cost comes on top. ADR
|
||||
reads a maintained `SUM` after every edit that touches it. With K = 8 (question 16)
|
||||
the read alone is up to 52–127 µs for a cell holding several large distinct
|
||||
denominators (see "Re-derived under K = 8"), and the update cost comes on top. ADR
|
||||
009 says `Eager` "pays the read on every aggregate evaluation", and today's TUI
|
||||
projects the whole grid every frame, so it pays one read per summed cell. Against ADR
|
||||
009's budget (8 ms per operation, a 2 ms slice for a job; ADR 008 clause 11), as
|
||||
arithmetic from these figures and not a finding: one worst-case read at 1.9 ms nearly
|
||||
fills a slice; **five** such cells (5 × 1.9 = 9.5 ms) or **twelve** at 0.67 ms
|
||||
(12 × 0.67 = 8.04 ms) exceed 8 ms. This is not a reason to revisit K = 32, which the
|
||||
user chose knowing the read's cost. It is a question for ADR 009's `Eager` and cap
|
||||
design. The worst case needs 2 to 32 large distinct denominators in one sum; a sum of
|
||||
small denominators is far cheaper. ADR 009's own
|
||||
arithmetic from these figures and not a finding: **154** such cells at 52 µs
|
||||
(154 × 52 = 8.0 ms; 153 stay under) or **63** at 127 µs (63 × 127 = 8.0 ms) exceed
|
||||
8 ms, and **39** at 52 µs or **16** at 127 µs exceed a 2 ms slice. At the earlier
|
||||
K = 32 (superseded) it was five and twelve cells per 8 ms, and one read nearly filled a
|
||||
slice. K = 8 is 13 to 15 times cheaper per read than 32 (0.67/0.052, 1.9/0.127). It remains a question for ADR
|
||||
009's `Eager` and cap design, but a far smaller one. The worst case needs 2 to 8 large
|
||||
distinct denominators in one sum; a sum of small denominators is far cheaper. ADR
|
||||
009's own
|
||||
`ExactSum` figures (2.0–3.6 ns per update, 0.6–1.1 µs per read) are for the f64
|
||||
accumulator and are not comparable.
|
||||
- **Flag, stale text in ADR 009.** At its head it describes ADR 005's cost as
|
||||
@@ -1976,7 +1998,7 @@ don't need to reinvent integers > safe size", makes a grid position a bigint abo
|
||||
- A value typed past `Decimal`'s range is an exact fraction when it fits `i128`
|
||||
(`1e-30`, a 30-digit integer), as the same value computed already is (clause 3).
|
||||
- A `SUM` reads exactly over at most K distinct fraction denominators, at a worst-case
|
||||
cost that grows about as K² (question 16: K = 32, decided), and past K it is inexact.
|
||||
cost that grows about as K² (question 16: K = 8, decided), and past K it is inexact.
|
||||
- Formulas gain `EQUAL(a, b, epsilon)`, and `EQUAL` becomes a keyword the writer quotes.
|
||||
- **Costs:** `Num` is 24 bytes where an `f64` is 8, but **`CellValue` stays 32 bytes**
|
||||
under both (a) and (d), because its `String` arm already sets the size (the review
|
||||
|
||||
Reference in New Issue
Block a user