1 /* 2 * Copyright 2011 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 #include "SkFloatingPoint.h" 9 #include "SkMath.h" 10 #include "SkPoint.h" 11 #include "SkRandom.h" 12 #include "SkRect.h" 13 #include "Test.h" 14 15 static void test_roundtoint(skiatest::Reporter* reporter) { 16 SkScalar x = 0.49999997f; 17 int ix = SkScalarRoundToInt(x); 18 // We "should" get 0, since x < 0.5, but we don't due to float addition rounding up the low 19 // bit after adding 0.5. 20 REPORTER_ASSERT(reporter, 1 == ix); 21 22 // This version explicitly performs the +0.5 step using double, which should avoid losing the 23 // low bits. 24 ix = SkDScalarRoundToInt(x); 25 REPORTER_ASSERT(reporter, 0 == ix); 26 } 27 28 struct PointSet { 29 const SkPoint* fPts; 30 size_t fCount; 31 bool fIsFinite; 32 }; 33 34 static void test_isRectFinite(skiatest::Reporter* reporter) { 35 static const SkPoint gF0[] = { 36 { 0, 0 }, { 1, 1 } 37 }; 38 static const SkPoint gF1[] = { 39 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 } 40 }; 41 42 static const SkPoint gI0[] = { 43 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarNaN, 3 }, { 2, 3 }, 44 }; 45 static const SkPoint gI1[] = { 46 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarNaN }, { 2, 3 }, 47 }; 48 static const SkPoint gI2[] = { 49 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarInfinity, 3 }, { 2, 3 }, 50 }; 51 static const SkPoint gI3[] = { 52 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarInfinity }, { 2, 3 }, 53 }; 54 55 static const struct { 56 const SkPoint* fPts; 57 size_t fCount; 58 bool fIsFinite; 59 } gSets[] = { 60 { gF0, SK_ARRAY_COUNT(gF0), true }, 61 { gF1, SK_ARRAY_COUNT(gF1), true }, 62 63 { gI0, SK_ARRAY_COUNT(gI0), false }, 64 { gI1, SK_ARRAY_COUNT(gI1), false }, 65 { gI2, SK_ARRAY_COUNT(gI2), false }, 66 { gI3, SK_ARRAY_COUNT(gI3), false }, 67 }; 68 69 for (size_t i = 0; i < SK_ARRAY_COUNT(gSets); ++i) { 70 SkRect r; 71 r.set(gSets[i].fPts, gSets[i].fCount); 72 bool rectIsFinite = !r.isEmpty(); 73 REPORTER_ASSERT(reporter, gSets[i].fIsFinite == rectIsFinite); 74 } 75 } 76 77 static bool isFinite_int(float x) { 78 uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts 79 int exponent = bits << 1 >> 24; 80 return exponent != 0xFF; 81 } 82 83 static bool isFinite_float(float x) { 84 return SkToBool(sk_float_isfinite(x)); 85 } 86 87 static bool isFinite_mulzero(float x) { 88 float y = x * 0; 89 return y == y; 90 } 91 92 // return true if the float is finite 93 typedef bool (*IsFiniteProc1)(float); 94 95 static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) { 96 return proc(x) && proc(y); 97 } 98 99 static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) { 100 return proc(x * 0 + y * 0); 101 } 102 103 // return true if both floats are finite 104 typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1); 105 106 enum FloatClass { 107 kFinite, 108 kInfinite, 109 kNaN 110 }; 111 112 static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) { 113 // our sk_float_is... function may return int instead of bool, 114 // hence the double ! to turn it into a bool 115 REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite)); 116 REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite)); 117 REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN)); 118 } 119 120 #if defined _WIN32 121 #pragma warning ( push ) 122 // we are intentionally causing an overflow here 123 // (warning C4756: overflow in constant arithmetic) 124 #pragma warning ( disable : 4756 ) 125 #endif 126 127 static void test_isfinite(skiatest::Reporter* reporter) { 128 struct Rec { 129 float fValue; 130 bool fIsFinite; 131 }; 132 133 float max = 3.402823466e+38f; 134 float inf = max * max; 135 float nan = inf * 0; 136 137 test_floatclass(reporter, 0, kFinite); 138 test_floatclass(reporter, max, kFinite); 139 test_floatclass(reporter, -max, kFinite); 140 test_floatclass(reporter, inf, kInfinite); 141 test_floatclass(reporter, -inf, kInfinite); 142 test_floatclass(reporter, nan, kNaN); 143 test_floatclass(reporter, -nan, kNaN); 144 145 const Rec data[] = { 146 { 0, true }, 147 { 1, true }, 148 { -1, true }, 149 { max * 0.75f, true }, 150 { max, true }, 151 { -max * 0.75f, true }, 152 { -max, true }, 153 { inf, false }, 154 { -inf, false }, 155 { nan, false }, 156 }; 157 158 const IsFiniteProc1 gProc1[] = { 159 isFinite_int, 160 isFinite_float, 161 isFinite_mulzero 162 }; 163 const IsFiniteProc2 gProc2[] = { 164 isFinite2_and, 165 isFinite2_mulzeroadd 166 }; 167 168 size_t i, n = SK_ARRAY_COUNT(data); 169 170 for (i = 0; i < n; ++i) { 171 for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) { 172 const Rec& rec = data[i]; 173 bool finite = gProc1[k](rec.fValue); 174 REPORTER_ASSERT(reporter, rec.fIsFinite == finite); 175 } 176 } 177 178 for (i = 0; i < n; ++i) { 179 const Rec& rec0 = data[i]; 180 for (size_t j = 0; j < n; ++j) { 181 const Rec& rec1 = data[j]; 182 for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) { 183 IsFiniteProc1 proc1 = gProc1[k]; 184 185 for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) { 186 bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1); 187 bool finite2 = rec0.fIsFinite && rec1.fIsFinite; 188 REPORTER_ASSERT(reporter, finite2 == finite); 189 } 190 } 191 } 192 } 193 194 test_isRectFinite(reporter); 195 } 196 197 #if defined _WIN32 198 #pragma warning ( pop ) 199 #endif 200 201 DEF_TEST(Scalar, reporter) { 202 test_isfinite(reporter); 203 test_roundtoint(reporter); 204 } 205