Bug 1526507 - Use std::exp2{,f}(n) instead of pow{,f}(2.0, n) in TestFloatingPoint.cpp to be (hopefully) more resilient against standard library imprecision in the latter. r=dmajor
authorJeff Walden <jwalden@mit.edu>
Mon, 25 Mar 2019 17:54:25 +0000
changeset 466030 873caa5b3108de7853cd6bb8718d81900b9d3157
parent 466029 ec2ef453e55bcdf81104b728880c934c1b4bffc1
child 466031 6e5ccb45dbe1824c4481151a283a68d927aaa07a
push id35758
push userrgurzau@mozilla.com
push dateTue, 26 Mar 2019 09:51:47 +0000
treeherdermozilla-central@4572f6055a6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdmajor
bugs1526507
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1526507 - Use std::exp2{,f}(n) instead of pow{,f}(2.0, n) in TestFloatingPoint.cpp to be (hopefully) more resilient against standard library imprecision in the latter. r=dmajor Differential Revision: https://phabricator.services.mozilla.com/D24403
mfbt/tests/TestFloatingPoint.cpp
--- a/mfbt/tests/TestFloatingPoint.cpp
+++ b/mfbt/tests/TestFloatingPoint.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Compiler.h"
 #include "mozilla/FloatingPoint.h"
 
+#include <cmath>  // exp2
 #include <float.h>
 #include <math.h>
 
 using mozilla::ExponentComponent;
 using mozilla::FloatingPoint;
 using mozilla::FuzzyEqualsAdditive;
 using mozilla::FuzzyEqualsMultiplicative;
 using mozilla::IsFinite;
@@ -23,16 +24,18 @@ using mozilla::IsNegativeZero;
 using mozilla::IsPositiveZero;
 using mozilla::NegativeInfinity;
 using mozilla::NumberEqualsInt32;
 using mozilla::NumberIsInt32;
 using mozilla::NumbersAreIdentical;
 using mozilla::PositiveInfinity;
 using mozilla::SpecificNaN;
 using mozilla::UnspecifiedNaN;
+using std::exp2;
+using std::exp2f;
 
 #define A(a) MOZ_RELEASE_ASSERT(a)
 
 template <typename T>
 static void ShouldBeIdentical(T aD1, T aD2) {
   A(NumbersAreIdentical(aD1, aD2));
   A(NumbersAreIdentical(aD2, aD1));
 }
