Your free trial has ended.

Try the live demo or log in .

88a2d03d

By: ValentinHirschi <valentin.hirschi@gmail.com>

Make native DoubleFloat products commutative for exact predicates

NinjaRS found an equal-mass four-mass D0 (m² = mu² = 1; p1² = 2171/144,
p2² = 211/16, p3² = -5/4, p4² = -587/72, s12 = -311/72, s23 = 27/16) whose
native DoubleFloat finite part was +0.372256 instead of -0.0634209 in one
of its eight relabellings, and at the rounded invariants its reduction
passes. The imaginary part was right. Binary64 (hand-written and
generated), native Float and the expression interpreter agreed in every
labelling. In NinjaRS this moved a 12-point box-stage sum by 3.5e-14
(relative) and the cancelling DoubleFloat amplitude by 1.6e-3.

The compensated product of xprec's Df64, behind numerica's DoubleFloat,
accumulates its cross terms in operand order, so x*y and y*x can differ in
the low component. The imaginary part of z conj(z), re (-im) + im re, then
kept a residue (1.2e-35 here), and the exact sign test x - |x| of the
sheet dilogarithm's inversion `negative(1 - z conj(z))` read it as
negative: it inverted an argument of modulus 0.09. Binary64 and MPFR
products are commutative, so their residue is exactly zero (as
tests/native_primitives.rs already checks for binary64).

The native DoubleFloat complex product now forms its real products from
operations that are each symmetric in the two operands: the high product
with its fused rounding error and the plain sum of the two cross products
(Dekker's form, the same few-ulp accuracy). Products are then exactly
commutative and odd in each operand, and z conj(z) is exactly real.
Binary64 and Float are unchanged. The interpreter's DoubleFloat route still
uses numerica's product.

Tests: tests/native_double_float_d0.rs (all eight labellings at exact and
at NinjaRS's rounded invariants, against native Float at 256 bits, Float
at 128 bits and binary64) and a DoubleFloat case in
tests/native_primitives.rs. Both fail without the change.

Retired instructions per call (in-process counters, DoubleFloat): complex
multiply-add 353 -> 269; 32 generic rows D0 -6.3%, C0 -8.5%; the eight
equal-mass rows above D0 -23% and C0 +9.8%, where exact decisions now
select other branches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>