TestFloatingPoint.cpp (28438B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/Assertions.h" 8 #include "mozilla/FloatingPoint.h" 9 10 #include <math.h> 11 12 using mozilla::ExponentComponent; 13 using mozilla::FloatingPoint; 14 using mozilla::FuzzyEqualsAdditive; 15 using mozilla::FuzzyEqualsMultiplicative; 16 using mozilla::IsFloat32Representable; 17 using mozilla::IsNegative; 18 using mozilla::IsNegativeZero; 19 using mozilla::IsPositiveZero; 20 using mozilla::NegativeInfinity; 21 using mozilla::NumberEqualsInt32; 22 using mozilla::NumberEqualsInt64; 23 using mozilla::NumberIsInt32; 24 using mozilla::NumberIsInt64; 25 using mozilla::NumbersAreIdentical; 26 using mozilla::PositiveInfinity; 27 using mozilla::SpecificNaN; 28 using mozilla::UnspecifiedNaN; 29 using std::exp2; 30 using std::exp2f; 31 32 #define A(a) MOZ_RELEASE_ASSERT(a) 33 34 template <typename T> 35 static void ShouldBeIdentical(T aD1, T aD2) { 36 A(NumbersAreIdentical(aD1, aD2)); 37 A(NumbersAreIdentical(aD2, aD1)); 38 } 39 40 template <typename T> 41 static void ShouldNotBeIdentical(T aD1, T aD2) { 42 A(!NumbersAreIdentical(aD1, aD2)); 43 A(!NumbersAreIdentical(aD2, aD1)); 44 } 45 46 static void TestDoublesAreIdentical() { 47 ShouldBeIdentical(+0.0, +0.0); 48 ShouldBeIdentical(-0.0, -0.0); 49 ShouldNotBeIdentical(+0.0, -0.0); 50 51 ShouldBeIdentical(1.0, 1.0); 52 ShouldNotBeIdentical(-1.0, 1.0); 53 ShouldBeIdentical(4294967295.0, 4294967295.0); 54 ShouldNotBeIdentical(-4294967295.0, 4294967295.0); 55 ShouldBeIdentical(4294967296.0, 4294967296.0); 56 ShouldBeIdentical(4294967297.0, 4294967297.0); 57 ShouldBeIdentical(1e300, 1e300); 58 59 ShouldBeIdentical(PositiveInfinity<double>(), PositiveInfinity<double>()); 60 ShouldBeIdentical(NegativeInfinity<double>(), NegativeInfinity<double>()); 61 ShouldNotBeIdentical(PositiveInfinity<double>(), NegativeInfinity<double>()); 62 63 ShouldNotBeIdentical(-0.0, NegativeInfinity<double>()); 64 ShouldNotBeIdentical(+0.0, NegativeInfinity<double>()); 65 ShouldNotBeIdentical(1e300, NegativeInfinity<double>()); 66 ShouldNotBeIdentical(3.141592654, NegativeInfinity<double>()); 67 68 ShouldBeIdentical(UnspecifiedNaN<double>(), UnspecifiedNaN<double>()); 69 ShouldBeIdentical(-UnspecifiedNaN<double>(), UnspecifiedNaN<double>()); 70 ShouldBeIdentical(UnspecifiedNaN<double>(), -UnspecifiedNaN<double>()); 71 72 ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(0, 42)); 73 ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(1, 42)); 74 ShouldBeIdentical(SpecificNaN<double>(0, 17), SpecificNaN<double>(1, 42)); 75 ShouldBeIdentical(SpecificNaN<double>(1, 17), SpecificNaN<double>(0, 42)); 76 77 const uint64_t Mask = 0xfffffffffffffULL; 78 for (unsigned i = 0; i < 52; i++) { 79 for (unsigned j = 0; j < 52; j++) { 80 for (unsigned sign = 0; i < 2; i++) { 81 ShouldBeIdentical(SpecificNaN<double>(0, 1ULL << i), 82 SpecificNaN<double>(sign, 1ULL << j)); 83 ShouldBeIdentical(SpecificNaN<double>(1, 1ULL << i), 84 SpecificNaN<double>(sign, 1ULL << j)); 85 86 ShouldBeIdentical(SpecificNaN<double>(0, Mask & ~(1ULL << i)), 87 SpecificNaN<double>(sign, Mask & ~(1ULL << j))); 88 ShouldBeIdentical(SpecificNaN<double>(1, Mask & ~(1ULL << i)), 89 SpecificNaN<double>(sign, Mask & ~(1ULL << j))); 90 } 91 } 92 } 93 ShouldBeIdentical(SpecificNaN<double>(0, 17), 94 SpecificNaN<double>(0, 0x8000000000000ULL)); 95 ShouldBeIdentical(SpecificNaN<double>(0, 17), 96 SpecificNaN<double>(0, 0x4000000000000ULL)); 97 ShouldBeIdentical(SpecificNaN<double>(0, 17), 98 SpecificNaN<double>(0, 0x2000000000000ULL)); 99 ShouldBeIdentical(SpecificNaN<double>(0, 17), 100 SpecificNaN<double>(0, 0x1000000000000ULL)); 101 ShouldBeIdentical(SpecificNaN<double>(0, 17), 102 SpecificNaN<double>(0, 0x0800000000000ULL)); 103 ShouldBeIdentical(SpecificNaN<double>(0, 17), 104 SpecificNaN<double>(0, 0x0400000000000ULL)); 105 ShouldBeIdentical(SpecificNaN<double>(0, 17), 106 SpecificNaN<double>(0, 0x0200000000000ULL)); 107 ShouldBeIdentical(SpecificNaN<double>(0, 17), 108 SpecificNaN<double>(0, 0x0100000000000ULL)); 109 ShouldBeIdentical(SpecificNaN<double>(0, 17), 110 SpecificNaN<double>(0, 0x0080000000000ULL)); 111 ShouldBeIdentical(SpecificNaN<double>(0, 17), 112 SpecificNaN<double>(0, 0x0040000000000ULL)); 113 ShouldBeIdentical(SpecificNaN<double>(0, 17), 114 SpecificNaN<double>(0, 0x0020000000000ULL)); 115 ShouldBeIdentical(SpecificNaN<double>(0, 17), 116 SpecificNaN<double>(0, 0x0010000000000ULL)); 117 ShouldBeIdentical(SpecificNaN<double>(1, 17), 118 SpecificNaN<double>(0, 0xff0ffffffffffULL)); 119 ShouldBeIdentical(SpecificNaN<double>(1, 17), 120 SpecificNaN<double>(0, 0xfffffffffff0fULL)); 121 122 ShouldNotBeIdentical(UnspecifiedNaN<double>(), +0.0); 123 ShouldNotBeIdentical(UnspecifiedNaN<double>(), -0.0); 124 ShouldNotBeIdentical(UnspecifiedNaN<double>(), 1.0); 125 ShouldNotBeIdentical(UnspecifiedNaN<double>(), -1.0); 126 ShouldNotBeIdentical(UnspecifiedNaN<double>(), PositiveInfinity<double>()); 127 ShouldNotBeIdentical(UnspecifiedNaN<double>(), NegativeInfinity<double>()); 128 } 129 130 static void TestFloatsAreIdentical() { 131 ShouldBeIdentical(+0.0f, +0.0f); 132 ShouldBeIdentical(-0.0f, -0.0f); 133 ShouldNotBeIdentical(+0.0f, -0.0f); 134 135 ShouldBeIdentical(1.0f, 1.0f); 136 ShouldNotBeIdentical(-1.0f, 1.0f); 137 ShouldBeIdentical(8388607.0f, 8388607.0f); 138 ShouldNotBeIdentical(-8388607.0f, 8388607.0f); 139 ShouldBeIdentical(8388608.0f, 8388608.0f); 140 ShouldBeIdentical(8388609.0f, 8388609.0f); 141 ShouldBeIdentical(1e36f, 1e36f); 142 143 ShouldBeIdentical(PositiveInfinity<float>(), PositiveInfinity<float>()); 144 ShouldBeIdentical(NegativeInfinity<float>(), NegativeInfinity<float>()); 145 ShouldNotBeIdentical(PositiveInfinity<float>(), NegativeInfinity<float>()); 146 147 ShouldNotBeIdentical(-0.0f, NegativeInfinity<float>()); 148 ShouldNotBeIdentical(+0.0f, NegativeInfinity<float>()); 149 ShouldNotBeIdentical(1e36f, NegativeInfinity<float>()); 150 ShouldNotBeIdentical(3.141592654f, NegativeInfinity<float>()); 151 152 ShouldBeIdentical(UnspecifiedNaN<float>(), UnspecifiedNaN<float>()); 153 ShouldBeIdentical(-UnspecifiedNaN<float>(), UnspecifiedNaN<float>()); 154 ShouldBeIdentical(UnspecifiedNaN<float>(), -UnspecifiedNaN<float>()); 155 156 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 42)); 157 ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(1, 42)); 158 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(1, 42)); 159 ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 42)); 160 161 const uint32_t Mask = 0x7fffffUL; 162 for (unsigned i = 0; i < 23; i++) { 163 for (unsigned j = 0; j < 23; j++) { 164 for (unsigned sign = 0; i < 2; i++) { 165 ShouldBeIdentical(SpecificNaN<float>(0, 1UL << i), 166 SpecificNaN<float>(sign, 1UL << j)); 167 ShouldBeIdentical(SpecificNaN<float>(1, 1UL << i), 168 SpecificNaN<float>(sign, 1UL << j)); 169 170 ShouldBeIdentical(SpecificNaN<float>(0, Mask & ~(1UL << i)), 171 SpecificNaN<float>(sign, Mask & ~(1UL << j))); 172 ShouldBeIdentical(SpecificNaN<float>(1, Mask & ~(1UL << i)), 173 SpecificNaN<float>(sign, Mask & ~(1UL << j))); 174 } 175 } 176 } 177 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x700000)); 178 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x400000)); 179 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x200000)); 180 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x100000)); 181 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x080000)); 182 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x040000)); 183 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x020000)); 184 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x010000)); 185 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x008000)); 186 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x004000)); 187 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x002000)); 188 ShouldBeIdentical(SpecificNaN<float>(0, 17), SpecificNaN<float>(0, 0x001000)); 189 ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7f0fff)); 190 ShouldBeIdentical(SpecificNaN<float>(1, 17), SpecificNaN<float>(0, 0x7fff0f)); 191 192 ShouldNotBeIdentical(UnspecifiedNaN<float>(), +0.0f); 193 ShouldNotBeIdentical(UnspecifiedNaN<float>(), -0.0f); 194 ShouldNotBeIdentical(UnspecifiedNaN<float>(), 1.0f); 195 ShouldNotBeIdentical(UnspecifiedNaN<float>(), -1.0f); 196 ShouldNotBeIdentical(UnspecifiedNaN<float>(), PositiveInfinity<float>()); 197 ShouldNotBeIdentical(UnspecifiedNaN<float>(), NegativeInfinity<float>()); 198 } 199 200 static void TestAreIdentical() { 201 TestDoublesAreIdentical(); 202 TestFloatsAreIdentical(); 203 } 204 205 static void TestDoubleExponentComponent() { 206 A(ExponentComponent(0.0) == 207 -int_fast16_t(FloatingPoint<double>::kExponentBias)); 208 A(ExponentComponent(-0.0) == 209 -int_fast16_t(FloatingPoint<double>::kExponentBias)); 210 A(ExponentComponent(0.125) == -3); 211 A(ExponentComponent(0.5) == -1); 212 A(ExponentComponent(1.0) == 0); 213 A(ExponentComponent(1.5) == 0); 214 A(ExponentComponent(2.0) == 1); 215 A(ExponentComponent(7.0) == 2); 216 A(ExponentComponent(PositiveInfinity<double>()) == 217 FloatingPoint<double>::kExponentBias + 1); 218 A(ExponentComponent(NegativeInfinity<double>()) == 219 FloatingPoint<double>::kExponentBias + 1); 220 A(ExponentComponent(UnspecifiedNaN<double>()) == 221 FloatingPoint<double>::kExponentBias + 1); 222 } 223 224 static void TestFloatExponentComponent() { 225 A(ExponentComponent(0.0f) == 226 -int_fast16_t(FloatingPoint<float>::kExponentBias)); 227 A(ExponentComponent(-0.0f) == 228 -int_fast16_t(FloatingPoint<float>::kExponentBias)); 229 A(ExponentComponent(0.125f) == -3); 230 A(ExponentComponent(0.5f) == -1); 231 A(ExponentComponent(1.0f) == 0); 232 A(ExponentComponent(1.5f) == 0); 233 A(ExponentComponent(2.0f) == 1); 234 A(ExponentComponent(7.0f) == 2); 235 A(ExponentComponent(PositiveInfinity<float>()) == 236 FloatingPoint<float>::kExponentBias + 1); 237 A(ExponentComponent(NegativeInfinity<float>()) == 238 FloatingPoint<float>::kExponentBias + 1); 239 A(ExponentComponent(UnspecifiedNaN<float>()) == 240 FloatingPoint<float>::kExponentBias + 1); 241 } 242 243 static void TestExponentComponent() { 244 TestDoubleExponentComponent(); 245 TestFloatExponentComponent(); 246 } 247 248 // Used to test Number{Is,Equals}{Int32,Int64} for -0.0, the only case where 249 // NumberEquals* and NumberIs* aren't equivalent. 250 template <typename T> 251 static void TestEqualsIsForNegativeZero() { 252 T negZero = T(-0.0); 253 254 int32_t i32; 255 A(!NumberIsInt32(negZero, &i32)); 256 A(NumberEqualsInt32(negZero, &i32)); 257 A(i32 == 0); 258 259 int64_t i64; 260 A(!NumberIsInt64(negZero, &i64)); 261 A(NumberEqualsInt64(negZero, &i64)); 262 A(i64 == 0); 263 } 264 265 // Used to test Number{Is,Equals}{Int32,Int64} for int32 values. 266 template <typename T> 267 static void TestEqualsIsForInt32(T aVal) { 268 int32_t i32; 269 A(NumberIsInt32(aVal, &i32)); 270 MOZ_RELEASE_ASSERT(i32 == aVal); 271 A(NumberEqualsInt32(aVal, &i32)); 272 MOZ_RELEASE_ASSERT(i32 == aVal); 273 274 int64_t i64; 275 A(NumberIsInt64(aVal, &i64)); 276 MOZ_RELEASE_ASSERT(i64 == aVal); 277 A(NumberEqualsInt64(aVal, &i64)); 278 MOZ_RELEASE_ASSERT(i64 == aVal); 279 }; 280 281 // Used to test Number{Is,Equals}{Int32,Int64} for values that fit in int64 but 282 // not int32. 283 template <typename T> 284 static void TestEqualsIsForInt64(T aVal) { 285 int32_t i32; 286 A(!NumberIsInt32(aVal, &i32)); 287 A(!NumberEqualsInt32(aVal, &i32)); 288 289 int64_t i64; 290 A(NumberIsInt64(aVal, &i64)); 291 MOZ_RELEASE_ASSERT(i64 == aVal); 292 A(NumberEqualsInt64(aVal, &i64)); 293 MOZ_RELEASE_ASSERT(i64 == aVal); 294 }; 295 296 // Used to test Number{Is,Equals}{Int32,Int64} for values that aren't equal to 297 // any int32 or int64. 298 template <typename T> 299 static void TestEqualsIsForNonInteger(T aVal) { 300 int32_t i32; 301 A(!NumberIsInt32(aVal, &i32)); 302 A(!NumberEqualsInt32(aVal, &i32)); 303 304 int64_t i64; 305 A(!NumberIsInt64(aVal, &i64)); 306 A(!NumberEqualsInt64(aVal, &i64)); 307 }; 308 309 static void TestDoublesPredicates() { 310 A(std::isnan(UnspecifiedNaN<double>())); 311 A(std::isnan(SpecificNaN<double>(1, 17))); 312 ; 313 A(std::isnan(SpecificNaN<double>(0, 0xfffffffffff0fULL))); 314 A(!std::isnan(PositiveInfinity<double>())); 315 A(!std::isnan(NegativeInfinity<double>())); 316 317 A(std::isinf(PositiveInfinity<double>())); 318 A(std::isinf(NegativeInfinity<double>())); 319 A(!std::isinf(UnspecifiedNaN<double>())); 320 321 A(!std::isfinite(PositiveInfinity<double>())); 322 A(!std::isfinite(NegativeInfinity<double>())); 323 A(!std::isfinite(UnspecifiedNaN<double>())); 324 325 A(!IsNegative(PositiveInfinity<double>())); 326 A(IsNegative(NegativeInfinity<double>())); 327 A(IsNegative(-0.0)); 328 A(!IsNegative(0.0)); 329 A(IsNegative(-1.0)); 330 A(!IsNegative(1.0)); 331 332 A(!IsNegativeZero(PositiveInfinity<double>())); 333 A(!IsNegativeZero(NegativeInfinity<double>())); 334 A(!IsNegativeZero(SpecificNaN<double>(1, 17))); 335 ; 336 A(!IsNegativeZero(SpecificNaN<double>(1, 0xfffffffffff0fULL))); 337 A(!IsNegativeZero(SpecificNaN<double>(0, 17))); 338 ; 339 A(!IsNegativeZero(SpecificNaN<double>(0, 0xfffffffffff0fULL))); 340 A(!IsNegativeZero(UnspecifiedNaN<double>())); 341 A(IsNegativeZero(-0.0)); 342 A(!IsNegativeZero(0.0)); 343 A(!IsNegativeZero(-1.0)); 344 A(!IsNegativeZero(1.0)); 345 346 // Edge case: negative zero. 347 TestEqualsIsForNegativeZero<double>(); 348 349 // Int32 values. 350 auto testInt32 = TestEqualsIsForInt32<double>; 351 testInt32(0.0); 352 testInt32(1.0); 353 testInt32(INT32_MIN); 354 testInt32(INT32_MAX); 355 356 // Int64 values that don't fit in int32. 357 auto testInt64 = TestEqualsIsForInt64<double>; 358 testInt64(2147483648); 359 testInt64(2147483649); 360 testInt64(-2147483649); 361 testInt64(INT64_MIN); 362 // Note: INT64_MAX can't be represented exactly as double. Use a large double 363 // very close to it. 364 testInt64(9223372036854772000.0); 365 366 constexpr double MinSafeInteger = -9007199254740991.0; 367 constexpr double MaxSafeInteger = 9007199254740991.0; 368 testInt64(MinSafeInteger); 369 testInt64(MaxSafeInteger); 370 371 // Doubles that aren't equal to any int32 or int64. 372 auto testNonInteger = TestEqualsIsForNonInteger<double>; 373 testNonInteger(NegativeInfinity<double>()); 374 testNonInteger(PositiveInfinity<double>()); 375 testNonInteger(UnspecifiedNaN<double>()); 376 testNonInteger(-double(1ULL << 52) + 0.5); 377 testNonInteger(double(1ULL << 52) - 0.5); 378 testNonInteger(double(INT32_MAX) + 0.1); 379 testNonInteger(double(INT32_MIN) - 0.1); 380 testNonInteger(0.5); 381 testNonInteger(-0.0001); 382 testNonInteger(-9223372036854778000.0); 383 testNonInteger(9223372036854776000.0); 384 385 // Sanity-check that the IEEE-754 double-precision-derived literals used in 386 // testing here work as we intend them to. 387 A(exp2(-1075.0) == 0.0); 388 A(exp2(-1074.0) != 0.0); 389 testNonInteger(exp2(-1074.0)); 390 testNonInteger(2 * exp2(-1074.0)); 391 392 A(1.0 - exp2(-54.0) == 1.0); 393 A(1.0 - exp2(-53.0) != 1.0); 394 testNonInteger(1.0 - exp2(-53.0)); 395 testNonInteger(1.0 - exp2(-52.0)); 396 397 A(1.0 + exp2(-53.0) == 1.0f); 398 A(1.0 + exp2(-52.0) != 1.0f); 399 testNonInteger(1.0 + exp2(-52.0)); 400 } 401 402 static void TestFloatsPredicates() { 403 A(std::isnan(UnspecifiedNaN<float>())); 404 A(std::isnan(SpecificNaN<float>(1, 17))); 405 ; 406 A(std::isnan(SpecificNaN<float>(0, 0x7fff0fUL))); 407 A(!std::isnan(PositiveInfinity<float>())); 408 A(!std::isnan(NegativeInfinity<float>())); 409 410 A(std::isinf(PositiveInfinity<float>())); 411 A(std::isinf(NegativeInfinity<float>())); 412 A(!std::isinf(UnspecifiedNaN<float>())); 413 414 A(!std::isfinite(PositiveInfinity<float>())); 415 A(!std::isfinite(NegativeInfinity<float>())); 416 A(!std::isfinite(UnspecifiedNaN<float>())); 417 418 A(!IsNegative(PositiveInfinity<float>())); 419 A(IsNegative(NegativeInfinity<float>())); 420 A(IsNegative(-0.0f)); 421 A(!IsNegative(0.0f)); 422 A(IsNegative(-1.0f)); 423 A(!IsNegative(1.0f)); 424 425 A(!IsNegativeZero(PositiveInfinity<float>())); 426 A(!IsNegativeZero(NegativeInfinity<float>())); 427 A(!IsNegativeZero(SpecificNaN<float>(1, 17))); 428 ; 429 A(!IsNegativeZero(SpecificNaN<float>(1, 0x7fff0fUL))); 430 A(!IsNegativeZero(SpecificNaN<float>(0, 17))); 431 ; 432 A(!IsNegativeZero(SpecificNaN<float>(0, 0x7fff0fUL))); 433 A(!IsNegativeZero(UnspecifiedNaN<float>())); 434 A(IsNegativeZero(-0.0f)); 435 A(!IsNegativeZero(0.0f)); 436 A(!IsNegativeZero(-1.0f)); 437 A(!IsNegativeZero(1.0f)); 438 439 A(!IsPositiveZero(PositiveInfinity<float>())); 440 A(!IsPositiveZero(NegativeInfinity<float>())); 441 A(!IsPositiveZero(SpecificNaN<float>(1, 17))); 442 ; 443 A(!IsPositiveZero(SpecificNaN<float>(1, 0x7fff0fUL))); 444 A(!IsPositiveZero(SpecificNaN<float>(0, 17))); 445 ; 446 A(!IsPositiveZero(SpecificNaN<float>(0, 0x7fff0fUL))); 447 A(!IsPositiveZero(UnspecifiedNaN<float>())); 448 A(IsPositiveZero(0.0f)); 449 A(!IsPositiveZero(-0.0f)); 450 A(!IsPositiveZero(-1.0f)); 451 A(!IsPositiveZero(1.0f)); 452 453 // Edge case: negative zero. 454 TestEqualsIsForNegativeZero<float>(); 455 456 // Int32 values. 457 auto testInt32 = TestEqualsIsForInt32<float>; 458 testInt32(0.0f); 459 testInt32(1.0f); 460 testInt32(INT32_MIN); 461 testInt32(float(2147483648 - 128)); // max int32_t fitting in float 462 const int32_t BIG = 2097151; 463 testInt32(BIG); 464 465 // Int64 values that don't fit in int32. 466 auto testInt64 = TestEqualsIsForInt64<float>; 467 testInt64(INT64_MIN); 468 testInt64(9007199254740992.0f); 469 testInt64(-float(2147483648) - 256); 470 testInt64(float(2147483648)); 471 testInt64(float(2147483648) + 256); 472 473 // Floats that aren't equal to any int32 or int64. 474 auto testNonInteger = TestEqualsIsForNonInteger<float>; 475 testNonInteger(NegativeInfinity<float>()); 476 testNonInteger(PositiveInfinity<float>()); 477 testNonInteger(UnspecifiedNaN<float>()); 478 testNonInteger(0.5f); 479 testNonInteger(1.5f); 480 testNonInteger(-0.0001f); 481 testNonInteger(-19223373116872850000.0f); 482 testNonInteger(19223373116872850000.0f); 483 testNonInteger(float(BIG) + 0.1f); 484 485 A(powf(2.0f, -150.0f) == 0.0f); 486 A(powf(2.0f, -149.0f) != 0.0f); 487 testNonInteger(powf(2.0f, -149.0f)); 488 testNonInteger(2 * powf(2.0f, -149.0f)); 489 490 A(1.0f - powf(2.0f, -25.0f) == 1.0f); 491 A(1.0f - powf(2.0f, -24.0f) != 1.0f); 492 testNonInteger(1.0f - powf(2.0f, -24.0f)); 493 testNonInteger(1.0f - powf(2.0f, -23.0f)); 494 495 A(1.0f + powf(2.0f, -24.0f) == 1.0f); 496 A(1.0f + powf(2.0f, -23.0f) != 1.0f); 497 testNonInteger(1.0f + powf(2.0f, -23.0f)); 498 } 499 500 static void TestPredicates() { 501 TestFloatsPredicates(); 502 TestDoublesPredicates(); 503 } 504 505 static void TestFloatsAreApproximatelyEqual() { 506 float epsilon = mozilla::detail::FuzzyEqualsEpsilon<float>::value(); 507 float lessThanEpsilon = epsilon / 2.0f; 508 float moreThanEpsilon = epsilon * 2.0f; 509 510 // Additive tests using the default epsilon 511 // ... around 1.0 512 A(FuzzyEqualsAdditive(1.0f, 1.0f + lessThanEpsilon)); 513 A(FuzzyEqualsAdditive(1.0f, 1.0f - lessThanEpsilon)); 514 A(FuzzyEqualsAdditive(1.0f, 1.0f + epsilon)); 515 A(FuzzyEqualsAdditive(1.0f, 1.0f - epsilon)); 516 A(!FuzzyEqualsAdditive(1.0f, 1.0f + moreThanEpsilon)); 517 A(!FuzzyEqualsAdditive(1.0f, 1.0f - moreThanEpsilon)); 518 // ... around 1.0e2 (this is near the upper bound of the range where 519 // adding moreThanEpsilon will still be representable and return false) 520 A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + lessThanEpsilon)); 521 A(FuzzyEqualsAdditive(1.0e2f, 1.0e2f + epsilon)); 522 A(!FuzzyEqualsAdditive(1.0e2f, 1.0e2f + moreThanEpsilon)); 523 // ... around 1.0e-10 524 A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + lessThanEpsilon)); 525 A(FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + epsilon)); 526 A(!FuzzyEqualsAdditive(1.0e-10f, 1.0e-10f + moreThanEpsilon)); 527 // ... straddling 0 528 A(FuzzyEqualsAdditive(1.0e-6f, -1.0e-6f)); 529 A(!FuzzyEqualsAdditive(1.0e-5f, -1.0e-5f)); 530 // Using a small epsilon 531 A(FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-9f)); 532 A(!FuzzyEqualsAdditive(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-11f)); 533 // Using a big epsilon 534 A(FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e16f)); 535 A(!FuzzyEqualsAdditive(1.0e20f, 1.0e20f + 1.0e15f, 1.0e14f)); 536 537 // Multiplicative tests using the default epsilon 538 // ... around 1.0 539 A(FuzzyEqualsMultiplicative(1.0f, 1.0f + lessThanEpsilon)); 540 A(FuzzyEqualsMultiplicative(1.0f, 1.0f - lessThanEpsilon)); 541 A(FuzzyEqualsMultiplicative(1.0f, 1.0f + epsilon)); 542 A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - epsilon)); 543 A(!FuzzyEqualsMultiplicative(1.0f, 1.0f + moreThanEpsilon)); 544 A(!FuzzyEqualsMultiplicative(1.0f, 1.0f - moreThanEpsilon)); 545 // ... around 1.0e10 546 A(FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (lessThanEpsilon * 1.0e10f))); 547 A(!FuzzyEqualsMultiplicative(1.0e10f, 1.0e10f + (moreThanEpsilon * 1.0e10f))); 548 // ... around 1.0e-10 549 A(FuzzyEqualsMultiplicative(1.0e-10f, 550 1.0e-10f + (lessThanEpsilon * 1.0e-10f))); 551 A(!FuzzyEqualsMultiplicative(1.0e-10f, 552 1.0e-10f + (moreThanEpsilon * 1.0e-10f))); 553 // ... straddling 0 554 A(!FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f)); 555 A(FuzzyEqualsMultiplicative(1.0e-6f, -1.0e-6f, 1.0e2f)); 556 // Using a small epsilon 557 A(FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-4f)); 558 A(!FuzzyEqualsMultiplicative(1.0e-5f, 1.0e-5f + 1.0e-10f, 1.0e-5f)); 559 // Using a big epsilon 560 A(FuzzyEqualsMultiplicative(1.0f, 2.0f, 1.0f)); 561 A(!FuzzyEqualsMultiplicative(1.0f, 2.0f, 0.1f)); 562 563 // "real world case" 564 float oneThird = 10.0f / 3.0f; 565 A(FuzzyEqualsAdditive(10.0f, 3.0f * oneThird)); 566 A(FuzzyEqualsMultiplicative(10.0f, 3.0f * oneThird)); 567 // NaN check 568 A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 1), SpecificNaN<float>(1, 1))); 569 A(!FuzzyEqualsAdditive(SpecificNaN<float>(1, 2), SpecificNaN<float>(0, 8))); 570 A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 1), 571 SpecificNaN<float>(1, 1))); 572 A(!FuzzyEqualsMultiplicative(SpecificNaN<float>(1, 2), 573 SpecificNaN<float>(0, 200))); 574 } 575 576 static void TestDoublesAreApproximatelyEqual() { 577 double epsilon = mozilla::detail::FuzzyEqualsEpsilon<double>::value(); 578 double lessThanEpsilon = epsilon / 2.0; 579 double moreThanEpsilon = epsilon * 2.0; 580 581 // Additive tests using the default epsilon 582 // ... around 1.0 583 A(FuzzyEqualsAdditive(1.0, 1.0 + lessThanEpsilon)); 584 A(FuzzyEqualsAdditive(1.0, 1.0 - lessThanEpsilon)); 585 A(FuzzyEqualsAdditive(1.0, 1.0 + epsilon)); 586 A(FuzzyEqualsAdditive(1.0, 1.0 - epsilon)); 587 A(!FuzzyEqualsAdditive(1.0, 1.0 + moreThanEpsilon)); 588 A(!FuzzyEqualsAdditive(1.0, 1.0 - moreThanEpsilon)); 589 // ... around 1.0e4 (this is near the upper bound of the range where 590 // adding moreThanEpsilon will still be representable and return false) 591 A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + lessThanEpsilon)); 592 A(FuzzyEqualsAdditive(1.0e4, 1.0e4 + epsilon)); 593 A(!FuzzyEqualsAdditive(1.0e4, 1.0e4 + moreThanEpsilon)); 594 // ... around 1.0e-25 595 A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + lessThanEpsilon)); 596 A(FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + epsilon)); 597 A(!FuzzyEqualsAdditive(1.0e-25, 1.0e-25 + moreThanEpsilon)); 598 // ... straddling 0 599 A(FuzzyEqualsAdditive(1.0e-13, -1.0e-13)); 600 A(!FuzzyEqualsAdditive(1.0e-12, -1.0e-12)); 601 // Using a small epsilon 602 A(FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-29)); 603 A(!FuzzyEqualsAdditive(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-31)); 604 // Using a big epsilon 605 A(FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e26)); 606 A(!FuzzyEqualsAdditive(1.0e40, 1.0e40 + 1.0e25, 1.0e24)); 607 608 // Multiplicative tests using the default epsilon 609 // ... around 1.0 610 A(FuzzyEqualsMultiplicative(1.0, 1.0 + lessThanEpsilon)); 611 A(FuzzyEqualsMultiplicative(1.0, 1.0 - lessThanEpsilon)); 612 A(FuzzyEqualsMultiplicative(1.0, 1.0 + epsilon)); 613 A(!FuzzyEqualsMultiplicative(1.0, 1.0 - epsilon)); 614 A(!FuzzyEqualsMultiplicative(1.0, 1.0 + moreThanEpsilon)); 615 A(!FuzzyEqualsMultiplicative(1.0, 1.0 - moreThanEpsilon)); 616 // ... around 1.0e30 617 A(FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (lessThanEpsilon * 1.0e30))); 618 A(!FuzzyEqualsMultiplicative(1.0e30, 1.0e30 + (moreThanEpsilon * 1.0e30))); 619 // ... around 1.0e-30 620 A(FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (lessThanEpsilon * 1.0e-30))); 621 A(!FuzzyEqualsMultiplicative(1.0e-30, 1.0e-30 + (moreThanEpsilon * 1.0e-30))); 622 // ... straddling 0 623 A(!FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6)); 624 A(FuzzyEqualsMultiplicative(1.0e-6, -1.0e-6, 1.0e2)); 625 // Using a small epsilon 626 A(FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-15)); 627 A(!FuzzyEqualsMultiplicative(1.0e-15, 1.0e-15 + 1.0e-30, 1.0e-16)); 628 // Using a big epsilon 629 A(FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 1.0)); 630 A(!FuzzyEqualsMultiplicative(1.0e40, 2.0e40, 0.1)); 631 632 // "real world case" 633 double oneThird = 10.0 / 3.0; 634 A(FuzzyEqualsAdditive(10.0, 3.0 * oneThird)); 635 A(FuzzyEqualsMultiplicative(10.0, 3.0 * oneThird)); 636 // NaN check 637 A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 1), SpecificNaN<double>(1, 1))); 638 A(!FuzzyEqualsAdditive(SpecificNaN<double>(1, 2), SpecificNaN<double>(0, 8))); 639 A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 1), 640 SpecificNaN<double>(1, 1))); 641 A(!FuzzyEqualsMultiplicative(SpecificNaN<double>(1, 2), 642 SpecificNaN<double>(0, 200))); 643 } 644 645 static void TestAreApproximatelyEqual() { 646 TestFloatsAreApproximatelyEqual(); 647 TestDoublesAreApproximatelyEqual(); 648 } 649 650 static void TestIsFloat32Representable() { 651 // Zeroes are representable. 652 A(IsFloat32Representable(+0.0)); 653 A(IsFloat32Representable(-0.0)); 654 655 // NaN and infinities are representable. 656 A(IsFloat32Representable(UnspecifiedNaN<double>())); 657 A(IsFloat32Representable(SpecificNaN<double>(0, 1))); 658 A(IsFloat32Representable(SpecificNaN<double>(0, 71389))); 659 A(IsFloat32Representable(SpecificNaN<double>(0, (uint64_t(1) << 52) - 2))); 660 A(IsFloat32Representable(SpecificNaN<double>(1, 1))); 661 A(IsFloat32Representable(SpecificNaN<double>(1, 71389))); 662 A(IsFloat32Representable(SpecificNaN<double>(1, (uint64_t(1) << 52) - 2))); 663 A(IsFloat32Representable(PositiveInfinity<double>())); 664 A(IsFloat32Representable(NegativeInfinity<double>())); 665 666 // Sanity-check that the IEEE-754 double-precision-derived literals used in 667 // testing here work as we intend them to. 668 A(exp2(-1075.0) == 0.0); 669 A(exp2(-1074.0) != 0.0); 670 671 for (double littleExp = -1074.0; littleExp < -149.0; littleExp++) { 672 // Powers of two representable as doubles but not as floats aren't 673 // representable. 674 A(!IsFloat32Representable(exp2(littleExp))); 675 } 676 677 // Sanity-check that the IEEE-754 single-precision-derived literals used in 678 // testing here work as we intend them to. 679 A(exp2f(-150.0f) == 0.0); 680 A(exp2f(-149.0f) != 0.0); 681 682 // Exact powers of two within the available range are representable. 683 for (double exponent = -149.0; exponent < 128.0; exponent++) { 684 A(IsFloat32Representable(exp2(exponent))); 685 } 686 687 // Powers of two above the available range aren't representable. 688 for (double bigExp = 128.0; bigExp < 1024.0; bigExp++) { 689 A(!IsFloat32Representable(exp2(bigExp))); 690 } 691 692 // Various denormal (i.e. super-small) doubles with MSB and LSB as far apart 693 // as possible are representable (but taken one bit further apart are not 694 // representable). 695 // 696 // Note that the final iteration tests non-denormal with exponent field 697 // containing (biased) 1, as |oneTooSmall| and |widestPossible| happen still 698 // to be correct for that exponent due to the extra bit of precision in the 699 // implicit-one bit. 700 double oneTooSmall = exp2(-150.0); 701 for (double denormExp = -149.0; 702 denormExp < 1 - double(FloatingPoint<double>::kExponentBias) + 1; 703 denormExp++) { 704 double baseDenorm = exp2(denormExp); 705 double tooWide = baseDenorm + oneTooSmall; 706 A(!IsFloat32Representable(tooWide)); 707 708 double widestPossible = baseDenorm; 709 if (oneTooSmall * 2.0 != baseDenorm) { 710 widestPossible += oneTooSmall * 2.0; 711 } 712 713 A(IsFloat32Representable(widestPossible)); 714 } 715 716 // Finally, check certain interesting/special values for basic sanity. 717 A(!IsFloat32Representable(2147483647.0)); 718 A(!IsFloat32Representable(-2147483647.0)); 719 } 720 721 #undef A 722 723 int main() { 724 TestAreIdentical(); 725 TestExponentComponent(); 726 TestPredicates(); 727 TestAreApproximatelyEqual(); 728 TestIsFloat32Representable(); 729 return 0; 730 }