The powl() shipped with MinGW is defective. 9**(9**9)
should return Inf, as this value is orders of magnitude above LDBL_MAX. Instead, this returns LDBL_MAX. Example:
lddemo.c:
#include <tgmath.h> #include <stdio.h> int main() { long double a, b, c; a = 9; b = powl(a, a); c = powl(a, b); __mingw_printf("powl(9, powl(9, 9)) = %Le\n", c); }
Console session:
W:\buildbot>set PATH=C:\MinGW\bin;%PATH% W:\buildbot>gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.9.3/lto-wrapper.exe Target: mingw32 Configured with: ../src/gcc-4.9.3/configure --build=x86_64-pc-linux-gnu --host=mingw32 --prefix=/mingw --disable-win32-registry --target=mingw32 --with-arch=i586 --enable-languages=c,c++,objc,obj-c++,fortran,ada --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libstdcxx-debug --with-tune=generic --enable-nls Thread model: win32 gcc version 4.9.3 (GCC) W:\buildbot>gcc lddemo.c -Wall lddemo.c: In function 'main': lddemo.c:10:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ W:\buildbot>a.exe powl(9, powl(9, 9)) = 1.189731e+4932
_mingw.h:
#define __MINGW32_VERSION 3022000L #define __MINGW32_MAJOR_VERSION 3 #define __MINGW32_MINOR_VERSION 22 #define __MINGW32_PATCHLEVEL 0
Expected output:
W:\buildbot>set PATH=C:\mingw-w64\x86_64-4.9.3\mingw64\bin;%PATH% W:\buildbot>gcc lddemo.c -Wall lddemo.c: In function 'main': lddemo.c:10:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ W:\buildbot>a.exe powl(9, powl(9, 9)) = inf
Regards,
Dan Collins
Thanks for bringing this to our attention. FWIW, the
powl()
implementation in question is a quick and dirty adaptation of Stephen Moshier's Cephes maths library implementation, (which must come close to being the most hideously ugly code I've ever seen); it looks like this bug has been inherited from the upstream source, where I see:Here,
MAXNUML
is equivalent to ISO-C'sLDBL_MAX
, which is the (incorrect) return value you are seeing; the correct return value should beHUGE_VALL
, (which corresponds to infinity).FWIW, if I modify this fragment of the upstream source:
such that it becomes:
then your test case returns the expected
inf
. I may push this intomingwrt-3.22.1
, as a Q&D resolution for this issue, but I do feel rather uncomfortable publishing such Q&D modifications to such hideously ugly code. Ideally, this requires a complete overhaul, and furthermore, I am inclined to wonder if the complexity of table lookups for base two logarithms, and their anti-logarithms, really offers any advantage over a direct computation, (perhaps even within the FPU directly, via inline assembly code), of the IEEE 754 80-bit extended precision analytical expression:(with
**
representing the exponentiation operator, as it does in FORTRAN).This particular aspect of this issue is corrected by commit [9dfbd7]; the modification is included within
mingwrt-3.22.1
. However, I am not closing the issue at this juncture, because there are other related boundary cases, for which POSIX prescribes a particular outcome for any IEC-60559 conforming implementation, (which any 8087 derivative FPU should deliver), and with which this implementation does not comply; there may be others, but in particular:Related
Commit: [9dfbd7]
As I suspected, the particular failure initially reported here is only one of many non-compliances, with the boundary condition return values prescribed by POSIX. To demonstrate the issues, I've compiled the attached set of unit tests, which may be integrated into the autotest framework I committed as [f8d4c2]; when hooked into
testsuite.at.in
immediately afterheaders.at
, and run with:it exhibits 21 failures, out of 55 unit tests run; (that's a 38% failure rate, which I don't think should be acceptable).
Related
Commit: [f8d4c2]
Last edit: Keith Marshall 2016-10-02
I've now extended the previously proposed testsuite module, to 60 unit tests, and committed it to
mingwrt
as [5b105e] ; even with the adjustment of [9dfbd7], this still exhibits the 21 POSIX compliance failures, as indicated in the attached log file.Related
Commit: [5b105e]
Commit: [9dfbd7]
For comparison, when subjected to the same 60 unit tests, Microsoft's
pow()
implementation exhibits 11 departures from POSIXly correct behaviour, (and FWIW, the equivalentwine
implementation stretches this to 21).I've now committed [ae8972], which completely replaces the old
powf()
andpowl()
implementations from Stephen Moshier's Cephes Math Library, with a pure x87 FPU implementation. This new implementation is:--a) Significantly faster than the older implementations, and
b) Passes all 60 of the specified unit tests, in respect of both functions.
Note that the Microsoft
pow()
implementation, fromMSVCRT.DLL
has not been replaced, and still fails 11 of the 60 unit tests, (21 on wine). However, the replacement implementation does includepow()
, not currently added tolibmingwex.a
, but could be included in some other supplementary extension, (or maybelibm.a
); this potential replacement does pass all 60 unit tests.Related
Commit: [ae8972]
Last edit: Keith Marshall 2016-11-21