Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/mfbt/tests/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 27 kB image not shown  

Quelle  TestFloatingPoint.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/Assertions.h"
#include "mozilla/FloatingPoint.h"

#include <math.h>

using mozilla::ExponentComponent;
using mozilla::FloatingPoint;
using mozilla::FuzzyEqualsAdditive;
using mozilla::FuzzyEqualsMultiplicative;
using mozilla::IsFloat32Representable;
using mozilla::IsNegative;
using mozilla::IsNegativeZero;
using mozilla::IsPositiveZero;
using mozilla::NegativeInfinity;
using mozilla::NumberEqualsInt32;
using mozilla::NumberEqualsInt64;
using mozilla::NumberIsInt32;
using mozilla::NumberIsInt64;
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));
}

template <typename T>
static void ShouldNotBeIdentical(T aD1, T aD2) {
  A(!NumbersAreIdentical(aD1, aD2));
  A(!NumbersAreIdentical(aD2, aD1));
}

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<double>(), PositiveInfinity<double>());
  ShouldBeIdentical(NegativeInfinity<double>(), NegativeInfinity<double>());
  ShouldNotBeIdentical(PositiveInfinity<double>(), NegativeInfinity<double>());

  ShouldNotBeIdentical(-0.0, NegativeInfinity<double>());
  ShouldNotBeIdentical(+0.0, NegativeInfinity<double>());
  ShouldNotBeIdentical(1e300, NegativeInfinity<double>());
  ShouldNotBeIdentical(3.141592654, NegativeInfinity<double>());

  ShouldBeIdentical(UnspecifiedNaN<double>(), UnspecifiedNaN<double>());
  ShouldBeIdentical(-UnspecifiedNaN<double>(), UnspecifiedNaN<double>());
  ShouldBeIdentical(UnspecifiedNaN<double>(), -UnspecifiedNaN<double>());

  ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(0, 42));
  ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(1, 42));
  ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(1, 42));
  ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(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<double>(0, 1ULL << i),
                          SpecificNaN<double>(sign, 1ULL << j));
        ShouldBeIdentical(SpecificNaN<double>(1, 1ULL << i),
                          SpecificNaN<double>(sign, 1ULL << j));

        ShouldBeIdentical(SpecificNaN<double>(0, Mask & ~(1ULL << i)),
                          SpecificNaN<double>(sign, Mask & ~(1ULL << j)));
        ShouldBeIdentical(SpecificNaN<double>(1, Mask & ~(1ULL << i)),
                          SpecificNaN<double>(sign, Mask & ~(1ULL << j)));
      }
    }
  }
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x8000000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x4000000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x2000000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x1000000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0800000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0400000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0200000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0100000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0080000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0040000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0020000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(0, 17),
                    SpecificNaN<double>(0, 0x0010000000000ULL));
  ShouldBeIdentical(SpecificNaN<double>(1, 17),
                    SpecificNaN<double>(0, 0xff0ffffffffffULL));
  ShouldBeIdentical(SpecificNaN<double>(1, 17),
                    SpecificNaN<double>(0, 0xfffffffffff0fULL));

  ShouldNotBeIdentical(UnspecifiedNaN<double>(), +0.0);
  ShouldNotBeIdentical(UnspecifiedNaN<double>(), -0.0);
  ShouldNotBeIdentical(UnspecifiedNaN<double>(), 1.0);
  ShouldNotBeIdentical(UnspecifiedNaN<double>(), -1.0);
  ShouldNotBeIdentical(UnspecifiedNaN<double>(), PositiveInfinity<double>());
  ShouldNotBeIdentical(UnspecifiedNaN<double>(), NegativeInfinity<double>());
}

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<float>(), PositiveInfinity<float>());
  ShouldBeIdentical(NegativeInfinity<float>(), NegativeInfinity<float>());
  ShouldNotBeIdentical(PositiveInfinity<float>(), NegativeInfinity<float>());

  ShouldNotBeIdentical(-0.0f, NegativeInfinity<float>());
  ShouldNotBeIdentical(+0.0f, NegativeInfinity<float>());
  ShouldNotBeIdentical(1e36f, NegativeInfinity<float>());
  ShouldNotBeIdentical(3.141592654f, NegativeInfinity<float>());

  ShouldBeIdentical(UnspecifiedNaN<float>(), UnspecifiedNaN<float>());
  ShouldBeIdentical(-UnspecifiedNaN<float>(), UnspecifiedNaN<float>());
  ShouldBeIdentical(UnspecifiedNaN<float>(), -UnspecifiedNaN<float>());

  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 42));
  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(1, 42));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(1, 42));
  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(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<float>(0, 1UL << i),
                          SpecificNaN<float>(sign, 1UL << j));
        ShouldBeIdentical(SpecificNaN<float>(1, 1UL << i),
                          SpecificNaN<float>(sign, 1UL << j));

        ShouldBeIdentical(SpecificNaN<float>(0, Mask & ~(1UL << i)),
                          SpecificNaN<float>(sign, Mask & ~(1UL << j)));
        ShouldBeIdentical(SpecificNaN<float>(1, Mask & ~(1UL << i)),
                          SpecificNaN<float>(sign, Mask & ~(1UL << j)));
      }
    }
  }
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x700000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x400000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x200000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x100000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x080000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x040000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x020000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x010000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x008000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x004000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x002000));
  ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x001000));
  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7f0fff));
  ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7fff0f));

  ShouldNotBeIdentical(UnspecifiedNaN<float>(), +0.0f);
  ShouldNotBeIdentical(UnspecifiedNaN<float>(), -0.0f);
  ShouldNotBeIdentical(UnspecifiedNaN<float>(), 1.0f);
  ShouldNotBeIdentical(UnspecifiedNaN<float>(), -1.0f);
  ShouldNotBeIdentical(UnspecifiedNaN<float>(), PositiveInfinity<float>());
  ShouldNotBeIdentical(UnspecifiedNaN<float>(), NegativeInfinity<float>());
}

