Patchwork Fix PR C++/54036, problem negating DFP NaNs

login
register
mail settings
Submitter Peter Bergner
Date July 19, 2012, 9:46 p.m.
Message ID <20120719164607.0d1ffd1f03762f7f3bb5bf21@vnet.ibm.com>
Download mbox | patch
Permalink /patch/172084/
State New
Headers show

Comments

Peter Bergner - July 19, 2012, 9:46 p.m.
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.

Patch

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;
+}
+