When negating a DFP NaN in C++, we produce another NaN and not a -NaN like we do when using a C test case or with binary floating point (C or C++). This happens on both my power64-linux and x86_64-linux systems.
bergner@bns:~> cat dfp-nan.C #include <stdio.h> #include <decimal/decimal> using namespace std; decimal::decimal64 my_nan (void) { decimal::decimal64 z = 0.0DD; decimal::decimal64 v = z/z; return v; } int main (void) { decimal::decimal64 v; v = my_nan (); printf ("value is %Dg\n", v); v = -v; printf ("-value is %Dg\n", v); return 0; } bergner@bns:~> g++ dfp-nan.C -ldfp bergner@bns:~> ./a.out value is nan -value is nan The problem is that the decimal class implementing unary operators uses binary operations, so a -nan is computed with a "0 - nan" which does not produce a -nan. The patch below fixes the problem for me and passes bootstrap and regtesting on powerpc64-linux. Ok for mainline? The same problem exists in 4.7 and 4.6, is this patch ok for the release branches too assuming my testing there passes without problems? Peter libstdc++-v3/ PR c++/54036 * include/decimal/decimal.h (_DEFINE_DECIMAL_UNARY_OP): Use _Op as a unary operator. gcc/testsuite/ PR c++/54036 * g++.dg/dfp/pr54036-1.C: New test. * g++.dg/dfp/pr54036-2.C: Likewise. * g++.dg/dfp/pr54036-3.C: Likewise. Index: libstdc++-v3/include/decimal/decimal.h =================================================================== --- libstdc++-v3/include/decimal/decimal.h (revision 189599) +++ libstdc++-v3/include/decimal/decimal.h (working copy) @@ -288,7 +288,7 @@ inline _Tp operator _Op(_Tp __rhs) \ { \ _Tp __tmp; \ - __tmp.__setval(0 _Op __rhs.__getval()); \ + __tmp.__setval(_Op __rhs.__getval()); \ return __tmp; \ } Index: gcc/testsuite/g++.dg/dfp/pr54036-1.C =================================================================== --- gcc/testsuite/g++.dg/dfp/pr54036-1.C (revision 0) +++ gcc/testsuite/g++.dg/dfp/pr54036-1.C (revision 0) @@ -0,0 +1,56 @@ +#include <decimal/decimal> +using namespace std; + +decimal::decimal32 +__attribute__ ((noinline)) +my_nan32 (void) +{ + decimal::decimal32 z = 0; + decimal::decimal32 v = z/z; + return v; +} + +decimal::decimal32 +__attribute__ ((noinline)) +my_inf32 (void) +{ + decimal::decimal32 o = 1; + decimal::decimal32 z = 0; + decimal::decimal32 v = o/z; + return v; +} + +int +main (void) +{ + decimal::decimal32 v; + + v = my_nan32 (); + if (!__builtin_isnand32 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd32 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isnand32 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd32 (v.__getval ())) + __builtin_abort (); + + v = my_inf32 (); + if (!__builtin_isinfd32 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd32 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isinfd32 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd32 (v.__getval ())) + __builtin_abort (); + + return 0; +} + Index: gcc/testsuite/g++.dg/dfp/pr54036-2.C =================================================================== --- gcc/testsuite/g++.dg/dfp/pr54036-2.C (revision 0) +++ gcc/testsuite/g++.dg/dfp/pr54036-2.C (revision 0) @@ -0,0 +1,56 @@ +#include <decimal/decimal> +using namespace std; + +decimal::decimal64 +__attribute__ ((noinline)) +my_nan64 (void) +{ + decimal::decimal64 z = 0; + decimal::decimal64 v = z/z; + return v; +} + +decimal::decimal64 +__attribute__ ((noinline)) +my_inf64 (void) +{ + decimal::decimal64 o = 1; + decimal::decimal64 z = 0; + decimal::decimal64 v = o/z; + return v; +} + +int +main (void) +{ + decimal::decimal64 v; + + v = my_nan64 (); + if (!__builtin_isnand64 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd64 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isnand64 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd64 (v.__getval ())) + __builtin_abort (); + + v = my_inf64 (); + if (!__builtin_isinfd64 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd64 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isinfd64 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd64 (v.__getval ())) + __builtin_abort (); + + return 0; +} + Index: gcc/testsuite/g++.dg/dfp/pr54036-3.C =================================================================== --- gcc/testsuite/g++.dg/dfp/pr54036-3.C (revision 0) +++ gcc/testsuite/g++.dg/dfp/pr54036-3.C (revision 0) @@ -0,0 +1,56 @@ +#include <decimal/decimal> +using namespace std; + +decimal::decimal128 +__attribute__ ((noinline)) +my_nan128 (void) +{ + decimal::decimal128 z = 0; + decimal::decimal128 v = z/z; + return v; +} + +decimal::decimal128 +__attribute__ ((noinline)) +my_inf128 (void) +{ + decimal::decimal128 o = 1; + decimal::decimal128 z = 0; + decimal::decimal128 v = o/z; + return v; +} + +int +main (void) +{ + decimal::decimal128 v; + + v = my_nan128 (); + if (!__builtin_isnand128 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd128 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isnand128 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd128 (v.__getval ())) + __builtin_abort (); + + v = my_inf128 (); + if (!__builtin_isinfd128 (v.__getval ())) + __builtin_abort (); + if (__builtin_signbitd128 (v.__getval ())) + __builtin_abort (); + + v = -v; + + if (!__builtin_isinfd128 (v.__getval ())) + __builtin_abort (); + if (!__builtin_signbitd128 (v.__getval ())) + __builtin_abort (); + + return 0; +} +