CC: | smueller [...] cpan.org |
Subject: | blead and perl 5.30 cause the test suite to fail on Free BSD and Open BSD |
A work around was added to Math-Clipper in May 2018 for a bug in the pow() function on Free BSD machines. It turns out that Open BSD is also affected. The work around involves these two lines from Clipper.pm
# brings behavior of FreeBSD + clang systems into harmony with others
$scale_vector[$ci] = 0.0 + sprintf("%.0f",$scale_vector[$ci]);
(If the comment had been clearer, it would have saved us some debugging time, though maybe the author didn't fully understand the situation)
It turns out that the earlier exponentiation
10**(-$max_exp + ($intspecs{$opts{bits}}->{maxdigits} - 1));
returns a slightly too large value when the exponent there evaluates to 29. (This is regular double precision; I havent tested with long doubles)
And it turns out that this statement turns, underneath the hood, into a call of the library routine pow(10,29), and that is buggy on these platforms. The 'harmonizing' line executes a sprintf which stringifies this wrong value, and adding it to zero causes perl to parse that string, and converted the wrong value into the right one. That is, it did so, until we fixed it to parse the string correctly, retaining the wrong value, causing the suite to fail.
I have no idea what the extent of the pow bug is. It could be just these two values, or it could be lots of inputs cause failures.
So what to do about this. We have tested our fix of string parsing with many different values, and it works better than what was there before, which fails miserably on many. Hence, we aren't going to revert our change. It likely fixes bugs with other inputs that your suite doesn't happen to check.
perl is not going to furnish a pow() function to override broken ones on those few platforms that have failures.
What could you do? For one, the call to _floor is asymmetric with regards to positive vs negative values. I think it should truncate towards zero. As it is, -2.000000000...0000001 gets changed to -3. I think that should be changed. Either a different function, such as rint() should be used, or perhaps easier is to take the floor of the absolute value, and then change the sign back to negative if needed. Doing that causes the test suite to pass, and the workaround there now wouldn't be necessary in any perl version.
A less enticing option would be to replace the exponentiation with a loop that multiplies 10 by itself n times. But Math::Clipper shouldn't have to write its own pow() equivalent for a bug on one platform. (Although the 'harmonizing' line is kinda doing that)