• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkFloatUtils_DEFINED
9 #define SkFloatUtils_DEFINED
10 
11 #include "include/core/SkTypes.h"
12 #include <limits.h>
13 #include <float.h>
14 
15 template <size_t size>
16 class SkTypeWithSize {
17 public:
18     // Prevents using SkTypeWithSize<N> with non-specialized N.
19     typedef void UInt;
20 };
21 
22 template <>
23 class SkTypeWithSize<32> {
24 public:
25     typedef uint32_t UInt;
26 };
27 
28 template <>
29 class SkTypeWithSize<64> {
30 public:
31     typedef uint64_t UInt;
32 };
33 
34 template <typename RawType>
35 struct SkNumericLimits {
36     static const int digits = 0;
37 };
38 
39 template <>
40 struct SkNumericLimits<double> {
41     static const int digits = DBL_MANT_DIG;
42 };
43 
44 template <>
45 struct SkNumericLimits<float> {
46     static const int digits = FLT_MANT_DIG;
47 };
48 
49 //See
50 //http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison/3423299#3423299
51 //http://code.google.com/p/googletest/source/browse/trunk/include/gtest/internal/gtest-internal.h
52 //http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
53 
54 template <typename RawType, unsigned int ULPs>
55 class SkFloatingPoint {
56 public:
57     /** Bits is a unsigned integer the same size as the floating point number. */
58     typedef typename SkTypeWithSize<sizeof(RawType) * CHAR_BIT>::UInt Bits;
59 
60     /** # of bits in a number. */
61     static const size_t kBitCount = CHAR_BIT * sizeof(RawType);
62 
63     /** # of fraction bits in a number. */
64     static const size_t kFractionBitCount = SkNumericLimits<RawType>::digits - 1;
65 
66     /** # of exponent bits in a number. */
67     static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
68 
69     /** The mask for the sign bit. */
70     static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
71 
72     /** The mask for the fraction bits. */
73     static const Bits kFractionBitMask =
74         ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
75 
76     /** The mask for the exponent bits. */
77     static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
78 
79     /** How many ULP's (Units in the Last Place) to tolerate when comparing. */
80     static const size_t kMaxUlps = ULPs;
81 
82     /**
83      *  Constructs a FloatingPoint from a raw floating-point number.
84      *
85      *  On an Intel CPU, passing a non-normalized NAN (Not a Number)
86      *  around may change its bits, although the new value is guaranteed
87      *  to be also a NAN.  Therefore, don't expect this constructor to
88      *  preserve the bits in x when x is a NAN.
89      */
90     explicit SkFloatingPoint(const RawType& x) { fU.value = x; }
91 
92     /** Returns the exponent bits of this number. */
93     Bits exponent_bits() const { return kExponentBitMask & fU.bits; }
94 
95     /** Returns the fraction bits of this number. */
96     Bits fraction_bits() const { return kFractionBitMask & fU.bits; }
97 
98     /** Returns true iff this is NAN (not a number). */
99     bool is_nan() const {
100         // It's a NAN if both of the folloowing are true:
101         // * the exponent bits are all ones
102         // * the fraction bits are not all zero.
103         return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
104     }
105 
106     /**
107      *  Returns true iff this number is at most kMaxUlps ULP's away from ths.
108      *  In particular, this function:
109      *   - returns false if either number is (or both are) NAN.
110      *   - treats really large numbers as almost equal to infinity.
111      *   - thinks +0.0 and -0.0 are 0 DLP's apart.
112      */
113     bool AlmostEquals(const SkFloatingPoint& rhs) const {
114         // Any comparison operation involving a NAN must return false.
115         if (is_nan() || rhs.is_nan()) return false;
116 
117         const Bits dist = DistanceBetweenSignAndMagnitudeNumbers(fU.bits,
118                                                                  rhs.fU.bits);
119         //SkDEBUGF("(%f, %f, %d) ", u_.value_, rhs.u_.value_, dist);
120         return dist <= kMaxUlps;
121     }
122 
123 private:
124     /** The data type used to store the actual floating-point number. */
125     union FloatingPointUnion {
126         /** The raw floating-point number. */
127         RawType value;
128         /** The bits that represent the number. */
129         Bits bits;
130     };
131 
132     /**
133      *  Converts an integer from the sign-and-magnitude representation to
134      *  the biased representation. More precisely, let N be 2 to the
135      *  power of (kBitCount - 1), an integer x is represented by the
136      *  unsigned number x + N.
137      *
138      *  For instance,
139      *
140      *    -N + 1 (the most negative number representable using
141      *           sign-and-magnitude) is represented by 1;
142      *    0      is represented by N; and
143      *    N - 1  (the biggest number representable using
144      *           sign-and-magnitude) is represented by 2N - 1.
145      *
146      *  Read http://en.wikipedia.org/wiki/Signed_number_representations
147      *  for more details on signed number representations.
148      */
149     static Bits SignAndMagnitudeToBiased(const Bits &sam) {
150         if (kSignBitMask & sam) {
151             // sam represents a negative number.
152             return ~sam + 1;
153         } else {
154             // sam represents a positive number.
155             return kSignBitMask | sam;
156         }
157     }
158 
159     /**
160      *  Given two numbers in the sign-and-magnitude representation,
161      *  returns the distance between them as an unsigned number.
162      */
163     static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
164                                                        const Bits &sam2) {
165         const Bits biased1 = SignAndMagnitudeToBiased(sam1);
166         const Bits biased2 = SignAndMagnitudeToBiased(sam2);
167         return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
168     }
169 
170     FloatingPointUnion fU;
171 };
172 
173 #endif
174