static void TestAreIdentical() {
  TestDoublesAreIdentical();
  TestFloatsAreIdentical();
}

static void TestDoubleExponentComponent() {
  A(ExponentComponent(0.0) ==
    -int_fast16_t(FloatingPoint<double>::kExponentBias));
  A(ExponentComponent(-0.0) ==
    -int_fast16_t(FloatingPoint<double>::kExponentBias));
  A(ExponentComponent(0.125) == -3);
  A(ExponentComponent(0.5) == -1);
  A(ExponentComponent(1.0) == 0);
  A(ExponentComponent(1.5) == 0);
  A(ExponentComponent(2.0) == 1);
  A(ExponentComponent(7.0) == 2);
  A(ExponentComponent(PositiveInfinity<double>()) ==
    FloatingPoint<double>::kExponentBias + 1);
  A(ExponentComponent(NegativeInfinity<double>()) ==
    FloatingPoint<double>::kExponentBias + 1);
  A(ExponentComponent(UnspecifiedNaN<double>()) ==
    FloatingPoint<double>::kExponentBias + 1);
}

static void TestFloatExponentComponent() {
  A(ExponentComponent(0.0f) ==
    -int_fast16_t(FloatingPoint<float>::kExponentBias));
  A(ExponentComponent(-0.0f) ==
    -int_fast16_t(FloatingPoint<float>::kExponentBias));
  A(ExponentComponent(0.125f) == -3);
  A(ExponentComponent(0.5f) == -1);
  A(ExponentComponent(1.0f) == 0);
  A(ExponentComponent(1.5f) == 0);
  A(ExponentComponent(2.0f) == 1);
  A(ExponentComponent(7.0f) == 2);
  A(ExponentComponent(PositiveInfinity<float>()) ==
    FloatingPoint<float>::kExponentBias + 1);
  A(ExponentComponent(NegativeInfinity<float>()) ==
    FloatingPoint<float>::kExponentBias + 1);
  A(ExponentComponent(UnspecifiedNaN<float>()) ==
    FloatingPoint<float>::kExponentBias + 1);
}

static void TestExponentComponent() {
  TestDoubleExponentComponent();
  TestFloatExponentComponent();
}

// Used to test Number{Is,Equals}{Int32,Int64} for -0.0, the only case where
// NumberEquals* and NumberIs* aren't equivalent.
template <typename T>
static void TestEqualsIsForNegativeZero() {
  T negZero = T(-0.0);

  int32_t i32;
  A(!NumberIsInt32(negZero, &i32));
  A(NumberEqualsInt32(negZero, &i32));
  A(i32 == 0);

  int64_t i64;
  A(!NumberIsInt64(negZero, &i64));
  A(NumberEqualsInt64(negZero, &i64));
  A(i64 == 0);
}

// Used to test Number{Is,Equals}{Int32,Int64} for int32 values.
template <typename T>
static void TestEqualsIsForInt32(T aVal) {
  int32_t i32;
  A(NumberIsInt32(aVal, &i32));
  MOZ_RELEASE_ASSERT(i32 == aVal);
  A(NumberEqualsInt32(aVal, &i32));
  MOZ_RELEASE_ASSERT(i32 == aVal);

  int64_t i64;
  A(NumberIsInt64(aVal, &i64));
  MOZ_RELEASE_ASSERT(i64 == aVal);
  A(NumberEqualsInt64(aVal, &i64));
  MOZ_RELEASE_ASSERT(i64 == aVal);
};

// Used to test Number{Is,Equals}{Int32,Int64} for values that fit in int64 but
// not int32.
template <typename T>
static void TestEqualsIsForInt64(T aVal) {
  int32_t i32;
  A(!NumberIsInt32(aVal, &i32));
  A(!NumberEqualsInt32(aVal, &i32));

  int64_t i64;
  A(NumberIsInt64(aVal, &i64));
  MOZ_RELEASE_ASSERT(i64 == aVal);
  A(NumberEqualsInt64(aVal, &i64));
  MOZ_RELEASE_ASSERT(i64 == aVal);
};

// Used to test Number{Is,Equals}{Int32,Int64} for values that aren't equal to
// any int32 or int64.
template <typename T>
static void TestEqualsIsForNonInteger(T aVal) {
  int32_t i32;
  A(!NumberIsInt32(aVal, &i32));
  A(!NumberEqualsInt32(aVal, &i32));

  int64_t i64;
  A(!NumberIsInt64(aVal, &i64));
  A(!NumberEqualsInt64(aVal, &i64));
};

static void TestDoublesPredicates() {
  A(std::isnan(UnspecifiedNaN<double>()));
  A(std::isnan(SpecificNaN<double>(1, 17)));
  ;
  A(std::isnan(SpecificNaN<double>(0, 0xfffffffffff0fULL)));
  A(!std::isnan(PositiveInfinity<double>()));
  A(!std::isnan(NegativeInfinity<double>()));

  A(std::isinf(PositiveInfinity<double>()));
  A(std::isinf(NegativeInfinity<double>()));
  A(!std::isinf(UnspecifiedNaN<double>()));

  A(!std::isfinite(PositiveInfinity<double>()));
  A(!std::isfinite(NegativeInfinity<double>()));
  A(!std::isfinite(UnspecifiedNaN<double>()));

  A(!IsNegative(PositiveInfinity<double>()));
  A(IsNegative(NegativeInfinity<double>()));
  A(IsNegative(-0.0));
  A(!IsNegative(0.0));
  A(IsNegative(-1.0));
  A(!IsNegative(1.0));

  A(!IsNegativeZero(PositiveInfinity<double>()));
  A(!IsNegativeZero(NegativeInfinity<double>()));
  A(!IsNegativeZero(SpecificNaN<double>(1, 17)));
  ;
  A(!IsNegativeZero(SpecificNaN<double>(1, 0xfffffffffff0fULL)));
  A(!IsNegativeZero(SpecificNaN<double>(0, 17)));
  ;
  A(!IsNegativeZero(SpecificNaN<double>(0, 0xfffffffffff0fULL)));
  A(!IsNegativeZero(UnspecifiedNaN<double>()));
  A(IsNegativeZero(-0.0));
  A(!IsNegativeZero(0.0));
  A(!IsNegativeZero(-1.0));
  A(!IsNegativeZero(1.0));

  // Edge case: negative zero.
  TestEqualsIsForNegativeZero<double>();

  // Int32 values.
  auto testInt32 = TestEqualsIsForInt32<double>;
  testInt32(0.0);
  testInt32(1.0);
  testInt32(INT32_MIN);
  testInt32(INT32_MAX);

  // Int64 values that don't fit in int32.
  auto testInt64 = TestEqualsIsForInt64<double>;
  testInt64(2147483648);
  testInt64(2147483649);
  testInt64(-2147483649);
  testInt64(INT64_MIN);
  // Note: INT64_MAX can't be represented exactly as double. Use a large double
  // very close to it.
  testInt64(9223372036854772000.0);

  constexpr double MinSafeInteger = -9007199254740991.0;
  constexpr double MaxSafeInteger = 9007199254740991.0;
  testInt64(MinSafeInteger);
  testInt64(MaxSafeInteger);

  // Doubles that aren't equal to any int32 or int64.
  auto testNonInteger = TestEqualsIsForNonInteger<double>;
  testNonInteger(NegativeInfinity<double>());
  testNonInteger(PositiveInfinity<double>());
  testNonInteger(UnspecifiedNaN<double>());
  testNonInteger(-double(1ULL << 52) + 0.5);
  testNonInteger(double(1ULL << 52) - 0.5);
  testNonInteger(double(INT32_MAX) + 0.1);
  testNonInteger(double(INT32_MIN) - 0.1);
  testNonInteger(0.5);
  testNonInteger(-0.0001);
  testNonInteger(-9223372036854778000.0);
  testNonInteger(9223372036854776000.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);
  testNonInteger(exp2(-1074.0));
  testNonInteger(2 * exp2(-1074.0));

  A(1.0 - exp2(-54.0) == 1.0);
  A(1.0 - exp2(-53.0) != 1.0);
  testNonInteger(1.0 - exp2(-53.0));
  testNonInteger(1.0 - exp2(-52.0));

  A(1.0 + exp2(-53.0) == 1.0f);
  A(1.0 + exp2(-52.0) != 1.0f);
  testNonInteger(1.0 + exp2(-52.0));
}

