The claim under test: the same call, with the same inputs, returns the same bits - on every backend, on every machine, on every day (host/include/cft.h). This page loads the library's software backend as wasm and replays the project's published conformance vectors through it, in this tab, with no server and no network. The backend's arithmetic is integer-only - uint32 limbs, uint64 intermediates - and WebAssembly integer semantics are fully specified, so what runs here is not a lookalike of libcft: it is libcft, and it must produce the library's exact bits or fail below.
loading the wasm module…
This page carries a deterministic sample of the published vector
sets and replays it automatically on load, through
cft_conformance() itself - the library's own parser,
per-element pass (exact flags per case), array pass (batching), and
its refusal to let a run that checked nothing read as a pass. Not a
JavaScript reimplementation of the replay: the same C code path every
other backend is judged by.
Sampling rule (deterministic, restated in
build.sh): regenerate the published sets with
; from each of the 20 opcode sets
(4 formats × 5 rounding attributes, 11,800 cases
each) take every 59th line - 0-based lines 0, 59, 118, … - then
add the set's first line for any opcode name the stride missed, so
every opcode class is present per set by construction, the seed
opcodes recip_seed/rsqrt_seed and the
unassigned reserved15/30/255 included. (That list has
shed a member three times - 24 became sum, 26
recip_seed, and 28 sumsq at ABI 0.6 - which
is the hazard a published reserved case carries and the
reason the replayer refuses a set whose reserved opcode has since
been assigned.) The other four families - transcendental, augmented,
reduction, character - are not embedded; drop them in section 3,
where they are replayed whole.
| set | cases | result |
|---|
The embedded sample is a sample. For the full claim, generate the
complete sets in a checkout of this repo -
make vectors, which writes 1,068,915 cases over
168 sets to vectors/out/: 240,000 over twenty
opcode sets, 533,265 over twenty transcendental sets (all thirty-nine
functions since ABI 0.6, table 9.1 complete), 89,616 over the four
augmented sets of clause 9.5, 8,960 over twenty reduction sets,
13,816 over twenty character sets, and since ABI 0.7 9,728 over the
four magnitude sets of clause 9.6 and 176,250 over the eighty
formatOf sets of clause 5.4.1 - one per ordered pair of formats per
attribute - and drop any or all of the
.jsonl files here. Same code path as section 2, whole
files this time.
vectors/out/*.jsonl here — or click to pick files| set | cases | result |
|---|
Only the generator's fixed names are accepted - all 168 of them: fp32.jsonl … fp256-rmm.jsonl, fp32-transcend.jsonl … fp256-transcend-rmm.jsonl, fp32-augmented.jsonl … fp256-augmented.jsonl (one per format, because 754-2019 9.5 fixes the rounding and there is no attribute to sweep), fp32-reduce.jsonl … fp256-reduce-rmm.jsonl, fp32-character.jsonl … fp256-character-rmm.jsonl, fp32-minmaxmag.jsonl … fp256-minmaxmag.jsonl (one per format again, and for a sharper reason: 9.6's magnitude forms compare two magnitudes and then select an operand, so there is no rounding for an attribute to direct) and fp32-to-fp32-formatof.jsonl … fp256-to-fp256-formatof-rmm.jsonl (sixteen ordered pairs × five attributes; a case there carries a source-format operand and a destination-format result on the same line, and names both formats so the file cannot lie about which pairing it is) - cft_conformance enumerates sets by name rather than by scanning, and a file this page cannot map to a set is refused loudly rather than skipped quietly.
The same library, called forward: one element through
cft_run(), or the composed cft_div() /
cft_sqrt() sequence, or any of the thirty-nine
transcendentals - phase 1's nine (cft_exp …
cft_hypot, ABI 0.3), phase 2's eleven
(cft_sinpi … cft_atan2pi, ABI 0.4),
phase 3's nine (cft_sin … cft_atanh,
ABI 0.5, sin/cos/tan in radians) and the ten that complete
754-2019 table 9.1 (cft_exp2m1 …
cft_rootn, ABI 0.6) - operands and result as raw
encodings. This is a working
binary32/64/128/256 calculator, and every answer it gives is pinned by
the replay above. The transcendentals are correctly rounded,
which is why they can be in a determinism contract at all: the answer
is defined by the mathematics, not by an algorithm, so every correct
implementation agrees with this one bit for bit. The eleven are the
ones whose argument reduction is exact - sinPi's is
x mod 2, a mask on the encoding, and the inverses meet
π only as a factor of the answer - while sin,
cos and tan of a radian argument
reduce against the library's own 270,336-bit 2/π instead.
ABI 0.6 also puts the other three packages here. Clause
5.12's character conversions read and write a
sequence rather than an encoding - the panel grows a text
field for one and a digit count for the other, and the two-call
sizing protocol it runs to get an answer out is the C's own, not a
shorter one invented for JavaScript. Clause 9.7's
three payload operations signal nothing at all, so there is no flag
line under them. Clause 9.5's augmented arithmetic
and clause 9.4's scaled products each return a
pair, shown on two lines: r and e,
whose sum is exactly the operation; or pr and an int64
sf, whose scaleB is the product. The
augmented three ignore the rounding select and grey it out, because
9.5 fixes their direction to roundTiesTowardZero, which is not one of
clause 4.3's five attributes. sumsq, sumabs
and the scaled products are reductions over a whole vector; this
panel is a one-element calculator, so it runs them over the single
operand, which is an answer the contract names rather than a special
case invented for the page.
ABI 0.7 adds two more. Clause 9.6's four
magnitude forms of minimum and maximum are here beside the
four opcodes they defer to, and like the augmented three they grey
the rounding select out - not because an attribute is fixed but
because there is no rounding at all: each compares two sign-cleared
encodings and then selects one operand, so the answer is an
operand's own bits except where the base operation delivers a NaN.
The row worth trying is equal magnitudes of opposite sign:
maximumMagnitude(+3, -3) is the “otherwise”
case and defers to maximum, so it is +3, and an
implementation that quietly preferred the second operand would be
wrong here and nowhere else. Clause 5.4.1's six
formatOf operations take two formats, so
the panel grows a second select: the operands are read in the source
format, the result is delivered in the destination one, and there is
exactly one rounding between them. Narrowing is not
“compute there, convert here” - that rounds twice, and on
operands this ladder can construct the composed answer is one ulp
low with the same flags.
The status word under the result is 754-2019
7.1's: one sticky word on the device handle into
which every call ORs what it signalled, which nothing in the
library ever lowers. The flags line above it is the
last call's; this one is every call since the page loaded or since
you last cleared it, which is the distinction 7.1 exists to draw.
Sections 2 and 3 are calls too, so the word is already carrying the
replay's exceptions before you compute anything — press
lower all flags first if you want to watch one operation on
its own. It
never influences a result - libcft never reads it back to decide
anything - so clearing it or not changes no answer anywhere.