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 15static 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 28struct PointSet { 29 const SkPoint* fPts; 30 size_t fCount; 31 bool fIsFinite; 32}; 33 34static 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 77static 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 83static bool isFinite_float(float x) { 84 return SkToBool(sk_float_isfinite(x)); 85} 86 87static bool isFinite_mulzero(float x) { 88 float y = x * 0; 89 return y == y; 90} 91 92// return true if the float is finite 93typedef bool (*IsFiniteProc1)(float); 94 95static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) { 96 return proc(x) && proc(y); 97} 98 99static 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 104typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1); 105 106enum FloatClass { 107 kFinite, 108 kInfinite, 109 kNaN 110}; 111 112static 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 127static 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 201DEF_TEST(Scalar, reporter) { 202 test_isfinite(reporter); 203 test_roundtoint(reporter); 204} 205