static void TestFloatsPredicates() {
  A(std::isnan(UnspecifiedNaN<float>()));
  A(std::isnan(SpecificNaN<float>(1, 17)));
  ;
  A(std::isnan(SpecificNaN<float>(0, 0x7fff0fUL)));
  A(!std::isnan(PositiveInfinity<float>()));
  A(!std::isnan(NegativeInfinity<float>()));

  A(std::isinf(PositiveInfinity<float>()));
  A(std::isinf(NegativeInfinity<float>()));
  A(!std::isinf(UnspecifiedNaN<float>()));

  A(!std::isfinite(PositiveInfinity<float>()));
  A(!std::isfinite(NegativeInfinity<float>()));
  A(!std::isfinite(UnspecifiedNaN<float>()));

  A(!IsNegative(PositiveInfinity<float>()));
  A(IsNegative(NegativeInfinity<float>()));
  A(IsNegative(-0.0f));
  A(!IsNegative(0.0f));
  A(IsNegative(-1.0f));
  A(!IsNegative(1.0f));

  A(!IsNegativeZero(PositiveInfinity<float>()));
  A(!IsNegativeZero(NegativeInfinity<float>()));
  A(!IsNegativeZero(SpecificNaN<float>(1, 17)));
  ;
  A(!IsNegativeZero(SpecificNaN<float>(1, 0x7fff0fUL)));
  A(!IsNegativeZero(SpecificNaN<float>(0, 17)));
  ;
  A(!IsNegativeZero(SpecificNaN<float>(0, 0x7fff0fUL)));
  A(!IsNegativeZero(UnspecifiedNaN<float>()));
  A(IsNegativeZero(-0.0f));
  A(!IsNegativeZero(0.0f));
  A(!IsNegativeZero(-1.0f));
  A(!IsNegativeZero(1.0f));

  A(!IsPositiveZero(PositiveInfinity<float>()));
  A(!IsPositiveZero(NegativeInfinity<float>()));
  A(!IsPositiveZero(SpecificNaN<float>(1, 17)));
  ;
  A(!IsPositiveZero(SpecificNaN<float>(1, 0x7fff0fUL)));
  A(!IsPositiveZero(SpecificNaN<float>(0, 17)));
  ;
  A(!IsPositiveZero(SpecificNaN<float>(0, 0x7fff0fUL)));
  A(!IsPositiveZero(UnspecifiedNaN<float>()));
  A(IsPositiveZero(0.0f));
  A(!IsPositiveZero(-0.0f));
  A(!IsPositiveZero(-1.0f));
  A(!IsPositiveZero(1.0f));

  // Edge case: negative zero.
  TestEqualsIsForNegativeZero<float>();

  // Int32 values.
  auto testInt32 = TestEqualsIsForInt32<float>;
  testInt32(0.0f);
  testInt32(1.0f);
  testInt32(INT32_MIN);
  testInt32(float(2147483648 - 128));  // max int32_t fitting in float
  const int32_t BIG = 2097151;
  testInt32(BIG);

  // Int64 values that don't fit in int32.
  auto testInt64 = TestEqualsIsForInt64<float>;
  testInt64(INT64_MIN);
  testInt64(9007199254740992.0f);
  testInt64(-float(2147483648) - 256);
  testInt64(float(2147483648));
  testInt64(float(2147483648) + 256);

  // Floats that aren't equal to any int32 or int64.
  auto testNonInteger = TestEqualsIsForNonInteger<float>;
  testNonInteger(NegativeInfinity<float>());
  testNonInteger(PositiveInfinity<float>());
  testNonInteger(UnspecifiedNaN<float>());
  testNonInteger(0.5f);
  testNonInteger(1.5f);
  testNonInteger(-0.0001f);
  testNonInteger(-19223373116872850000.0f);
  testNonInteger(19223373116872850000.0f);
  testNonInteger(float(BIG) + 0.1f);

  A(powf(2.0f, -150.0f) == 0.0f);
  A(powf(2.0f, -149.0f) != 0.0f);
  testNonInteger(powf(2.0f, -149.0f));
  testNonInteger(2 * powf(2.0f, -149.0f));

  A(1.0f - powf(2.0f, -25.0f) == 1.0f);
  A(1.0f - powf(2.0f, -24.0f) != 1.0f);
  testNonInteger(1.0f - powf(2.0f, -24.0f));
  testNonInteger(1.0f - powf(2.0f, -23.0f));

  A(1.0f + powf(2.0f, -24.0f) == 1.0f);
  A(1.0f + powf(2.0f, -23.0f) != 1.0f);
  testNonInteger(1.0f + powf(2.0f, -23.0f));
}

static void TestPredicates() {
  TestFloatsPredicates();
  TestDoublesPredicates();
}

static void TestFloatsAreApproximatelyEqual() {
  float epsilon = mozilla::detail::FuzzyEqualsEpsilon<float>::value();
  float lessThanEpsilon = epsilon / 2.0f;
  float moreThanEpsilon = epsilon * 2.0f;

  // Additive tests using the default epsilon
  // ... around 1.0
  A(FuzzyEqualsAdditive(1.0f, 1.0f + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0f, 1.0f - lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0f, 1.0f + epsilon));
  A(FuzzyEqualsAdditive(1.0f, 1.0f - epsilon));
  A(!FuzzyEqualsAdditive(1.0f, 1.0f + moreThanEpsilon));
  A(!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)
  A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + epsilon));
  A(!FuzzyEqualsAdditive(1.0e2f, 1.0e2f + moreThanEpsilon));
  // ... around 1.0e-10
  A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + epsilon));
  A(!FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + moreThanEpsilon));
  // ... straddling 0
  A(FuzzyEqualsAdditive(1.0e-6f, -1.0e-6f));
  A(!FuzzyEqualsAdditive(1.0e-5f, -1.0e-5f));
  // Using a small epsilon
  A(FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-9f));
  A(!FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-11f));
  // Using a big epsilon
  A(FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e16f));
  A(!FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e14f));

  // Multiplicative tests using the default epsilon
  // ... around 1.0
  A(FuzzyEqualsMultiplicative(1.0f, 1.0f + lessThanEpsilon));
  A(FuzzyEqualsMultiplicative(1.0f, 1.0f - lessThanEpsilon));
  A(FuzzyEqualsMultiplicative(1.0f, 1.0f + epsilon));
  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - epsilon));
  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f + moreThanEpsilon));
  A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - moreThanEpsilon));
  // ... around 1.0e10
  A(FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (lessThanEpsilon * 1.0e10f)));
  A(!FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (moreThanEpsilon * 1.0e10f)));
  // ... around 1.0e-10
  A(FuzzyEqualsMultiplicative(1.0e-10f,
                              1.0e-10f + (lessThanEpsilon * 1.0e-10f)));
  A(!FuzzyEqualsMultiplicative(1.0e-10f,
                               1.0e-10f + (moreThanEpsilon * 1.0e-10f)));
  // ... straddling 0
  A(!FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f));
  A(FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f, 1.0e2f));
  // Using a small epsilon
  A(FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-4f));
  A(!FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-5f));
  // Using a big epsilon
  A(FuzzyEqualsMultiplicative(1.0f, 2.0f, 1.0f));
  A(!FuzzyEqualsMultiplicative(1.0f, 2.0f, 0.1f));

  // "real world case"
  float oneThird = 10.0f / 3.0f;
  A(FuzzyEqualsAdditive(10.0f, 3.0f * oneThird));
  A(FuzzyEqualsMultiplicative(10.0f, 3.0f * oneThird));
  // NaN check
  A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 1), SpecificNaN<float>(1, 1)));
  A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 2), SpecificNaN<float>(0, 8)));
  A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 1),
                               SpecificNaN<float>(1, 1)));
  A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 2),
                               SpecificNaN<float>(0, 200)));
}

