Skip to content

Commit 0a4e02b

Browse files
committed
BUG: Give low-accuracy f64 cosine its own minimax fit
Cosine reduces around (N+0.5)pi, so its polynomial needs its own coefficient set rather than reusing the sine fit to bitexact with SVML. low-inl.h now selects cosine-tuned c3..c15 for the kCos path. Also raise the low-accuracy cosine large-argument threshold to 0x1.921fb2200366fp+24 (largest double with trunc(|x|/pi) <= 8388606) so it stays on the fast path up to the real boundary instead of falling back to extended precision at 2^24.
1 parent 632bb0c commit 0a4e02b

2 files changed

Lines changed: 20 additions & 12 deletions

File tree

npsr/trig/inl.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ namespace npsr::HWY_NAMESPACE::trig {
4949
* - Double: |x| > 2^24 (16,777,216 - where 53-bit mantissa loses precision)
5050
*/
5151
template <Operation OP, typename Prec, typename V>
52-
NPSR_INTRIN V Trig(Prec &prec, V x) {
52+
NPSR_INTRIN V Trig(Prec& prec, V x) {
5353
using namespace hwy::HWY_NAMESPACE;
5454
constexpr bool kIsSingle = std::is_same_v<TFromV<V>, float>;
5555
const DFromV<V> d;
@@ -81,8 +81,14 @@ NPSR_INTRIN V Trig(Prec &prec, V x) {
8181
// Thresholds chosen based on when standard reduction loses accuracy:
8282
// - Float: 10,000 is conservative but ensures < 1 ULP error
8383
// - Double: 2^24 is where mantissa can't represent x and x-2π distinctly
84+
// - Double low-accuracy cosine: stays on its fast path
85+
// until trunc(|x|/π) > 8388606; this is the largest double below that
86+
// boundary (~8388607π)
87+
constexpr bool kIsLowCos =
88+
Prec::kLowAccuracy && OP == trig::Operation::kCos;
89+
constexpr double kLargeF64 = kIsLowCos ? 0x1.921fb2200366fp+24 : 16777216.0;
8490
auto has_large_arg =
85-
And(Gt(Abs(x), Set(d, kIsSingle ? 10000.0f : 16777216.0)), is_finite);
91+
And(Gt(Abs(x), Set(d, kIsSingle ? 10000.0f : kLargeF64)), is_finite);
8692

8793
// Extended precision is expensive, only use when necessary
8894
if (HWY_UNLIKELY(!AllFalse(d, has_large_arg))) {
@@ -121,7 +127,7 @@ namespace npsr::HWY_NAMESPACE {
121127
* ```
122128
*/
123129
template <typename Prec, typename V>
124-
NPSR_INTRIN V Sin(Prec &prec, V x) {
130+
NPSR_INTRIN V Sin(Prec& prec, V x) {
125131
return trig::Trig<trig::Operation::kSin>(prec, x);
126132
}
127133

@@ -143,7 +149,7 @@ NPSR_INTRIN V Sin(Prec &prec, V x) {
143149
* ```
144150
*/
145151
template <typename Prec, typename V>
146-
NPSR_INTRIN V Cos(Prec &prec, V x) {
152+
NPSR_INTRIN V Cos(Prec& prec, V x) {
147153
return trig::Trig<trig::Operation::kCos>(prec, x);
148154
}
149155

npsr/trig/low-inl.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,17 @@ NPSR_INTRIN V PolyLow(V r, V r2) {
5454
template <Operation OP, typename V, HWY_IF_F64(TFromV<V>)>
5555
NPSR_INTRIN V PolyLow(V r, V r2) {
5656
using namespace hn;
57-
5857
const DFromV<V> d;
59-
const V c15 = Set(d, -0x1.9f1517e9f65fp-41);
60-
const V c13 = Set(d, 0x1.60e6bee01d83ep-33);
61-
const V c11 = Set(d, -0x1.ae6355aaa4a53p-26);
62-
const V c9 = Set(d, 0x1.71de3806add1ap-19);
63-
const V c7 = Set(d, -0x1.a01a019a659ddp-13);
64-
const V c5 = Set(d, 0x1.111111110a573p-7);
65-
const V c3 = Set(d, -0x1.55555555554a8p-3);
58+
// Sine and cosine use distinct minimax fits of sin(r): the cosine path
59+
// reduces around (N + 0.5)*pi, so its coefficient set differs
60+
constexpr bool kCos = OP == Operation::kCos;
61+
const V c15 = Set(d, kCos ? -0x1.9f0d60811aac8p-41 : -0x1.9f1517e9f65fp-41);
62+
const V c13 = Set(d, kCos ? 0x1.60e6857a2f220p-33 : 0x1.60e6bee01d83ep-33);
63+
const V c11 = Set(d, kCos ? -0x1.ae63546002231p-26 : -0x1.ae6355aaa4a53p-26);
64+
const V c9 = Set(d, kCos ? 0x1.71de38030fea0p-19 : 0x1.71de3806add1ap-19);
65+
const V c7 = Set(d, kCos ? -0x1.a01a019a5b87bp-13 : -0x1.a01a019a659ddp-13);
66+
const V c5 = Set(d, kCos ? 0x1.111111110a4a8p-7 : 0x1.111111110a573p-7);
67+
const V c3 = Set(d, kCos ? -0x1.55555555554a7p-3 : -0x1.55555555554a8p-3);
6668
V poly = MulAdd(c15, r2, c13);
6769
poly = MulAdd(r2, poly, c11);
6870
poly = MulAdd(r2, poly, c9);

0 commit comments

Comments
 (0)