mfbt/FloatingPoint.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* Various predicates and operations on IEEE-754 floating point types. */
michael@0 8
michael@0 9 #ifndef mozilla_FloatingPoint_h
michael@0 10 #define mozilla_FloatingPoint_h
michael@0 11
michael@0 12 #include "mozilla/Assertions.h"
michael@0 13 #include "mozilla/Attributes.h"
michael@0 14 #include "mozilla/Casting.h"
michael@0 15 #include "mozilla/MathAlgorithms.h"
michael@0 16 #include "mozilla/Types.h"
michael@0 17
michael@0 18 #include <stdint.h>
michael@0 19
michael@0 20 namespace mozilla {
michael@0 21
michael@0 22 /*
michael@0 23 * It's reasonable to ask why we have this header at all. Don't isnan,
michael@0 24 * copysign, the built-in comparison operators, and the like solve these
michael@0 25 * problems? Unfortunately, they don't. We've found that various compilers
michael@0 26 * (MSVC, MSVC when compiling with PGO, and GCC on OS X, at least) miscompile
michael@0 27 * the standard methods in various situations, so we can't use them. Some of
michael@0 28 * these compilers even have problems compiling seemingly reasonable bitwise
michael@0 29 * algorithms! But with some care we've found algorithms that seem to not
michael@0 30 * trigger those compiler bugs.
michael@0 31 *
michael@0 32 * For the aforementioned reasons, be very wary of making changes to any of
michael@0 33 * these algorithms. If you must make changes, keep a careful eye out for
michael@0 34 * compiler bustage, particularly PGO-specific bustage.
michael@0 35 */
michael@0 36
michael@0 37 struct FloatTypeTraits
michael@0 38 {
michael@0 39 typedef uint32_t Bits;
michael@0 40
michael@0 41 static const unsigned ExponentBias = 127;
michael@0 42 static const unsigned ExponentShift = 23;
michael@0 43
michael@0 44 static const Bits SignBit = 0x80000000UL;
michael@0 45 static const Bits ExponentBits = 0x7F800000UL;
michael@0 46 static const Bits SignificandBits = 0x007FFFFFUL;
michael@0 47 };
michael@0 48
michael@0 49 struct DoubleTypeTraits
michael@0 50 {
michael@0 51 typedef uint64_t Bits;
michael@0 52
michael@0 53 static const unsigned ExponentBias = 1023;
michael@0 54 static const unsigned ExponentShift = 52;
michael@0 55
michael@0 56 static const Bits SignBit = 0x8000000000000000ULL;
michael@0 57 static const Bits ExponentBits = 0x7ff0000000000000ULL;
michael@0 58 static const Bits SignificandBits = 0x000fffffffffffffULL;
michael@0 59 };
michael@0 60
michael@0 61 template<typename T> struct SelectTrait;
michael@0 62 template<> struct SelectTrait<float> : public FloatTypeTraits {};
michael@0 63 template<> struct SelectTrait<double> : public DoubleTypeTraits {};
michael@0 64
michael@0 65 /*
michael@0 66 * This struct contains details regarding the encoding of floating-point
michael@0 67 * numbers that can be useful for direct bit manipulation. As of now, the
michael@0 68 * template parameter has to be float or double.
michael@0 69 *
michael@0 70 * The nested typedef |Bits| is the unsigned integral type with the same size
michael@0 71 * as T: uint32_t for float and uint64_t for double (static assertions
michael@0 72 * double-check these assumptions).
michael@0 73 *
michael@0 74 * ExponentBias is the offset that is subtracted from the exponent when
michael@0 75 * computing the value, i.e. one plus the opposite of the mininum possible
michael@0 76 * exponent.
michael@0 77 * ExponentShift is the shift that one needs to apply to retrieve the exponent
michael@0 78 * component of the value.
michael@0 79 *
michael@0 80 * SignBit contains a bits mask. Bit-and-ing with this mask will result in
michael@0 81 * obtaining the sign bit.
michael@0 82 * ExponentBits contains the mask needed for obtaining the exponent bits and
michael@0 83 * SignificandBits contains the mask needed for obtaining the significand bits.
michael@0 84 *
michael@0 85 * Full details of how floating point number formats are encoded are beyond the
michael@0 86 * scope of this comment. For more information, see
michael@0 87 * http://en.wikipedia.org/wiki/IEEE_floating_point
michael@0 88 * http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers
michael@0 89 */
michael@0 90 template<typename T>
michael@0 91 struct FloatingPoint : public SelectTrait<T>
michael@0 92 {
michael@0 93 typedef SelectTrait<T> Base;
michael@0 94 typedef typename Base::Bits Bits;
michael@0 95
michael@0 96 static_assert((Base::SignBit & Base::ExponentBits) == 0,
michael@0 97 "sign bit shouldn't overlap exponent bits");
michael@0 98 static_assert((Base::SignBit & Base::SignificandBits) == 0,
michael@0 99 "sign bit shouldn't overlap significand bits");
michael@0 100 static_assert((Base::ExponentBits & Base::SignificandBits) == 0,
michael@0 101 "exponent bits shouldn't overlap significand bits");
michael@0 102
michael@0 103 static_assert((Base::SignBit | Base::ExponentBits | Base::SignificandBits) ==
michael@0 104 ~Bits(0),
michael@0 105 "all bits accounted for");
michael@0 106
michael@0 107 /*
michael@0 108 * These implementations assume float/double are 32/64-bit single/double format
michael@0 109 * number types compatible with the IEEE-754 standard. C++ don't require this
michael@0 110 * to be the case. But we required this in implementations of these algorithms
michael@0 111 * that preceded this header, so we shouldn't break anything if we keep doing so.
michael@0 112 */
michael@0 113 static_assert(sizeof(T) == sizeof(Bits), "Bits must be same size as T");
michael@0 114 };
michael@0 115
michael@0 116 /** Determines whether a double is NaN. */
michael@0 117 template<typename T>
michael@0 118 static MOZ_ALWAYS_INLINE bool
michael@0 119 IsNaN(T t)
michael@0 120 {
michael@0 121 /*
michael@0 122 * A float/double is NaN if all exponent bits are 1 and the significand contains at
michael@0 123 * least one non-zero bit.
michael@0 124 */
michael@0 125 typedef FloatingPoint<T> Traits;
michael@0 126 typedef typename Traits::Bits Bits;
michael@0 127 Bits bits = BitwiseCast<Bits>(t);
michael@0 128 return (bits & Traits::ExponentBits) == Traits::ExponentBits &&
michael@0 129 (bits & Traits::SignificandBits) != 0;
michael@0 130 }
michael@0 131
michael@0 132 /** Determines whether a float/double is +Infinity or -Infinity. */
michael@0 133 template<typename T>
michael@0 134 static MOZ_ALWAYS_INLINE bool
michael@0 135 IsInfinite(T t)
michael@0 136 {
michael@0 137 /* Infinities have all exponent bits set to 1 and an all-0 significand. */
michael@0 138 typedef FloatingPoint<T> Traits;
michael@0 139 typedef typename Traits::Bits Bits;
michael@0 140 Bits bits = BitwiseCast<Bits>(t);
michael@0 141 return (bits & ~Traits::SignBit) == Traits::ExponentBits;
michael@0 142 }
michael@0 143
michael@0 144 /** Determines whether a float/double is not NaN or infinite. */
michael@0 145 template<typename T>
michael@0 146 static MOZ_ALWAYS_INLINE bool
michael@0 147 IsFinite(T t)
michael@0 148 {
michael@0 149 /*
michael@0 150 * NaN and Infinities are the only non-finite floats/doubles, and both have all
michael@0 151 * exponent bits set to 1.
michael@0 152 */
michael@0 153 typedef FloatingPoint<T> Traits;
michael@0 154 typedef typename Traits::Bits Bits;
michael@0 155 Bits bits = BitwiseCast<Bits>(t);
michael@0 156 return (bits & Traits::ExponentBits) != Traits::ExponentBits;
michael@0 157 }
michael@0 158
michael@0 159 /**
michael@0 160 * Determines whether a float/double is negative. It is an error to call this method
michael@0 161 * on a float/double which is NaN.
michael@0 162 */
michael@0 163 template<typename T>
michael@0 164 static MOZ_ALWAYS_INLINE bool
michael@0 165 IsNegative(T t)
michael@0 166 {
michael@0 167 MOZ_ASSERT(!IsNaN(t), "NaN does not have a sign");
michael@0 168
michael@0 169 /* The sign bit is set if the double is negative. */
michael@0 170 typedef FloatingPoint<T> Traits;
michael@0 171 typedef typename Traits::Bits Bits;
michael@0 172 Bits bits = BitwiseCast<Bits>(t);
michael@0 173 return (bits & Traits::SignBit) != 0;
michael@0 174 }
michael@0 175
michael@0 176 /** Determines whether a float/double represents -0. */
michael@0 177 template<typename T>
michael@0 178 static MOZ_ALWAYS_INLINE bool
michael@0 179 IsNegativeZero(T t)
michael@0 180 {
michael@0 181 /* Only the sign bit is set if the value is -0. */
michael@0 182 typedef FloatingPoint<T> Traits;
michael@0 183 typedef typename Traits::Bits Bits;
michael@0 184 Bits bits = BitwiseCast<Bits>(t);
michael@0 185 return bits == Traits::SignBit;
michael@0 186 }
michael@0 187
michael@0 188 /**
michael@0 189 * Returns the exponent portion of the float/double.
michael@0 190 *
michael@0 191 * Zero is not special-cased, so ExponentComponent(0.0) is
michael@0 192 * -int_fast16_t(Traits::ExponentBias).
michael@0 193 */
michael@0 194 template<typename T>
michael@0 195 static MOZ_ALWAYS_INLINE int_fast16_t
michael@0 196 ExponentComponent(T t)
michael@0 197 {
michael@0 198 /*
michael@0 199 * The exponent component of a float/double is an unsigned number, biased from its
michael@0 200 * actual value. Subtract the bias to retrieve the actual exponent.
michael@0 201 */
michael@0 202 typedef FloatingPoint<T> Traits;
michael@0 203 typedef typename Traits::Bits Bits;
michael@0 204 Bits bits = BitwiseCast<Bits>(t);
michael@0 205 return int_fast16_t((bits & Traits::ExponentBits) >> Traits::ExponentShift) -
michael@0 206 int_fast16_t(Traits::ExponentBias);
michael@0 207 }
michael@0 208
michael@0 209 /** Returns +Infinity. */
michael@0 210 template<typename T>
michael@0 211 static MOZ_ALWAYS_INLINE T
michael@0 212 PositiveInfinity()
michael@0 213 {
michael@0 214 /*
michael@0 215 * Positive infinity has all exponent bits set, sign bit set to 0, and no
michael@0 216 * significand.
michael@0 217 */
michael@0 218 typedef FloatingPoint<T> Traits;
michael@0 219 return BitwiseCast<T>(Traits::ExponentBits);
michael@0 220 }
michael@0 221
michael@0 222 /** Returns -Infinity. */
michael@0 223 template<typename T>
michael@0 224 static MOZ_ALWAYS_INLINE T
michael@0 225 NegativeInfinity()
michael@0 226 {
michael@0 227 /*
michael@0 228 * Negative infinity has all exponent bits set, sign bit set to 1, and no
michael@0 229 * significand.
michael@0 230 */
michael@0 231 typedef FloatingPoint<T> Traits;
michael@0 232 return BitwiseCast<T>(Traits::SignBit | Traits::ExponentBits);
michael@0 233 }
michael@0 234
michael@0 235
michael@0 236 /** Constructs a NaN value with the specified sign bit and significand bits. */
michael@0 237 template<typename T>
michael@0 238 static MOZ_ALWAYS_INLINE T
michael@0 239 SpecificNaN(int signbit, typename FloatingPoint<T>::Bits significand)
michael@0 240 {
michael@0 241 typedef FloatingPoint<T> Traits;
michael@0 242 MOZ_ASSERT(signbit == 0 || signbit == 1);
michael@0 243 MOZ_ASSERT((significand & ~Traits::SignificandBits) == 0);
michael@0 244 MOZ_ASSERT(significand & Traits::SignificandBits);
michael@0 245
michael@0 246 T t = BitwiseCast<T>((signbit ? Traits::SignBit : 0) |
michael@0 247 Traits::ExponentBits |
michael@0 248 significand);
michael@0 249 MOZ_ASSERT(IsNaN(t));
michael@0 250 return t;
michael@0 251 }
michael@0 252
michael@0 253 /** Computes the smallest non-zero positive float/double value. */
michael@0 254 template<typename T>
michael@0 255 static MOZ_ALWAYS_INLINE T
michael@0 256 MinNumberValue()
michael@0 257 {
michael@0 258 typedef FloatingPoint<T> Traits;
michael@0 259 typedef typename Traits::Bits Bits;
michael@0 260 return BitwiseCast<T>(Bits(1));
michael@0 261 }
michael@0 262
michael@0 263 /**
michael@0 264 * If t is equal to some int32_t value, set *i to that value and return true;
michael@0 265 * otherwise return false.
michael@0 266 *
michael@0 267 * Note that negative zero is "equal" to zero here. To test whether a value can
michael@0 268 * be losslessly converted to int32_t and back, use NumberIsInt32 instead.
michael@0 269 */
michael@0 270 template<typename T>
michael@0 271 static MOZ_ALWAYS_INLINE bool
michael@0 272 NumberEqualsInt32(T t, int32_t* i)
michael@0 273 {
michael@0 274 /*
michael@0 275 * XXX Casting a floating-point value that doesn't truncate to int32_t, to
michael@0 276 * int32_t, induces undefined behavior. We should definitely fix this
michael@0 277 * (bug 744965), but as apparently it "works" in practice, it's not a
michael@0 278 * pressing concern now.
michael@0 279 */
michael@0 280 return t == (*i = int32_t(t));
michael@0 281 }
michael@0 282
michael@0 283 /**
michael@0 284 * If d can be converted to int32_t and back to an identical double value,
michael@0 285 * set *i to that value and return true; otherwise return false.
michael@0 286 *
michael@0 287 * The difference between this and NumberEqualsInt32 is that this method returns
michael@0 288 * false for negative zero.
michael@0 289 */
michael@0 290 template<typename T>
michael@0 291 static MOZ_ALWAYS_INLINE bool
michael@0 292 NumberIsInt32(T t, int32_t* i)
michael@0 293 {
michael@0 294 return !IsNegativeZero(t) && NumberEqualsInt32(t, i);
michael@0 295 }
michael@0 296
michael@0 297 /**
michael@0 298 * Computes a NaN value. Do not use this method if you depend upon a particular
michael@0 299 * NaN value being returned.
michael@0 300 */
michael@0 301 template<typename T>
michael@0 302 static MOZ_ALWAYS_INLINE T
michael@0 303 UnspecifiedNaN()
michael@0 304 {
michael@0 305 /*
michael@0 306 * If we can use any quiet NaN, we might as well use the all-ones NaN,
michael@0 307 * since it's cheap to materialize on common platforms (such as x64, where
michael@0 308 * this value can be represented in a 32-bit signed immediate field, allowing
michael@0 309 * it to be stored to memory in a single instruction).
michael@0 310 */
michael@0 311 typedef FloatingPoint<T> Traits;
michael@0 312 return SpecificNaN<T>(1, Traits::SignificandBits);
michael@0 313 }
michael@0 314
michael@0 315 /**
michael@0 316 * Compare two doubles for equality, *without* equating -0 to +0, and equating
michael@0 317 * any NaN value to any other NaN value. (The normal equality operators equate
michael@0 318 * -0 with +0, and they equate NaN to no other value.)
michael@0 319 */
michael@0 320 template<typename T>
michael@0 321 static inline bool
michael@0 322 NumbersAreIdentical(T t1, T t2)
michael@0 323 {
michael@0 324 typedef FloatingPoint<T> Traits;
michael@0 325 typedef typename Traits::Bits Bits;
michael@0 326 if (IsNaN(t1))
michael@0 327 return IsNaN(t2);
michael@0 328 return BitwiseCast<Bits>(t1) == BitwiseCast<Bits>(t2);
michael@0 329 }
michael@0 330
michael@0 331 namespace detail {
michael@0 332
michael@0 333 template<typename T>
michael@0 334 struct FuzzyEqualsEpsilon;
michael@0 335
michael@0 336 template<>
michael@0 337 struct FuzzyEqualsEpsilon<float>
michael@0 338 {
michael@0 339 // A number near 1e-5 that is exactly representable in
michael@0 340 // floating point
michael@0 341 static const float value() { return 1.0f / (1 << 17); }
michael@0 342 };
michael@0 343
michael@0 344 template<>
michael@0 345 struct FuzzyEqualsEpsilon<double>
michael@0 346 {
michael@0 347 // A number near 1e-12 that is exactly representable in
michael@0 348 // a double
michael@0 349 static const double value() { return 1.0 / (1LL << 40); }
michael@0 350 };
michael@0 351
michael@0 352 } // namespace detail
michael@0 353
michael@0 354 /**
michael@0 355 * Compare two floating point values for equality, modulo rounding error. That
michael@0 356 * is, the two values are considered equal if they are both not NaN and if they
michael@0 357 * are less than or equal to epsilon apart. The default value of epsilon is near
michael@0 358 * 1e-5.
michael@0 359 *
michael@0 360 * For most scenarios you will want to use FuzzyEqualsMultiplicative instead,
michael@0 361 * as it is more reasonable over the entire range of floating point numbers.
michael@0 362 * This additive version should only be used if you know the range of the numbers
michael@0 363 * you are dealing with is bounded and stays around the same order of magnitude.
michael@0 364 */
michael@0 365 template<typename T>
michael@0 366 static MOZ_ALWAYS_INLINE bool
michael@0 367 FuzzyEqualsAdditive(T val1, T val2, T epsilon = detail::FuzzyEqualsEpsilon<T>::value())
michael@0 368 {
michael@0 369 static_assert(IsFloatingPoint<T>::value, "floating point type required");
michael@0 370 return Abs(val1 - val2) <= epsilon;
michael@0 371 }
michael@0 372
michael@0 373 /**
michael@0 374 * Compare two floating point values for equality, allowing for rounding error
michael@0 375 * relative to the magnitude of the values. That is, the two values are
michael@0 376 * considered equal if they are both not NaN and they are less than or equal to
michael@0 377 * some epsilon apart, where the epsilon is scaled by the smaller of the two
michael@0 378 * argument values.
michael@0 379 *
michael@0 380 * In most cases you will want to use this rather than FuzzyEqualsAdditive, as
michael@0 381 * this function effectively masks out differences in the bottom few bits of
michael@0 382 * the floating point numbers being compared, regardless of what order of magnitude
michael@0 383 * those numbers are at.
michael@0 384 */
michael@0 385 template<typename T>
michael@0 386 static MOZ_ALWAYS_INLINE bool
michael@0 387 FuzzyEqualsMultiplicative(T val1, T val2, T epsilon = detail::FuzzyEqualsEpsilon<T>::value())
michael@0 388 {
michael@0 389 static_assert(IsFloatingPoint<T>::value, "floating point type required");
michael@0 390 // can't use std::min because of bug 965340
michael@0 391 T smaller = Abs(val1) < Abs(val2) ? Abs(val1) : Abs(val2);
michael@0 392 return Abs(val1 - val2) <= epsilon * smaller;
michael@0 393 }
michael@0 394
michael@0 395 /**
michael@0 396 * Returns true if the given value can be losslessly represented as an IEEE-754
michael@0 397 * single format number, false otherwise. All NaN values are considered
michael@0 398 * representable (notwithstanding that the exact bit pattern of a double format
michael@0 399 * NaN value can't be exactly represented in single format).
michael@0 400 *
michael@0 401 * This function isn't inlined to avoid buggy optimizations by MSVC.
michael@0 402 */
michael@0 403 MOZ_WARN_UNUSED_RESULT
michael@0 404 extern MFBT_API bool
michael@0 405 IsFloat32Representable(double x);
michael@0 406
michael@0 407 } /* namespace mozilla */
michael@0 408
michael@0 409 #endif /* mozilla_FloatingPoint_h */

mercurial