2026-09-04 - (/loop) libm splits in two, and only half belongs here

differential   345  ->  373 cases
suites 125   tests 2013   clippy/fmt/identity clean

Nineteenth cron tick.

The census was incomplete, and the filter was mine

D532 asked which implemented libc functions have no differential case - and filtered the answer to string- and number-shaped names. That hid around fifty math functions, all implemented, none ever compared. A negative from a filter being a fact about the filter (check 4), applied to my own census one tick after writing it up.

437 uncovered in full. Most is correctly out of scope - pthreads, sockets, files, the C++ ABI - none of it comparable by value. libm is the part that is.

The split is the finding

The second half is the rand/strerror trap again, and a bigger one: forty agreeing cases would look like forty verified functions while asserting an implementation detail nobody promised.

Bit patterns, because a decimal hides the case that matters

A decimal rendering hides last-place differences and the sign of zero. round(-0.5) is -0.0, and an implementation answering +0.0 passes every comparison that goes through a string.

The break, and the case that stayed quiet

round is half-away-from-zero; the hardware default is half-to-even. Breaking it that way:

round/half-up:              returned 0x0,                glibc 0x3ff0000000000000
round/half-away-from-zero:  returned 0x8000000000000000, glibc 0xbff0000000000000
round/two-and-a-half:       returned 0x4000000000000000, glibc 0x4008000000000000
round/minus-two-and-a-half: returned 0xc000000000000000, glibc 0xc008000000000000

The second is -0.0 against -1.0 - the sign-of-zero point on its own.

round/one-and-a-half did not fire, because half-to-even also answers 2 for 1.5. The halfway cases discriminate rather than failing as a block, which is what says they test the rule and not the neighbourhood.

One instrument note

The build script did not link libm, so the first regeneration failed at the linker - and the script's own guard refused to install the short run, leaving the committed file untouched at 345. That guard has now paid for itself. -lm added.

Decision: D533.