Skip to content

ENH: improve f32 sin/cos accuracy - #12

Draft
seiko2plus wants to merge 2 commits into
numpy:mainfrom
seiko2plus:ENH/trig-float32-accuracy
Draft

ENH: improve f32 sin/cos accuracy#12
seiko2plus wants to merge 2 commits into
numpy:mainfrom
seiko2plus:ENH/trig-float32-accuracy

Conversation

@seiko2plus

@seiko2plus seiko2plus commented Jul 28, 2026

Copy link
Copy Markdown
Member

merge after #10

The new improvements provide better accuracy for both non-FMA and FMA
targets, so we can achieve 2ulp for the low accuracy path and 1ulp for
the high accuracy path without affecting performance, except for a few ops on
non-FMA targets, which was necessary to match FMA target precision.
The improvements also include increasing the fast path ranges for FMA targets,
and it has been tested against an exhaustive test covering all float32 ranges (#11).

This was achieved by refitting the f32 sin/cos polynomials as generated minimax sets (new
data/polyf32.h.pol) instead of SVML hardcoded coefficients, split per op and per
FMA mode. For non-FMA:

  • High<> gets a third pi word with 31-bit heads so n*pi_i stays
  • exact; FMA keeps the two-word 35+53-bit split.
  • Low<> recovers the pi[2] rounding error via Fast2Sum on non-FMA,
    the same approach applies to float64.

Also, for all targets:

  • Low<> cos(x) == 1 is answered for all |x| below a per-type bound, not just
    x_trans == pi/2, which fixes tiny tests.
  • kLargeF32 replaces the flat 10000 with per-path measured thresholds.
  • Sollya prec 512 -> 1024, which was needed for generating the float32-widening double poly.

TODO:

- Extended path: restructure final reconstruction to follow SVML's
  per-precision rounding DAG (f32/f64 pair the sin/cos correction
  terms differently) and regenerate approx.h so sigma is a signed
  power of two, keeping sigma*r exact
- Low path: give f64 cosine its own minimax fit matching
  __svml_cos_d_la and keep its fast path up to ~8388607*pi
- Non-FMA f64: add SplitMul (exact head product via 26-bit split) to
  replace the FMA product-error idiom in the high/extended paths and
  reduce with a descending 4-word pi/16, restoring sub-ULP accuracy
- Correct trig polynomial/scale/threshold commentsit log
@seiko2plus

Copy link
Copy Markdown
Member Author

it should resolves numpy/numpy#29699

The new improvements provide better accuracy for both non-FMA and FMA
targets, so we can achieve < 2ulp for the low accuracy path and < 0.6 for
the high accuracy path without affecting performance, except for a few ops on
non-FMA targets, which was necessary to match FMA target precision.
The improvements also include increasing the fast path ranges for FMA targets,
and it has been tested against an exhaustive test covering all float32 ranges.

This was achieved by refitting the f32 sin/cos polynomials as generated minimax sets (new
data/polyf32.h.pol) instead of SVML hardcoded coefficients, split per op and per
FMA mode. For non-FMA:
- High<> gets a third pi word with 31-bit heads so n*pi_i stays
- exact; FMA keeps the two-word 35+53-bit split.
- Low<> recovers the pi[2] rounding error via Fast2Sum on non-FMA,
  the same approach applies to float64 and buys ~0.3 ulp.

Also, for all targets:
- Low<> cos(x) == 1 is answered for all |x| below a per-type bound, not just
x_trans == pi/2, which fixes tiny tests.
- kLargeF32 replaces the flat 10000 with per-path measured thresholds.
- Sollya prec 512 -> 1024, which was needed for generating the float32-widening double poly.
@seiko2plus
seiko2plus force-pushed the ENH/trig-float32-accuracy branch from 20237d9 to 25c7820 Compare July 28, 2026 00:27
@seiko2plus
seiko2plus marked this pull request as ready for review July 28, 2026 00:30
@seiko2plus
seiko2plus marked this pull request as draft July 28, 2026 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant