@@ -138,42 +138,16 @@ cstring_to_quad_internal(const char *str, const char *start, QuadBackendType bac
138138 memcpy (temp , str , len );
139139 temp [len ] = '\0' ;
140140
141- // Call Sleef_strtoq with the bounded string
141+ // Call Sleef_strtoq with the bounded string.
142142 //
143- // DEVELOPER NOTE - Sleef_strtoq decimal precision limit.
144- // The decimal branch of Sleef_strtoq is NOT correctly-rounded. It
145- // accumulates digits (n = n*10 + d) into SLEEF's triple-double "tdx"
146- // format (a 64-bit exponent + vdouble3 mantissa, ~159 mantissa bits),
147- // scales by exp10i() and rounds via cast_vq_tdx(). Only the hex (0x...)
148- // branch is exact bit-manipulation.
149- //
150- // Three different digit counts are involved - do NOT conflate them:
151- // * ~34 = a quad's actual precision (113 * log10(2))
152- // * 36 = digits that GUARANTEE any quad round-trips; this is
153- // SLEEF_QUAD_DECIMAL_DIG and the most Dragon4 (str/repr) emits
154- // * ~48 = the tdx mantissa's raw capacity (159 bits / log2(10))
155- // * ~45 = the EFFECTIVE window this parser resolves correctly - a few
156- // digits below 48 because the tdx add/mul/div/exp10i are not
157- // perfectly rounded. Property of the parser, not of quads.
158- //
159- // ~45 is NOT a hard/coded limit: it is a soft, build-dependent threshold,
160- // and it is measured (empirical), not read from a constant. Sweeping
161- // genuine quads across the exponent range, the smallest k at which
162- // nudging a half-ULP midpoint by 10^-k gets silently dropped (rounds the
163- // wrong way) was 45 (some values tolerate 46-48). Inputs longer than the
164- // window are still read - the extra digits just stop reliably affecting
165- // the result. So if the digit that decides rounding sits at position
166- // >= ~46 - e.g. a value just above a midpoint - the result can be 1 ULP
167- // off. Concrete repro
168- // (SLEEF 3.9.0, x86): the ~46-digit-deep value near
169- // "1.99999...9997111...e0" parses to ...ffffe, not the correct ...fffff.
170- //
171- // Practical impact on quad<->string round-trips: none here. Every quad
172- // is captured by <= 36 digits, ~9 below the ~45 window, so Dragon4
173- // output re-parses exactly. BUT that ~45 is FMA-/codegen-dependent (the
174- // tdx arithmetic can lose a guard bit on some toolchains, e.g. macOS)
175- // and can shrink toward 36 - so do not rely on string parsing for
176- // exactness. Binary paths (raw bytes) are always exact.
143+ // NOTE: SLEEF's decimal strtoq is only non-correctly-rounded for inputs
144+ // whose *significant* digits exceed what a quad can hold (>~45); there it
145+ // may be <= 1 ULP off. This is unreachable for quad<->string round-trips:
146+ // every quad is exact within SLEEF_QUAD_DECIMAL_DIG (36) significant
147+ // digits and Dragon4 (str/repr) emits <= 36, so re-parsing is exact. Only
148+ // significant digits count - magnitude/exponent (e.g. 1e4932) is scaled
149+ // separately and is fine. Pickling uses raw bytes (from_raw_bytes), which
150+ // never goes through this path.
177151 char * sleef_endptr ;
178152 out_value -> sleef_value = Sleef_strtoq (temp , & sleef_endptr );
179153 free (temp );
0 commit comments