-
-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
@seiko2plus - Came here out of curiosity from numpy/numpy#29699 (comment), to see how things get done. For cos, the following transformation is done before any real calculation:
numpy-simd-routines/npsr/trig/high-inl.h
Lines 35 to 43 in 1acd145
| const V x_abs = And(abs_mask, x); | |
| const V x_sign = AndNot(x_abs, x); | |
| // Transform cosine to sine using identity: cos(x) = sin(x + π/2) | |
| const V half_pi = Set(d, data::kHalfPi<T>); | |
| V x_trans = x_abs; | |
| if constexpr (OP == Operation::kCos) { | |
| x_trans = Add(x_abs, half_pi); | |
| } |
This would seem to loose some precision for the common case where angle input will be between -pi and pi, by moving those angles to pi/2 to 3*pi/2. Instead, one can move those angles to near zero and thus get optimal precision near both crossings by using that cos(x) = sin(pi/2 - |x|) , i.e. do something like,
// Transform cosine to sine using identity cos(x) = sin(π/2 - |x|)
// where |x| ensures optimal precision near both -pi/2 and pi/2.
const V half_pi = Set(d, data::kHalfPi<T>);
V x_trans = x;
if constexpr (OP == Operation::kCos) {
x_trans = And(abs_mask, x);
x_trans = Sub(half_pi, x_trans);
}
const V x_abs = And(abs_mask, x_trans);
const V x_sign = AndNot(x_abs, x_trans);
Metadata
Metadata
Assignees
Labels
No labels