MathTest.cpp revision ed673310e2551e64d8196f7776d7d4c92085f8c2
1#include "Test.h" 2#include "SkPoint.h" 3#include "SkRandom.h" 4 5#if defined(SkLONGLONG) 6static int symmetric_fixmul(int a, int b) { 7 int sa = SkExtractSign(a); 8 int sb = SkExtractSign(b); 9 10 a = SkApplySign(a, sa); 11 b = SkApplySign(b, sb); 12 13#if 1 14 int c = (int)(((SkLONGLONG)a * b) >> 16); 15 16 return SkApplySign(c, sa ^ sb); 17#else 18 SkLONGLONG ab = (SkLONGLONG)a * b; 19 if (sa ^ sb) { 20 ab = -ab; 21 } 22 return ab >> 16; 23#endif 24} 25#endif 26 27static void check_length(skiatest::Reporter* reporter, 28 const SkPoint& p, SkScalar targetLen) { 29#ifdef SK_CAN_USE_FLOAT 30 float x = SkScalarToFloat(p.fX); 31 float y = SkScalarToFloat(p.fY); 32 float len = sk_float_sqrt(x*x + y*y); 33 34 len /= SkScalarToFloat(targetLen); 35 36 REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f); 37#endif 38} 39 40#if defined(SK_CAN_USE_FLOAT) 41 42static float nextFloat(SkRandom& rand) { 43 SkFloatIntUnion data; 44 data.fSignBitInt = rand.nextU(); 45 return data.fFloat; 46} 47 48/* returns true if a == b as resulting from (int)x. Since it is undefined 49 what to do if the float exceeds 2^32-1, we check for that explicitly. 50 */ 51static bool equal_float_native_skia(float x, uint32_t ni, uint32_t si) { 52 if (!(x == x)) { // NAN 53 return si == SK_MaxS32 || si == SK_MinS32; 54 } 55 // for out of range, C is undefined, but skia always should return NaN32 56 if (x > SK_MaxS32) { 57 return si == SK_MaxS32; 58 } 59 if (x < -SK_MaxS32) { 60 return si == SK_MinS32; 61 } 62 return si == ni; 63} 64 65static void assert_float_equal(skiatest::Reporter* reporter, const char op[], 66 float x, uint32_t ni, uint32_t si) { 67 if (!equal_float_native_skia(x, ni, si)) { 68 SkString desc; 69 desc.printf("%s float %g bits %x native %x skia %x\n", op, x, ni, si); 70 reporter->reportFailed(desc); 71 } 72} 73 74static void test_float_cast(skiatest::Reporter* reporter, float x) { 75 int ix = (int)x; 76 int iix = SkFloatToIntCast(x); 77 assert_float_equal(reporter, "cast", x, ix, iix); 78} 79 80static void test_float_floor(skiatest::Reporter* reporter, float x) { 81 int ix = (int)floor(x); 82 int iix = SkFloatToIntFloor(x); 83 assert_float_equal(reporter, "floor", x, ix, iix); 84} 85 86static void test_float_round(skiatest::Reporter* reporter, float x) { 87 double xx = x + 0.5; // need intermediate double to avoid temp loss 88 int ix = (int)floor(xx); 89 int iix = SkFloatToIntRound(x); 90 assert_float_equal(reporter, "round", x, ix, iix); 91} 92 93static void test_float_ceil(skiatest::Reporter* reporter, float x) { 94 int ix = (int)ceil(x); 95 int iix = SkFloatToIntCeil(x); 96 assert_float_equal(reporter, "ceil", x, ix, iix); 97} 98 99static void test_float_conversions(skiatest::Reporter* reporter, float x) { 100 test_float_cast(reporter, x); 101 test_float_floor(reporter, x); 102 test_float_round(reporter, x); 103 test_float_ceil(reporter, x); 104} 105 106static void test_int2float(skiatest::Reporter* reporter, int ival) { 107 float x0 = (float)ival; 108 float x1 = SkIntToFloatCast(ival); 109 float x2 = SkIntToFloatCast_NoOverflowCheck(ival); 110 REPORTER_ASSERT(reporter, x0 == x1); 111 REPORTER_ASSERT(reporter, x0 == x2); 112} 113 114static void unittest_fastfloat(skiatest::Reporter* reporter) { 115 SkRandom rand; 116 size_t i; 117 118 static const float gFloats[] = { 119 0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3, 120 0.000000001f, 1000000000.f, // doesn't overflow 121 0.0000000001f, 10000000000.f // does overflow 122 }; 123 for (i = 0; i < SK_ARRAY_COUNT(gFloats); i++) { 124 // SkDebugf("---- test floats %g %d\n", gFloats[i], (int)gFloats[i]); 125 test_float_conversions(reporter, gFloats[i]); 126 test_float_conversions(reporter, -gFloats[i]); 127 } 128 129 for (int outer = 0; outer < 100; outer++) { 130 rand.setSeed(outer); 131 for (i = 0; i < 100000; i++) { 132 float x = nextFloat(rand); 133 test_float_conversions(reporter, x); 134 } 135 136 test_int2float(reporter, 0); 137 test_int2float(reporter, 1); 138 test_int2float(reporter, -1); 139 for (i = 0; i < 100000; i++) { 140 // for now only test ints that are 24bits or less, since we don't 141 // round (down) large ints the same as IEEE... 142 int ival = rand.nextU() & 0xFFFFFF; 143 test_int2float(reporter, ival); 144 test_int2float(reporter, -ival); 145 } 146 } 147} 148 149#endif 150 151static void test_muldiv255(skiatest::Reporter* reporter) { 152#ifdef SK_CAN_USE_FLOAT 153 for (int a = 0; a <= 255; a++) { 154 for (int b = 0; b <= 255; b++) { 155 int ab = a * b; 156 float s = ab / 255.0f; 157 int round = (int)floorf(s + 0.5f); 158 int trunc = (int)floorf(s); 159 160 int iround = SkMulDiv255Round(a, b); 161 int itrunc = SkMulDiv255Trunc(a, b); 162 163 REPORTER_ASSERT(reporter, iround == round); 164 REPORTER_ASSERT(reporter, itrunc == trunc); 165 166 REPORTER_ASSERT(reporter, itrunc <= iround); 167 REPORTER_ASSERT(reporter, iround <= a); 168 REPORTER_ASSERT(reporter, iround <= b); 169 } 170 } 171#endif 172} 173 174static void TestMath(skiatest::Reporter* reporter) { 175 int i; 176 int32_t x; 177 SkRandom rand; 178 179 // these should not assert 180 SkToS8(127); SkToS8(-128); SkToU8(255); 181 SkToS16(32767); SkToS16(-32768); SkToU16(65535); 182 SkToS32(2*1024*1024); SkToS32(-2*1024*1024); SkToU32(4*1024*1024); 183 184 // these should assert 185#if 0 186 SkToS8(128); 187 SkToS8(-129); 188 SkToU8(256); 189 SkToU8(-5); 190 191 SkToS16(32768); 192 SkToS16(-32769); 193 SkToU16(65536); 194 SkToU16(-5); 195 196 if (sizeof(size_t) > 4) { 197 SkToS32(4*1024*1024); 198 SkToS32(-4*1024*1024); 199 SkToU32(5*1024*1024); 200 SkToU32(-5); 201 } 202#endif 203 204 test_muldiv255(reporter); 205 206 { 207 SkScalar x = SK_ScalarNaN; 208 REPORTER_ASSERT(reporter, SkScalarIsNaN(x)); 209 } 210 211 for (i = 1; i <= 10; i++) { 212 x = SkCubeRootBits(i*i*i, 11); 213 REPORTER_ASSERT(reporter, x == i); 214 } 215 216 REPORTER_ASSERT(reporter, !"test the reporter"); 217 218 x = SkFixedSqrt(SK_Fixed1); 219 REPORTER_ASSERT(reporter, x == SK_Fixed1); 220 x = SkFixedSqrt(SK_Fixed1/4); 221 REPORTER_ASSERT(reporter, x == SK_Fixed1/2); 222 x = SkFixedSqrt(SK_Fixed1*4); 223 REPORTER_ASSERT(reporter, x == SK_Fixed1*2); 224 225 x = SkFractSqrt(SK_Fract1); 226 REPORTER_ASSERT(reporter, x == SK_Fract1); 227 x = SkFractSqrt(SK_Fract1/4); 228 REPORTER_ASSERT(reporter, x == SK_Fract1/2); 229 x = SkFractSqrt(SK_Fract1/16); 230 REPORTER_ASSERT(reporter, x == SK_Fract1/4); 231 232 for (i = 1; i < 100; i++) { 233 x = SkFixedSqrt(SK_Fixed1 * i * i); 234 REPORTER_ASSERT(reporter, x == SK_Fixed1 * i); 235 } 236 237 for (i = 0; i < 1000; i++) { 238 int value = rand.nextS16(); 239 int max = rand.nextU16(); 240 241 int clamp = SkClampMax(value, max); 242 int clamp2 = value < 0 ? 0 : (value > max ? max : value); 243 REPORTER_ASSERT(reporter, clamp == clamp2); 244 } 245 246 for (i = 0; i < 100000; i++) { 247 SkPoint p; 248 249 p.setLength(rand.nextS(), rand.nextS(), SK_Scalar1); 250 check_length(reporter, p, SK_Scalar1); 251 p.setLength(rand.nextS() >> 13, rand.nextS() >> 13, SK_Scalar1); 252 check_length(reporter, p, SK_Scalar1); 253 } 254 255 { 256 SkFixed result = SkFixedDiv(100, 100); 257 REPORTER_ASSERT(reporter, result == SK_Fixed1); 258 result = SkFixedDiv(1, SK_Fixed1); 259 REPORTER_ASSERT(reporter, result == 1); 260 } 261 262#ifdef SK_CAN_USE_FLOAT 263 unittest_fastfloat(reporter); 264#endif 265 266#ifdef SkLONGLONG 267 for (i = 0; i < 100000; i++) { 268 SkFixed numer = rand.nextS(); 269 SkFixed denom = rand.nextS(); 270 SkFixed result = SkFixedDiv(numer, denom); 271 SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom; 272 273 (void)SkCLZ(numer); 274 (void)SkCLZ(denom); 275 276 REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32); 277 if (check > SK_MaxS32) { 278 check = SK_MaxS32; 279 } else if (check < -SK_MaxS32) { 280 check = SK_MinS32; 281 } 282 REPORTER_ASSERT(reporter, result == (int32_t)check); 283 284 result = SkFractDiv(numer, denom); 285 check = ((SkLONGLONG)numer << 30) / denom; 286 287 REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32); 288 if (check > SK_MaxS32) { 289 check = SK_MaxS32; 290 } else if (check < -SK_MaxS32) { 291 check = SK_MinS32; 292 } 293 REPORTER_ASSERT(reporter, result == (int32_t)check); 294 295 // make them <= 2^24, so we don't overflow in fixmul 296 numer = numer << 8 >> 8; 297 denom = denom << 8 >> 8; 298 299 result = SkFixedMul(numer, denom); 300 SkFixed r2 = symmetric_fixmul(numer, denom); 301 // SkASSERT(result == r2); 302 303 result = SkFixedMul(numer, numer); 304 r2 = SkFixedSquare(numer); 305 REPORTER_ASSERT(reporter, result == r2); 306 307#ifdef SK_CAN_USE_FLOAT 308 if (numer >= 0 && denom >= 0) { 309 SkFixed mean = SkFixedMean(numer, denom); 310 float fm = sk_float_sqrt(sk_float_abs(SkFixedToFloat(numer) * SkFixedToFloat(denom))); 311 SkFixed mean2 = SkFloatToFixed(fm); 312 int diff = SkAbs32(mean - mean2); 313 REPORTER_ASSERT(reporter, diff <= 1); 314 } 315 316 { 317 SkFixed mod = SkFixedMod(numer, denom); 318 float n = SkFixedToFloat(numer); 319 float d = SkFixedToFloat(denom); 320 float m = sk_float_mod(n, d); 321 REPORTER_ASSERT(reporter, mod == 0 || (mod < 0) == (m < 0)); // ensure the same sign 322 int diff = SkAbs32(mod - SkFloatToFixed(m)); 323 REPORTER_ASSERT(reporter, (diff >> 7) == 0); 324 } 325#endif 326 } 327#endif 328 329#ifdef SK_CAN_USE_FLOAT 330 for (i = 0; i < 100000; i++) { 331 SkFract x = rand.nextU() >> 1; 332 double xx = (double)x / SK_Fract1; 333 SkFract xr = SkFractSqrt(x); 334 SkFract check = SkFloatToFract(sqrt(xx)); 335 REPORTER_ASSERT(reporter, xr == check || xr == check-1 || xr == check+1); 336 337 xr = SkFixedSqrt(x); 338 xx = (double)x / SK_Fixed1; 339 check = SkFloatToFixed(sqrt(xx)); 340 REPORTER_ASSERT(reporter, xr == check || xr == check-1); 341 342 xr = SkSqrt32(x); 343 xx = (double)x; 344 check = (int32_t)sqrt(xx); 345 REPORTER_ASSERT(reporter, xr == check || xr == check-1); 346 } 347#endif 348 349#if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT) 350 { 351 SkFixed s, c; 352 s = SkFixedSinCos(0, &c); 353 REPORTER_ASSERT(reporter, s == 0); 354 REPORTER_ASSERT(reporter, c == SK_Fixed1); 355 } 356 357 int maxDiff = 0; 358 for (i = 0; i < 10000; i++) { 359 SkFixed rads = rand.nextS() >> 10; 360 double frads = SkFixedToFloat(rads); 361 362 SkFixed s, c; 363 s = SkScalarSinCos(rads, &c); 364 365 double fs = sin(frads); 366 double fc = cos(frads); 367 368 SkFixed is = SkFloatToFixed(fs); 369 SkFixed ic = SkFloatToFixed(fc); 370 371 maxDiff = SkMax32(maxDiff, SkAbs32(is - s)); 372 maxDiff = SkMax32(maxDiff, SkAbs32(ic - c)); 373 } 374 SkDebugf("SinCos: maximum error = %d\n", maxDiff); 375#endif 376} 377 378/////////////////////////////////////////////////////////////////////////////// 379 380namespace skiatest { 381 382 class MathTest : public Test { 383 public: 384 static Test* Factory(void*) { 385 return SkNEW(MathTest); 386 } 387 388 protected: 389 virtual void onGetName(SkString* name) { 390 name->set("Math"); 391 } 392 393 virtual void onRun(Reporter* reporter) { 394 TestMath(reporter); 395 } 396 }; 397 398 static TestRegistry gReg(MathTest::Factory); 399} 400 401