By: ValentinHirschi <valentin.hirschi@gmail.com>
Pin Symbolica with single-rounded Float products and exact ±1 factors The Float routes (native code and interpreted expressions, which NinjaRS's arbitrary-precision masters use) were wrong on rows where binary64 was right, by 5e-2 to 4e6 of the value. In the D0 oracle sweeps (seeds 1-4, 25,645 rows where OneLOop is stable) that was 62 native and 44 interpreted rows at 256 bits, and similar counts at 128, 512 and 1024 bits. Example: 3.07e4 + 19i for 8.70 + 5.83i at 256 bits. The C0 sweeps had 46 and 33. The values were the same at 09b2c74. Cause, in Symbolica's numerica: a Float carries its own precision, and a square root has one bit more than its argument. Two operations broke identities that binary64 keeps. - A product by reference first rounded the more precise factor to the other's precision, so a b and b a differed, and z conj(z) kept an imaginary residue. - Evaluators form a - b as a + (-1) b with a -1 at the working precision, so the product rounded b. x - |x| (the sign test) and x - conj(x) (the imaginary part) then gave one-bit residues for about half of all square roots. Exact sign and zero tests branched on these residues. For example, a tie |b + d| = |b - d| came out -2.8e-76 at 256 bits and swapped the roots of the two-mass box above. Fix: symbolica-dev/symbolica#97 rounds Float products and quotients once, to the smaller precision, and keeps factors of exactly ±1 exact. The pin moves to 9cdc2949 (ValentinHirschi/symbolica claude/oneloopmaster-integration-float-products: e679e8c1 plus that commit) in all three build roots. Results: - D0 sweeps, rows wrong at 128/256/512/1024 bits: native 82/62/56/59 -> 12/0/0/5, interpreted 96/44/68/46 -> 12/0/4/4. - C0 sweeps: native 62/46/33/52 -> 23/7/6/12, interpreted 62/33/33/39 -> 20/12/8/5. A0, B0 and dB0 had none before or after. - Binary64 is bitwise unchanged on every route over the 37,642 D0 and 17,555 A0-C0 sweep rows. So is DoubleFloat, over those rows plus the 7,645 NinjaRS C0/D0 calls. - The D0 sweep failure lists (seeds 1-4, native, generated and expression) are byte-identical to 9a898ee and 09b2c74. The summaries equal 9a898ee's, except that in seed 4 twelve OneLOop-unstable rows move from unstable-analytic to unstable-binary64: their 256-bit values now agree with OneLOop's quadruple precision. - NinjaRS: none of the 7,645 C0/D0 calls of the rank n+2 suite and final review lanes was affected. Their Float values move by at most 4.7e-71 relative at 256 bits. tests/float_exact_products.rs checks 7 D0 and 4 C0 rows in all their relabellings: - References: Denner and Dittmaier's two-mass box or the C0 Feynman-parameter integral in mpmath at 40 digits, otherwise COLLIER 1.2.9 in quadruple precision on exact decimal inputs. - Routes: binary64 (hand-written, generated, interpreted, SymJIT), DoubleFloat, and native and interpreted Float at 128 to 512 bits. - It fails with the previous pin in 605 checks on every row. - An ignored test reproduces the interpreted Float C0 at vanishing invariants, which remains open. STATUS.md records the fix, the remaining D0 and C0 Float rows and a C0 defect that every route shares. PRECISION.md and README.md describe the new pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>