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