static void TestDoublesAreApproximatelyEqual() {
  double epsilon = mozilla::detail::FuzzyEqualsEpsilon<double>::value();
  double lessThanEpsilon = epsilon / 2.0;
  double moreThanEpsilon = epsilon * 2.0;

  // Additive tests using the default epsilon
  // ... around 1.0
  A(FuzzyEqualsAdditive(1.0, 1.0 + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0, 1.0 - lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0, 1.0 + epsilon));
  A(FuzzyEqualsAdditive(1.0, 1.0 - epsilon));
  A(!FuzzyEqualsAdditive(1.0, 1.0 + moreThanEpsilon));
  A(!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)
  A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + epsilon));
  A(!FuzzyEqualsAdditive(1.0e4, 1.0e4 + moreThanEpsilon));
  // ... around 1.0e-25
  A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + lessThanEpsilon));
  A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + epsilon));
  A(!FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + moreThanEpsilon));
  // ... straddling 0
  A(FuzzyEqualsAdditive(1.0e-13, -1.0e-13));
  A(!FuzzyEqualsAdditive(1.0e-12, -1.0e-12));
  // Using a small epsilon
  A(FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-29));
  A(!FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-31));
  // Using a big epsilon
  A(FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e26));
  A(!FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e24));

  // Multiplicative tests using the default epsilon
  // ... around 1.0
  A(FuzzyEqualsMultiplicative(1.0, 1.0 + lessThanEpsilon));
  A(FuzzyEqualsMultiplicative(1.0, 1.0 - lessThanEpsilon));
  A(FuzzyEqualsMultiplicative(1.0, 1.0 + epsilon));
  A(!FuzzyEqualsMultiplicative(1.0, 1.0 - epsilon));
  A(!FuzzyEqualsMultiplicative(1.0, 1.0 + moreThanEpsilon));
  A(!FuzzyEqualsMultiplicative(1.0, 1.0 - moreThanEpsilon));
  // ... around 1.0e30
  A(FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (lessThanEpsilon * 1.0e30)));
  A(!FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (moreThanEpsilon * 1.0e30)));
  // ... around 1.0e-30
  A(FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (lessThanEpsilon * 1.0e-30)));
  A(!FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (moreThanEpsilon * 1.0e-30)));
  // ... straddling 0
  A(!FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6));
  A(FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6, 1.0e2));
  // Using a small epsilon
  A(FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-15));
  A(!FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-16));
  // Using a big epsilon
  A(FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 1.0));
  A(!FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 0.1));

  // "real world case"
  double oneThird = 10.0 / 3.0;
  A(FuzzyEqualsAdditive(10.0, 3.0 * oneThird));
  A(FuzzyEqualsMultiplicative(10.0, 3.0 * oneThird));
  // NaN check
  A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 1), SpecificNaN<double>(1, 1)));
  A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 2), SpecificNaN<double>(0, 8)));
  A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 1),
                               SpecificNaN<double>(1, 1)));
  A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 2),
                               SpecificNaN<double>(0, 200)));
}

static void TestAreApproximatelyEqual() {
  TestFloatsAreApproximatelyEqual();
  TestDoublesAreApproximatelyEqual();
}

static void TestIsFloat32Representable() {
  // Zeroes are representable.
  A(IsFloat32Representable(+0.0));
  A(IsFloat32Representable(-0.0));

  // NaN and infinities are representable.
  A(IsFloat32Representable(UnspecifiedNaN<double>()));
  A(IsFloat32Representable(SpecificNaN<double>(0, 1)));
  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>()));

  // 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 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(exp2(exponent)));
  }

  // Powers of two above the available range aren't representable.
  for (double bigExp = 128.0; bigExp < 1024.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 = exp2(-150.0);
  for (double denormExp = -149.0;
       denormExp < 1 - double(FloatingPoint<double>::kExponentBias) + 1;
       denormExp++) {
    double baseDenorm = exp2(denormExp);
    double tooWide = baseDenorm + oneTooSmall;
    A(!IsFloat32Representable(tooWide));

    double widestPossible = baseDenorm;
    if (oneTooSmall * 2.0 != baseDenorm) {
      widestPossible += oneTooSmall * 2.0;
    }

    A(IsFloat32Representable(widestPossible));
  }

  // Finally, check certain interesting/special values for basic sanity.
  A(!IsFloat32Representable(2147483647.0));
  A(!IsFloat32Representable(-2147483647.0));
}

#undef A

int main() {
  TestAreIdentical();
  TestExponentComponent();
  TestPredicates();
  TestAreApproximatelyEqual();
  TestIsFloat32Representable();
  return 0;
}

Messung V0.5
C=93 H=90 G=91

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.