22
33#include " numerics/angle_reduction.hpp"
44
5+ #include < algorithm>
56#include < cmath>
67#include < limits>
78
89#include " base/macros.hpp" // 🧙 For PRINCIPIA_USE_SSE3_INTRINSICS.
910#include " numerics/double_precision.hpp"
11+ #include " numerics/elementary_functions.hpp"
1012#include " numerics/payne_hanek.mathematica.h"
1113#include " quantities/si.hpp"
1214
@@ -16,6 +18,7 @@ namespace _angle_reduction {
1618namespace internal {
1719
1820using namespace principia ::numerics::_double_precision;
21+ using namespace principia ::numerics::_elementary_functions;
1922using namespace principia ::numerics::_payne_hanek;
2023using namespace principia ::quantities::_si;
2124
@@ -175,7 +178,12 @@ void PayneHanek(Angle const& x,
175178 // Correct the mantissa and exponent to match [Mul97, p. 155].
176179 e--;
177180 X = std::scalbn (X, n);
178- CHECK_GE (e, -1 );
181+ if (e < -1 ) {
182+ DCHECK_LT (Abs (x), 0.5 * Radian);
183+ x_reduced = DoublePrecision<Angle>(x);
184+ quadrant = 0 ;
185+ return ;
186+ }
179187
180188 // Split `X` so that the multiplications below are exact.
181189 double Xh;
@@ -185,7 +193,7 @@ void PayneHanek(Angle const& x,
185193 // Converts the bit numbering of [Mul97, p. 155] into our index in
186194 // `PayneHanekChunks`.
187195 auto bit_to_index = [](std::int64_t const b) {
188- return -b / PayneHanekBitsPerChunk;
196+ return std::max ( INT64_C ( 0 ), -b / PayneHanekBitsPerChunk) ;
189197 };
190198
191199 // `Medium(e, p)` is made of the chunks with indices [medium_first,
@@ -235,8 +243,8 @@ void PayneHanek(Angle const& x,
235243 // rounding, not x * (4 / π) with truncation.
236244 h = Scale (0.5 , h);
237245
238- // Because of the bound on `h` above, the fractional point is sure to be in
239- // the `value `.
246+ // Because of the bound on `h` above, the fractional point cannot be in the
247+ // `error `.
240248 double const round_h = std::round (h.value );
241249 quadrant = static_cast <std::int64_t >(round_h) & 0b11 ;
242250 x_reduced = (h - round_h) * π_over_2;
0 commit comments