Ticket #9104 (closed Bugs: fixed)

Opened 4 years ago

Last modified 4 years ago

boost::math::ellint_2 bug in x86_64 double precision

Reported by: julian.panetta@… Owned by: johnmaddock
Milestone: To Be Determined Component: math
Version: Boost 1.54.0 Severity: Problem
Keywords: Cc:


The way ellint_e_imp reduces its input angle into the range |phi| <= pi/2 has a bug when executing in double precision mode on intel chips (as opposed to the default double extended-precision mode) that results in errors as great as 100%.

The relevant lines are at boost/math/special_functions/ellint_2.hpp:

T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
T m = floor((2 * phi) / constants::pi<T>());

Compiled with optimizations on both g++ and clang++, fmod_workaround() essentially becomes a "fprem" instruction, and (2 * phi) / pi() becomes an "fdivr" instruction. "fprem" ignores the precision mode and always produces exact results. "fdivr," however, gives less accurate results in plain double precision mode. This leads to the following error when, for example, phi = M_PI (slightly less than boost's more accurate pi()):

In plain double precision, rphi is computed as slightly less than pi()/2 (correct since M_PI < pi()). However, m = 2 (incorrect, rounded result). The end result is m * pi()/2 + rphi is close to 3pi/2 instead of M_PI, causing the computed integral to be 50% too large. In extended precision, the "fdivr" is accurate enough to yield m = 1 correctly.

There are two ways I can see of avoiding this:

T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
T m = (phi - rphi) / T(constants::pi<T>() / 2);

and the less verbose:

T m = floor(phi / T(constants::pi<T>() / 2));
T rphi = phi - m * T(constants::pi<T>() / 2);

Both would ensure rphi and m are consistent with the original phi. Note: in the second formula for m, T(constants::pi<T>() / 2) is folded into a constant that is exactly pi()/2, whereas the floor() argument in the original version generated extra code to double phi.


Change History

comment:1 Changed 4 years ago by johnmaddock

  • Status changed from new to closed
  • Resolution set to fixed

(In [85678]) Suppress warning in fraction.hpp. Fix internal consistency of argument reduction in elliptic integrals when the argument is very close to a multiple of PI/2. Fixes #9107. Fixes #9104.

comment:2 Changed 4 years ago by johnmaddock

(In [85987]) Merge accumulated patches from Trunk. Refs #8384, Refs #8855, refs #9107, refs #9109, refs #8333, refs #8621, refs #8732, refs #8733, refs #8837, refs #8940, refs #9042, refs #9087, refs #9104, refs #9126.


Add a comment

Modify Ticket

Change Properties
<Author field>
as closed
The resolution will be deleted. Next status will be 'reopened'

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.