@@ -303,35 +306,31 @@ static void TestDoublesPredicates() {
   A(i == INT32_MIN);
   A(NumberIsInt32(double(INT32_MAX), &i));
   A(i == INT32_MAX);
   A(NumberEqualsInt32(double(INT32_MIN), &i));
   A(i == INT32_MIN);
   A(NumberEqualsInt32(double(INT32_MAX), &i));
   A(i == INT32_MAX);
 
-  // MSVC seems to compile 2**-1075, which should be half of the smallest
-  // IEEE-754 double precision value, to equal 2**-1074 right now.  This might
-  // be the result of a missing compiler flag to force more-accurate floating
-  // point calculations; bug 1440184 has been filed as a followup to fix this,
-  // so that only the first half of this condition is necessary.
-  A(pow(2.0, -1075.0) == 0.0 ||
-    (MOZ_IS_MSVC && pow(2.0, -1075.0) == pow(2.0, -1074.0)));
+  // Sanity-check that the IEEE-754 double-precision-derived literals used in
+  // testing here work as we intend them to.
+  A(exp2(-1075.0) == 0.0);
+  A(exp2(-1074.0) != 0.0);
 
-  A(pow(2.0, -1074.0) != 0.0);
-  A(!NumberIsInt32(pow(2.0, -1074.0), &i));
-  A(!NumberIsInt32(2 * pow(2.0, -1074.0), &i));
+  A(!NumberIsInt32(exp2(-1074.0), &i));
+  A(!NumberIsInt32(2 * exp2(-1074.0), &i));
   A(!NumberIsInt32(0.5, &i));
-  A(1.0 - pow(2.0, -54.0) == 1.0);
-  A(1.0 - pow(2.0, -53.0) != 1.0);
-  A(!NumberIsInt32(1.0 - pow(2.0, -53.0), &i));
-  A(!NumberIsInt32(1.0 - pow(2.0, -52.0), &i));
-  A(1.0 + pow(2.0, -53.0) == 1.0f);
-  A(1.0 + pow(2.0, -52.0) != 1.0f);
-  A(!NumberIsInt32(1.0 + pow(2.0, -52.0), &i));
+  A(1.0 - exp2(-54.0) == 1.0);
+  A(1.0 - exp2(-53.0) != 1.0);
+  A(!NumberIsInt32(1.0 - exp2(-53.0), &i));
+  A(!NumberIsInt32(1.0 - exp2(-52.0), &i));
+  A(1.0 + exp2(-53.0) == 1.0f);
+  A(1.0 + exp2(-52.0) != 1.0f);
+  A(!NumberIsInt32(1.0 + exp2(-52.0), &i));
   A(!NumberIsInt32(1.5f, &i));
   A(!NumberIsInt32(-double(2147483649), &i));
   A(!NumberIsInt32(double(2147483648), &i));
   A(!NumberIsInt32(-double(1ULL << 52) + 0.5, &i));
   A(!NumberIsInt32(double(1ULL << 52) - 0.5, &i));
   A(!NumberIsInt32(double(2147483648), &i));
   A(!NumberIsInt32(double(INT32_MAX) + 0.1, &i));
   A(!NumberIsInt32(double(INT32_MIN) - 0.1, &i));
@@ -621,55 +620,55 @@ static void TestIsFloat32Representable()
   A(IsFloat32Representable(SpecificNaN<double>(0, 71389)));
   A(IsFloat32Representable(SpecificNaN<double>(0, (uint64_t(1) << 52) - 2)));
   A(IsFloat32Representable(SpecificNaN<double>(1, 1)));
   A(IsFloat32Representable(SpecificNaN<double>(1, 71389)));
   A(IsFloat32Representable(SpecificNaN<double>(1, (uint64_t(1) << 52) - 2)));
   A(IsFloat32Representable(PositiveInfinity<double>()));
   A(IsFloat32Representable(NegativeInfinity<double>()));
 
-  // MSVC seems to compile 2**-1075, which should be half of the smallest
-  // IEEE-754 double precision value, to equal 2**-1074 right now.  This might
-  // be the result of a missing compiler flag to force more-accurate floating
-  // point calculations; bug 1440184 has been filed as a followup to fix this,
-  // so that only the first half of this condition is necessary.
-  A(pow(2.0, -1075.0) == 0.0 ||
-    (MOZ_IS_MSVC && pow(2.0, -1075.0) == pow(2.0, -1074.0)));
-
-  A(powf(2.0f, -150.0f) == 0.0);
-  A(powf(2.0f, -149.0f) != 0.0);
+  // Sanity-check that the IEEE-754 double-precision-derived literals used in
+  // testing here work as we intend them to.
+  A(exp2(-1075.0) == 0.0);
+  A(exp2(-1074.0) != 0.0);
 
   for (double littleExp = -1074.0; littleExp < -149.0; littleExp++) {
-    // Powers of two below the available range aren't representable.
-    A(!IsFloat32Representable(pow(2.0, littleExp)));
+    // Powers of two representable as doubles but not as floats aren't
+    // representable.
+    A(!IsFloat32Representable(exp2(littleExp)));
   }
 
+  // Sanity-check that the IEEE-754 single-precision-derived literals used in
+  // testing here work as we intend them to.
+  A(exp2f(-150.0f) == 0.0);
+  A(exp2f(-149.0f) != 0.0);
+
   // Exact powers of two within the available range are representable.
   for (double exponent = -149.0; exponent < 128.0; exponent++) {
-    A(IsFloat32Representable(pow(2.0, exponent)));
+    A(IsFloat32Representable(exp2(exponent)));
   }
 
   // Powers of two above the available range aren't representable.
   for (double bigExp = 128.0; bigExp < 1024.0; bigExp++) {
-    A(!IsFloat32Representable(pow(2.0, bigExp)));
+    A(!IsFloat32Representable(exp2(bigExp)));
   }
 
   // Various denormal (i.e. super-small) doubles with MSB and LSB as far apart
   // as possible are representable (but taken one bit further apart are not
   // representable).
   //
   // Note that the final iteration tests non-denormal with exponent field
   // containing (biased) 1, as |oneTooSmall| and |widestPossible| happen still
   // to be correct for that exponent due to the extra bit of precision in the
   // implicit-one bit.
-  double oneTooSmall = pow(2.0, -150.0);
+  double oneTooSmall = exp2(-150.0);
   for (double denormExp = -149.0;
        denormExp < 1 - double(FloatingPoint<double>::kExponentBias) + 1;
        denormExp++) {
-    double baseDenorm = pow(2.0, denormExp);
+    double baseDenorm = exp2(denormExp);
     double tooWide = baseDenorm + oneTooSmall;
     A(!IsFloat32Representable(tooWide));
 
     double widestPossible = baseDenorm;
     if (oneTooSmall * 2.0 != baseDenorm) {
       widestPossible += oneTooSmall * 2.0;
     }