diff -r 000000000000 -r 6474c204b198 mfbt/tests/TestFloatingPoint.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mfbt/tests/TestFloatingPoint.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,523 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/FloatingPoint.h" + +#include + +using mozilla::ExponentComponent; +using mozilla::FloatingPoint; +using mozilla::FuzzyEqualsAdditive; +using mozilla::FuzzyEqualsMultiplicative; +using mozilla::IsFinite; +using mozilla::IsInfinite; +using mozilla::IsNaN; +using mozilla::IsNegative; +using mozilla::IsNegativeZero; +using mozilla::NegativeInfinity; +using mozilla::NumberEqualsInt32; +using mozilla::NumberIsInt32; +using mozilla::NumbersAreIdentical; +using mozilla::PositiveInfinity; +using mozilla::SpecificNaN; +using mozilla::UnspecifiedNaN; + +template +static void +ShouldBeIdentical(T d1, T d2) +{ + MOZ_RELEASE_ASSERT(NumbersAreIdentical(d1, d2)); + MOZ_RELEASE_ASSERT(NumbersAreIdentical(d2, d1)); +} + +template +static void +ShouldNotBeIdentical(T d1, T d2) +{ + MOZ_RELEASE_ASSERT(!NumbersAreIdentical(d1, d2)); + MOZ_RELEASE_ASSERT(!NumbersAreIdentical(d2, d1)); +} + +static void +TestDoublesAreIdentical() +{ + ShouldBeIdentical(+0.0, +0.0); + ShouldBeIdentical(-0.0, -0.0); + ShouldNotBeIdentical(+0.0, -0.0); + + ShouldBeIdentical(1.0, 1.0); + ShouldNotBeIdentical(-1.0, 1.0); + ShouldBeIdentical(4294967295.0, 4294967295.0); + ShouldNotBeIdentical(-4294967295.0, 4294967295.0); + ShouldBeIdentical(4294967296.0, 4294967296.0); + ShouldBeIdentical(4294967297.0, 4294967297.0); + ShouldBeIdentical(1e300, 1e300); + + ShouldBeIdentical(PositiveInfinity(), PositiveInfinity()); + ShouldBeIdentical(NegativeInfinity(), NegativeInfinity()); + ShouldNotBeIdentical(PositiveInfinity(), NegativeInfinity()); + + ShouldNotBeIdentical(-0.0, NegativeInfinity()); + ShouldNotBeIdentical(+0.0, NegativeInfinity()); + ShouldNotBeIdentical(1e300, NegativeInfinity()); + ShouldNotBeIdentical(3.141592654, NegativeInfinity()); + + ShouldBeIdentical(UnspecifiedNaN(), UnspecifiedNaN()); + ShouldBeIdentical(-UnspecifiedNaN(), UnspecifiedNaN()); + ShouldBeIdentical(UnspecifiedNaN(), -UnspecifiedNaN()); + + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 42)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(1, 42)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(1, 42)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 42)); + + const uint64_t Mask = 0xfffffffffffffULL; + for (unsigned i = 0; i < 52; i++) { + for (unsigned j = 0; j < 52; j++) { + for (unsigned sign = 0; i < 2; i++) { + ShouldBeIdentical(SpecificNaN(0, 1ULL << i), SpecificNaN(sign, 1ULL << j)); + ShouldBeIdentical(SpecificNaN(1, 1ULL << i), SpecificNaN(sign, 1ULL << j)); + + ShouldBeIdentical(SpecificNaN(0, Mask & ~(1ULL << i)), + SpecificNaN(sign, Mask & ~(1ULL << j))); + ShouldBeIdentical(SpecificNaN(1, Mask & ~(1ULL << i)), + SpecificNaN(sign, Mask & ~(1ULL << j))); + } + } + } + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x8000000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x4000000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x2000000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x1000000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0800000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0400000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0200000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0100000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0080000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0040000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0020000000000ULL)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x0010000000000ULL)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 0xff0ffffffffffULL)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 0xfffffffffff0fULL)); + + ShouldNotBeIdentical(UnspecifiedNaN(), +0.0); + ShouldNotBeIdentical(UnspecifiedNaN(), -0.0); + ShouldNotBeIdentical(UnspecifiedNaN(), 1.0); + ShouldNotBeIdentical(UnspecifiedNaN(), -1.0); + ShouldNotBeIdentical(UnspecifiedNaN(), PositiveInfinity()); + ShouldNotBeIdentical(UnspecifiedNaN(), NegativeInfinity()); +} + +static void +TestFloatsAreIdentical() +{ + ShouldBeIdentical(+0.0f, +0.0f); + ShouldBeIdentical(-0.0f, -0.0f); + ShouldNotBeIdentical(+0.0f, -0.0f); + + ShouldBeIdentical(1.0f, 1.0f); + ShouldNotBeIdentical(-1.0f, 1.0f); + ShouldBeIdentical(8388607.0f, 8388607.0f); + ShouldNotBeIdentical(-8388607.0f, 8388607.0f); + ShouldBeIdentical(8388608.0f, 8388608.0f); + ShouldBeIdentical(8388609.0f, 8388609.0f); + ShouldBeIdentical(1e36f, 1e36f); + + ShouldBeIdentical(PositiveInfinity(), PositiveInfinity()); + ShouldBeIdentical(NegativeInfinity(), NegativeInfinity()); + ShouldNotBeIdentical(PositiveInfinity(), NegativeInfinity()); + + ShouldNotBeIdentical(-0.0f, NegativeInfinity()); + ShouldNotBeIdentical(+0.0f, NegativeInfinity()); + ShouldNotBeIdentical(1e36f, NegativeInfinity()); + ShouldNotBeIdentical(3.141592654f, NegativeInfinity()); + + ShouldBeIdentical(UnspecifiedNaN(), UnspecifiedNaN()); + ShouldBeIdentical(-UnspecifiedNaN(), UnspecifiedNaN()); + ShouldBeIdentical(UnspecifiedNaN(), -UnspecifiedNaN()); + + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 42)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(1, 42)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(1, 42)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 42)); + + const uint32_t Mask = 0x7fffffUL; + for (unsigned i = 0; i < 23; i++) { + for (unsigned j = 0; j < 23; j++) { + for (unsigned sign = 0; i < 2; i++) { + ShouldBeIdentical(SpecificNaN(0, 1UL << i), SpecificNaN(sign, 1UL << j)); + ShouldBeIdentical(SpecificNaN(1, 1UL << i), SpecificNaN(sign, 1UL << j)); + + ShouldBeIdentical(SpecificNaN(0, Mask & ~(1UL << i)), + SpecificNaN(sign, Mask & ~(1UL << j))); + ShouldBeIdentical(SpecificNaN(1, Mask & ~(1UL << i)), + SpecificNaN(sign, Mask & ~(1UL << j))); + } + } + } + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x700000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x400000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x200000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x100000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x080000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x040000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x020000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x010000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x008000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x004000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x002000)); + ShouldBeIdentical(SpecificNaN(0, 17), SpecificNaN(0, 0x001000)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 0x7f0fff)); + ShouldBeIdentical(SpecificNaN(1, 17), SpecificNaN(0, 0x7fff0f)); + + ShouldNotBeIdentical(UnspecifiedNaN(), +0.0f); + ShouldNotBeIdentical(UnspecifiedNaN(), -0.0f); + ShouldNotBeIdentical(UnspecifiedNaN(), 1.0f); + ShouldNotBeIdentical(UnspecifiedNaN(), -1.0f); + ShouldNotBeIdentical(UnspecifiedNaN(), PositiveInfinity()); + ShouldNotBeIdentical(UnspecifiedNaN(), NegativeInfinity()); +} + +static void +TestAreIdentical() +{ + TestDoublesAreIdentical(); + TestFloatsAreIdentical(); +} + +static void +TestDoubleExponentComponent() +{ + MOZ_RELEASE_ASSERT(ExponentComponent(0.0) == -int_fast16_t(FloatingPoint::ExponentBias)); + MOZ_RELEASE_ASSERT(ExponentComponent(-0.0) == -int_fast16_t(FloatingPoint::ExponentBias)); + MOZ_RELEASE_ASSERT(ExponentComponent(0.125) == -3); + MOZ_RELEASE_ASSERT(ExponentComponent(0.5) == -1); + MOZ_RELEASE_ASSERT(ExponentComponent(1.0) == 0); + MOZ_RELEASE_ASSERT(ExponentComponent(1.5) == 0); + MOZ_RELEASE_ASSERT(ExponentComponent(2.0) == 1); + MOZ_RELEASE_ASSERT(ExponentComponent(7.0) == 2); + MOZ_RELEASE_ASSERT(ExponentComponent(PositiveInfinity()) == FloatingPoint::ExponentBias + 1); + MOZ_RELEASE_ASSERT(ExponentComponent(NegativeInfinity()) == FloatingPoint::ExponentBias + 1); + MOZ_RELEASE_ASSERT(ExponentComponent(UnspecifiedNaN()) == FloatingPoint::ExponentBias + 1); +} + +static void +TestFloatExponentComponent() +{ + MOZ_RELEASE_ASSERT(ExponentComponent(0.0f) == -int_fast16_t(FloatingPoint::ExponentBias)); + MOZ_RELEASE_ASSERT(ExponentComponent(-0.0f) == -int_fast16_t(FloatingPoint::ExponentBias)); + MOZ_RELEASE_ASSERT(ExponentComponent(0.125f) == -3); + MOZ_RELEASE_ASSERT(ExponentComponent(0.5f) == -1); + MOZ_RELEASE_ASSERT(ExponentComponent(1.0f) == 0); + MOZ_RELEASE_ASSERT(ExponentComponent(1.5f) == 0); + MOZ_RELEASE_ASSERT(ExponentComponent(2.0f) == 1); + MOZ_RELEASE_ASSERT(ExponentComponent(7.0f) == 2); + MOZ_RELEASE_ASSERT(ExponentComponent(PositiveInfinity()) == FloatingPoint::ExponentBias + 1); + MOZ_RELEASE_ASSERT(ExponentComponent(NegativeInfinity()) == FloatingPoint::ExponentBias + 1); + MOZ_RELEASE_ASSERT(ExponentComponent(UnspecifiedNaN()) == FloatingPoint::ExponentBias + 1); +} + +static void +TestExponentComponent() +{ + TestDoubleExponentComponent(); + TestFloatExponentComponent(); +} + +static void +TestDoublesPredicates() +{ + MOZ_RELEASE_ASSERT(IsNaN(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsNaN(SpecificNaN(1, 17)));; + MOZ_RELEASE_ASSERT(IsNaN(SpecificNaN(0, 0xfffffffffff0fULL))); + MOZ_RELEASE_ASSERT(!IsNaN(0.0)); + MOZ_RELEASE_ASSERT(!IsNaN(-0.0)); + MOZ_RELEASE_ASSERT(!IsNaN(1.0)); + MOZ_RELEASE_ASSERT(!IsNaN(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsNaN(NegativeInfinity())); + + MOZ_RELEASE_ASSERT(IsInfinite(PositiveInfinity())); + MOZ_RELEASE_ASSERT(IsInfinite(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsInfinite(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(!IsInfinite(0.0)); + MOZ_RELEASE_ASSERT(!IsInfinite(-0.0)); + MOZ_RELEASE_ASSERT(!IsInfinite(1.0)); + + MOZ_RELEASE_ASSERT(!IsFinite(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsFinite(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsFinite(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsFinite(0.0)); + MOZ_RELEASE_ASSERT(IsFinite(-0.0)); + MOZ_RELEASE_ASSERT(IsFinite(1.0)); + + MOZ_RELEASE_ASSERT(!IsNegative(PositiveInfinity())); + MOZ_RELEASE_ASSERT(IsNegative(NegativeInfinity())); + MOZ_RELEASE_ASSERT(IsNegative(-0.0)); + MOZ_RELEASE_ASSERT(!IsNegative(0.0)); + MOZ_RELEASE_ASSERT(IsNegative(-1.0)); + MOZ_RELEASE_ASSERT(!IsNegative(1.0)); + + MOZ_RELEASE_ASSERT(!IsNegativeZero(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsNegativeZero(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(1, 17)));; + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(1, 0xfffffffffff0fULL))); + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(0, 17)));; + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(0, 0xfffffffffff0fULL))); + MOZ_RELEASE_ASSERT(!IsNegativeZero(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsNegativeZero(-0.0)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(0.0)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(-1.0)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(1.0)); + + int32_t i; + MOZ_RELEASE_ASSERT(NumberIsInt32(0.0, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(!NumberIsInt32(-0.0, &i)); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(0.0, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(-0.0, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(NumberIsInt32(double(INT32_MIN), &i)); MOZ_RELEASE_ASSERT(i == INT32_MIN); + MOZ_RELEASE_ASSERT(NumberIsInt32(double(INT32_MAX), &i)); MOZ_RELEASE_ASSERT(i == INT32_MAX); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(double(INT32_MIN), &i)); MOZ_RELEASE_ASSERT(i == INT32_MIN); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(double(INT32_MAX), &i)); MOZ_RELEASE_ASSERT(i == INT32_MAX); + MOZ_RELEASE_ASSERT(!NumberIsInt32(0.5, &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(double(INT32_MAX) + 0.1, &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(double(INT32_MIN) - 0.1, &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(NegativeInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(PositiveInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(UnspecifiedNaN(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(0.5, &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(double(INT32_MAX) + 0.1, &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(double(INT32_MIN) - 0.1, &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(NegativeInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(PositiveInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(UnspecifiedNaN(), &i)); +} + +static void +TestFloatsPredicates() +{ + MOZ_RELEASE_ASSERT(IsNaN(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsNaN(SpecificNaN(1, 17)));; + MOZ_RELEASE_ASSERT(IsNaN(SpecificNaN(0, 0x7fff0fUL))); + MOZ_RELEASE_ASSERT(!IsNaN(0.0f)); + MOZ_RELEASE_ASSERT(!IsNaN(-0.0f)); + MOZ_RELEASE_ASSERT(!IsNaN(1.0f)); + MOZ_RELEASE_ASSERT(!IsNaN(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsNaN(NegativeInfinity())); + + MOZ_RELEASE_ASSERT(IsInfinite(PositiveInfinity())); + MOZ_RELEASE_ASSERT(IsInfinite(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsInfinite(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(!IsInfinite(0.0f)); + MOZ_RELEASE_ASSERT(!IsInfinite(-0.0f)); + MOZ_RELEASE_ASSERT(!IsInfinite(1.0f)); + + MOZ_RELEASE_ASSERT(!IsFinite(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsFinite(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsFinite(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsFinite(0.0f)); + MOZ_RELEASE_ASSERT(IsFinite(-0.0f)); + MOZ_RELEASE_ASSERT(IsFinite(1.0f)); + + MOZ_RELEASE_ASSERT(!IsNegative(PositiveInfinity())); + MOZ_RELEASE_ASSERT(IsNegative(NegativeInfinity())); + MOZ_RELEASE_ASSERT(IsNegative(-0.0f)); + MOZ_RELEASE_ASSERT(!IsNegative(0.0f)); + MOZ_RELEASE_ASSERT(IsNegative(-1.0f)); + MOZ_RELEASE_ASSERT(!IsNegative(1.0f)); + + MOZ_RELEASE_ASSERT(!IsNegativeZero(PositiveInfinity())); + MOZ_RELEASE_ASSERT(!IsNegativeZero(NegativeInfinity())); + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(1, 17)));; + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(1, 0x7fff0fUL))); + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(0, 17)));; + MOZ_RELEASE_ASSERT(!IsNegativeZero(SpecificNaN(0, 0x7fff0fUL))); + MOZ_RELEASE_ASSERT(!IsNegativeZero(UnspecifiedNaN())); + MOZ_RELEASE_ASSERT(IsNegativeZero(-0.0f)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(0.0f)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(-1.0f)); + MOZ_RELEASE_ASSERT(!IsNegativeZero(1.0f)); + + int32_t i; + const int32_t BIG = 2097151; + MOZ_RELEASE_ASSERT(NumberIsInt32(0.0f, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(!NumberIsInt32(-0.0f, &i)); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(0.0f, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(-0.0f, &i)); MOZ_RELEASE_ASSERT(i == 0); + MOZ_RELEASE_ASSERT(NumberIsInt32(float(INT32_MIN), &i)); MOZ_RELEASE_ASSERT(i == INT32_MIN); + MOZ_RELEASE_ASSERT(NumberIsInt32(float(BIG), &i)); MOZ_RELEASE_ASSERT(i == BIG); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(float(INT32_MIN), &i)); MOZ_RELEASE_ASSERT(i == INT32_MIN); + MOZ_RELEASE_ASSERT(NumberEqualsInt32(float(BIG), &i)); MOZ_RELEASE_ASSERT(i == BIG); + MOZ_RELEASE_ASSERT(!NumberIsInt32(0.5f, &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(float(BIG) + 0.1f, &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(NegativeInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(PositiveInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberIsInt32(UnspecifiedNaN(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(0.5f, &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(float(BIG) + 0.1f, &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(NegativeInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(PositiveInfinity(), &i)); + MOZ_RELEASE_ASSERT(!NumberEqualsInt32(UnspecifiedNaN(), &i)); +} + +static void +TestPredicates() +{ + TestFloatsPredicates(); + TestDoublesPredicates(); +} + +static void +TestFloatsAreApproximatelyEqual() +{ + float epsilon = mozilla::detail::FuzzyEqualsEpsilon::value(); + float lessThanEpsilon = epsilon / 2.0f; + float moreThanEpsilon = epsilon * 2.0f; + + // Additive tests using the default epsilon + // ... around 1.0 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0f, 1.0f + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0f, 1.0f - lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0f, 1.0f + epsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0f, 1.0f - epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0f, 1.0f + moreThanEpsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0f, 1.0f - moreThanEpsilon)); + // ... around 1.0e2 (this is near the upper bound of the range where + // adding moreThanEpsilon will still be representable and return false) + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e2f, 1.0e2f + moreThanEpsilon)); + // ... around 1.0e-10 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + moreThanEpsilon)); + // ... straddling 0 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-6f, -1.0e-6f)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-5f, -1.0e-5f)); + // Using a small epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-9f)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-11f)); + // Using a big epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e16f)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e14f)); + + // Multiplicative tests using the default epsilon + // ... around 1.0 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0f, 1.0f + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0f, 1.0f - lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0f, 1.0f + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0f, 1.0f - epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0f, 1.0f + moreThanEpsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0f, 1.0f - moreThanEpsilon)); + // ... around 1.0e10 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (lessThanEpsilon * 1.0e10f))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (moreThanEpsilon * 1.0e10f))); + // ... around 1.0e-10 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-10f, 1.0e-10f + (lessThanEpsilon * 1.0e-10f))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-10f, 1.0e-10f + (moreThanEpsilon * 1.0e-10f))); + // ... straddling 0 + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f, 1.0e2f)); + // Using a small epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-4f)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-5f)); + // Using a big epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0f, 2.0f, 1.0f)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0f, 2.0f, 0.1f)); + + // "real world case" + float oneThird = 10.0f / 3.0f; + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(10.0f, 3.0f * oneThird)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(10.0f, 3.0f * oneThird)); + // NaN check + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(SpecificNaN(1, 1), SpecificNaN(1, 1))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(SpecificNaN(1, 2), SpecificNaN(0, 8))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(SpecificNaN(1, 1), SpecificNaN(1, 1))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(SpecificNaN(1, 2), SpecificNaN(0, 200))); +} + +static void +TestDoublesAreApproximatelyEqual() +{ + double epsilon = mozilla::detail::FuzzyEqualsEpsilon::value(); + double lessThanEpsilon = epsilon / 2.0; + double moreThanEpsilon = epsilon * 2.0; + + // Additive tests using the default epsilon + // ... around 1.0 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0, 1.0 + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0, 1.0 - lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0, 1.0 + epsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0, 1.0 - epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0, 1.0 + moreThanEpsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0, 1.0 - moreThanEpsilon)); + // ... around 1.0e4 (this is near the upper bound of the range where + // adding moreThanEpsilon will still be representable and return false) + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e4, 1.0e4 + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e4, 1.0e4 + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e4, 1.0e4 + moreThanEpsilon)); + // ... around 1.0e-25 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + moreThanEpsilon)); + // ... straddling 0 + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-13, -1.0e-13)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-12, -1.0e-12)); + // Using a small epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-29)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-31)); + // Using a big epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e26)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e24)); + + // Multiplicative tests using the default epsilon + // ... around 1.0 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0, 1.0 + lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0, 1.0 - lessThanEpsilon)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0, 1.0 + epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0, 1.0 - epsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0, 1.0 + moreThanEpsilon)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0, 1.0 - moreThanEpsilon)); + // ... around 1.0e30 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (lessThanEpsilon * 1.0e30))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (moreThanEpsilon * 1.0e30))); + // ... around 1.0e-30 + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (lessThanEpsilon * 1.0e-30))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (moreThanEpsilon * 1.0e-30))); + // ... straddling 0 + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6, 1.0e2)); + // Using a small epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-15)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-16)); + // Using a big epsilon + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 1.0)); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 0.1)); + + // "real world case" + double oneThird = 10.0 / 3.0; + MOZ_RELEASE_ASSERT(FuzzyEqualsAdditive(10.0, 3.0 * oneThird)); + MOZ_RELEASE_ASSERT(FuzzyEqualsMultiplicative(10.0, 3.0 * oneThird)); + // NaN check + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(SpecificNaN(1, 1), SpecificNaN(1, 1))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsAdditive(SpecificNaN(1, 2), SpecificNaN(0, 8))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(SpecificNaN(1, 1), SpecificNaN(1, 1))); + MOZ_RELEASE_ASSERT(!FuzzyEqualsMultiplicative(SpecificNaN(1, 2), SpecificNaN(0, 200))); +} + +static void +TestAreApproximatelyEqual() +{ + TestFloatsAreApproximatelyEqual(); + TestDoublesAreApproximatelyEqual(); +} + +int +main() +{ + TestAreIdentical(); + TestExponentComponent(); + TestPredicates(); + TestAreApproximatelyEqual(); +}