std::remquo does not yield the proper result for the quotient
Ok. You should upgrade to GCC-9.2.0 and see if it is already fixed.
Thanks for bringing this to our attention; FWIW, I can reproduce this, cross-compiling with mingw32-gcc version 9.2.0 on GNU/Linux, and running under Wine.
It would have been helpful, (and you would have received a quicker response), if you had provided the requisite SSCCE ... your sample code was incomplete; notwithstanding, I have adapted your sample, (as you should have done):
- #include <cmath>
- #include <cstdlib>
- #include <iostream>
- extern "C" char *basename( char * );
- int main( int argc, char **argv )
- {
- if( argc != 3 )
- { std::cerr << "Usage: " << basename(*argv) << " dividend divisor" << std::endl;
- return 1;
- }
- int quotient;
- double divisor = std::strtod( argv[2], nullptr );
- double dividend = std::strtod( argv[1], nullptr );
- double remainder = std::remquo( dividend, divisor, "ient );
- std::cout << dividend << " / " << divisor << " = " << quotient
- << " remainder " << remainder << std::endl;
- return 0;
- }
$ mingw32-g++ t-remquo.cc $ ./a.exe 90.1 90.0 90.1 / 90 = 0 remainder 0.1
I understand the purpose of the fprem1 loop, at the start of the remquo() implementation, and believe that it is correct. However, I cannot make any sense, at all, of the bit-twiddling logic which follows; it seems clear that it does not do the right thing. OTOH, if I reimplement the entire remquo() function, using MPFR, that does DTRT; alternatively, adding:
into my t-remquo.cc, (below the original set of #include statements), this also appears to successfully work around the issue:
$ mingw32-g++ remquo.cc $ ./a.exe 90.1 90.0 90.1 / 90 = 1 remainder 0.1
Reply To apodtele
Ok. You should upgrade to GCC-9.2.0 and see if it is already fixed.
I agree that it would be prudent for the OP to upgrade to GCC-9.2.0. However, as I noted in my formal analysis of the issue, that isn't going to resolve this problem, because it is not a GCC issue; it is a MinGW runtime library issue, (although I don't know why GCC directs its __builtin_remquo() call to the MinGW remquo() implementation, rather than to its own MPFR-based implementation).
I've prepared the attached tentative patch, to resolve this issue; it appears to DTRT, testing under Wine with your example values, (and a few other multiples of 90.0, for the dividend).
I've also attached an updated copy of libmingwex.a, with the patch applied. Please install it, in place of your existing libmingwex.a, test, and confirm that it resolves the issue for you.
Reply To avhaecke
Context : This problem was encountered with gcc on MinGW in the following version : gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0
...
On another version of gcc (gcc 4.9.1 2014), the expected behavior is encountered.
Just to clarify: I assume that your GCC-4.9.1 is not a MinGW release? I can find no evidence of any legitimate MinGW GCC release, of that version; the only GCC-4.9.x release, which we did publish, was GCC-4.9.3, (and I assume, given the vintage of the remquo() implementation in libmingwex.a, that our GCC-4.9.3 release would have exhibited the same erroneous behaviour).
To answer Keith's question : Yes indeed, the version GCC-4.9.1 I mentioned in the original post was not a MinGW Release. It came (in 2014) from MinGW-build project as a binary package. You can still find it online on source forge with MinGW-w64 project at : https://sourceforge.net/projects/mingw-w64/files/ under : Home / Toolchains targetting Win64 / Personal Builds / mingw-builds / 4.9.1 / threads-posix/ seh I do not currently have access to the installation archive and cannot tell you more precisely which package it came from : I will be able to check next week.
Reply To keith
Reply To avhaecke
Context : This problem was encountered with gcc on MinGW in the following version : gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0
...
On another version of gcc (gcc 4.9.1 2014), the expected behavior is encountered.Just to clarify: I assume that your GCC-4.9.1 is not a MinGW release? I can find no evidence of any legitimate MinGW GCC release, of that version; the only GCC-4.9.x release, which we did publish, was GCC-4.9.3, (and I assume, given the vintage of the remquo() implementation in libmingwex.a, that our GCC-4.9.3 release would have exhibited the same erroneous behaviour).
Reply To keith
Reply To avhaecke
Context : This problem was encountered with gcc on MinGW in the following version : gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0
...
On another version of gcc (gcc 4.9.1 2014), the expected behavior is encountered.Just to clarify: I assume that your GCC-4.9.1 is not a MinGW release? I can find no evidence of any legitimate MinGW GCC release, of that version; the only GCC-4.9.x release, which we did publish, was GCC-4.9.3, (and I assume, given the vintage of the remquo() implementation in libmingwex.a, that our GCC-4.9.3 release would have exhibited the same erroneous behaviour).
Reply To keith
I've prepared the attached tentative patch, to resolve this issue; it appears to DTRT, testing under Wine with your example values, (and a few other multiples of 90.0, for the dividend). I've also attached an updated copy of libmingwex.a, with the patch applied. Please install it, in place of your existing libmingwex.a, test, and confirm that it resolves the issue for you.
Thank you for your patch (and your support).
However, I cannot link with your new libmingwex.a library as it appears to have the following symbols as Undefined (U) :
_imp____msvcrt_realloc _imp____msvcrt_free
Those 2 symbols do not appear in the libmingwex library that came from the installer. As a consequence, when I try to link with the new libmingwex.a, I get the 3 following errors :
\home\keith\builds\mingw\mingw-wsl\build\mingwrt\..\..\mingwrt\mingwex\memalign.c : 645: undefined reference to '_imp____msvcrt_free' \home\keith\builds\mingw\mingw-wsl\build\mingwrt\..\..\mingwrt\mingwex\memalign.c : 557: undefined reference to '_imp____msvcrt_realloc' \home\keith\builds\mingw\mingw-wsl\build\mingwrt\..\..\mingwrt\mingwex\memalign.c : 582: undefined reference to '_imp____msvcrt_realloc'
Reply To avhaecke
Reply To keith
I've prepared the attached tentative patch, to resolve this issue; it appears to DTRT, testing under Wine with your example values, (and a few other multiples of 90.0, for the dividend). I've also attached an updated copy of libmingwex.a, with the patch applied. Please install it, in place of your existing libmingwex.a, test, and confirm that it resolves the issue for you.
Thank you for your patch (and your support). However, I cannot link with your new libmingwex.a library as it appears to have the following symbols as Undefined (U) :
_imp____msvcrt_realloc _imp____msvcrt_freeThose 2 symbols do not appear in the libmingwex library that came from the installer.
Okay. Then your mingwrt/w32api installation is too old; did you follow apodtele's advice, and upgrade to GCC-9.2.0? In conjunction with that, you should also be using up-to-date versions of the MinGW runtime, and W32API libraries — it simply isn't practical for me to continue backporting to those versions of the same vintage as GCC-6.3.0; the attached replacement libmingwex.a is compatible with version 5.4.x runtime libraries, (and maybe also 5.3.x), but probably not with anything older.
Furthermore, if you are using a mingw-get installer which suggests that GCC-6.3.0 is the latest release, then it is still referring to the (defunct) SourceForge FRS; please refer to this mailing-list post, for advice on ensuring that you can continue to receive updates.
Reply To keith
Reply To avhaecke
Reply To keith
I've prepared the attached tentative patch, to resolve this issue; it appears to DTRT, testing under Wine with your example values, (and a few other multiples of 90.0, for the dividend). I've also attached an updated copy of libmingwex.a, with the patch applied. Please install it, in place of your existing libmingwex.a, test, and confirm that it resolves the issue for you.
Thank you for your patch (and your support). However, I cannot link with your new libmingwex.a library as it appears to have the following symbols as Undefined (U) :
{{{ _impmsvcrt_realloc _impmsvcrt_free }}}
Those 2 symbols do not appear in the libmingwex library that came from the installer.
Okay. Then your mingwrt/w32api installation is too old; did you follow apodtele's advice, and upgrade to GCC-9.2.0? In conjunction with that, you should also be using up-to-date versions of the MinGW runtime, and W32API libraries — it simply isn't practical for me to continue backporting to those versions of the same vintage as GCC-6.3.0; the attached replacement libmingwex.a is compatible with version 5.4.x runtime libraries, (and maybe also 5.3.x), but probably not with anything older. Furthermore, if you are using a mingw-get installer which suggests that GCC-6.3.0 is the latest release, then it is still referring to the (defunct) SourceForge FRS; please refer to this mailing-list post, for advice on ensuring that you can continue to receive updates.
Thank you for pointing me to the correct repository. I performed the full upgrade to GCC 9.2.0 and replaced the libmingwex.a with the one you provided. It did correct the unexpected behavior I had encountered and my specific problem i.e. quo gets the correct value after the call std::remquo(x, y, quo) when x and y are of double type.
However, I had a test program for remquo that also tested the case when x and y were "long double" rather than double and it continues to yield unexpected result with the library you provided. The program is as follows :
and I get as a result (with the new library) :
nan -2147483648
I do not know if this behavior is expected as the correction may be a partial patch but I wanted to bring it to your attention. Many thanks for your time. Alex
Reply To avhaecke
I performed the full upgrade to GCC 9.2.0 and replaced the libmingwex.a with the one you provided.
It did correct the unexpected behavior I had encountered and my specific problem i.e. quo gets the correct value after the call std::remquo(x, y, quo) when x and y are of double type. However, I had a test program for remquo that also tested the case when x and y were "long double" rather than double and it continues to yield unexpected result with the library you provided.
[...code snipped...]
and I get as a result (with the new library) :nan -2147483648I do not know if this behavior is expected as the correction may be a partial patch but I wanted to bring it to your attention.
Thanks, Alex.
Ouch! GIGO. That behaviour definitely wasn't expected, but I'd made a copy-and-paste error ... copied the remquof() preamble to remquol() but neglected to change the argument type references from DWORD to TBYTE, so the FPU was attempting to load REAL4 arguments from stack offsets within a single REAL10 value, yielding obviously invalid input.
I've fixed it, and refreshed the attached libmingwex.a. It appears to work correctly now, for me, when I change the data types from double to long double, where appropriate in my test program, (and substitute std::strtold() for std::strtod()), but I'd appreciate if you'd like to test as well. I'll update the patch, to reflect the correction, shortly.
BTW, please wrap example code in formatted text block markup, to preserve layout. The OSDN site documentation tells you how, or you can see how I've modified your posts, if you select the "edit" option.
Addendum To keith
I've fixed it, ... I'll update the patch, to reflect the correction, shortly.
Done. The difference, w.r.t. the preceding patch, is effectively:
- $ hg diff
- diff --git a/mingwrt/mingwex/math/remquo_generic.sx b/mingwrt/mingwex/math/remquo_generic.sx
- --- a/mingwrt/mingwex/math/remquo_generic.sx
- +++ b/mingwrt/mingwex/math/remquo_generic.sx
- @@ -90,12 +90,12 @@
- */
- .globl _remquol
- .def _remquol; .scl 2; .type 32; .endef
- _remquol:
- - fld DWORD ptr 4[esp] /* FPU TOS = x */
- - fld DWORD ptr 16[esp] /* FPU TOS = y, x */
- + fld TBYTE ptr 4[esp] /* FPU TOS = x */
- + fld TBYTE ptr 16[esp] /* FPU TOS = y, x */
- mov edx, DWORD ptr 28[esp] /* EDX = *q */
- /* Hand off the preloaded register set, to the shared computational
- * back-end routine, to...
- */
Reply To keith
Reply To avhaecke
I performed the full upgrade to GCC 9.2.0 and replaced the libmingwex.a with the one you provided.
It did correct the unexpected behavior I had encountered and my specific problem i.e. quo gets the correct value after the call std::remquo(x, y, quo) when x and y are of double type. However, I had a test program for remquo that also tested the case when x and y were "long double" rather than double and it continues to yield unexpected result with the library you provided.
[...code snipped...]
and I get as a result (with the new library) :nan -2147483648I do not know if this behavior is expected as the correction may be a partial patch but I wanted to bring it to your attention.Thanks, Alex.
Ouch! GIGO. That behaviour definitely wasn't expected, but I'd made a copy-and-paste error ... copied the remquof() preamble to remquol() but neglected to change the argument type references from DWORD to TBYTE, so the FPU was attempting to load REAL4 arguments from stack offsets within a single REAL10 value, yielding obviously invalid input.
I've fixed it, and refreshed the attached libmingwex.a. It appears to work correctly now, for me, when I change the data types from double to long double, where appropriate in my test program, (and substitute std::strtold() for std::strtod()), but I'd appreciate if you'd like to test as well. I'll update the patch, to reflect the correction, shortly. BTW, please wrap example code in formatted text block markup, to preserve layout. The OSDN site documentation tells you how, or you can see how I've modified your posts, if you select the "edit" option.
Thank you for your answer. I've tested your new library and indeed it works for my test cases. Everything seems fine as far as I can tell. Many thanks for your time ! Alex
PS : and sorry for all the mistakes I made in the posts !
Context : This problem was encountered with gcc on MinGW in the following version : gcc.exe (MinGW.org GCC-6.3.0-1) 6.3.0
Description :
The following code :
should yield :As is expected from std::remquo, quot has a magnitude which should be congruent (modulo 2 to the nth) to the magnitude of the integral quotient of x/y, n being greater or equal than 3.
However with gcc 6.3.0, on MinGW, the above instructions yield : result 0.1 quot 0
On another version of gcc (gcc 4.9.1 2014), the expected behavior is encountered.