| reed@android.com | ed67331 | 2009-02-27 16:24:51 +0000 | [diff] [blame] | 1 | #include "Test.h" | 
 | 2 | #include "SkPoint.h" | 
 | 3 | #include "SkRandom.h" | 
 | 4 |  | 
 | 5 | #if defined(SkLONGLONG) | 
 | 6 | static 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 |  | 
 | 27 | static 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 |  | 
 | 42 | static 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 |  */ | 
 | 51 | static 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 |  | 
 | 65 | static 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 |  | 
 | 74 | static 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 |  | 
 | 80 | static 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 |  | 
 | 86 | static 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 |  | 
 | 93 | static 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 |  | 
 | 99 | static 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 |  | 
 | 106 | static 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 |  | 
 | 114 | static 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 |  | 
 | 151 | static 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 |  | 
 | 174 | static 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 |      | 
| reed@android.com | ed67331 | 2009-02-27 16:24:51 +0000 | [diff] [blame] | 216 |     x = SkFixedSqrt(SK_Fixed1); | 
 | 217 |     REPORTER_ASSERT(reporter, x == SK_Fixed1); | 
 | 218 |     x = SkFixedSqrt(SK_Fixed1/4); | 
 | 219 |     REPORTER_ASSERT(reporter, x == SK_Fixed1/2); | 
 | 220 |     x = SkFixedSqrt(SK_Fixed1*4); | 
 | 221 |     REPORTER_ASSERT(reporter, x == SK_Fixed1*2); | 
 | 222 |      | 
 | 223 |     x = SkFractSqrt(SK_Fract1); | 
 | 224 |     REPORTER_ASSERT(reporter, x == SK_Fract1); | 
 | 225 |     x = SkFractSqrt(SK_Fract1/4); | 
 | 226 |     REPORTER_ASSERT(reporter, x == SK_Fract1/2); | 
 | 227 |     x = SkFractSqrt(SK_Fract1/16); | 
 | 228 |     REPORTER_ASSERT(reporter, x == SK_Fract1/4); | 
 | 229 |      | 
 | 230 |     for (i = 1; i < 100; i++) { | 
 | 231 |         x = SkFixedSqrt(SK_Fixed1 * i * i); | 
 | 232 |         REPORTER_ASSERT(reporter, x == SK_Fixed1 * i); | 
 | 233 |     } | 
 | 234 |      | 
 | 235 |     for (i = 0; i < 1000; i++) { | 
 | 236 |         int value = rand.nextS16(); | 
 | 237 |         int max = rand.nextU16(); | 
 | 238 |          | 
 | 239 |         int clamp = SkClampMax(value, max); | 
 | 240 |         int clamp2 = value < 0 ? 0 : (value > max ? max : value); | 
 | 241 |         REPORTER_ASSERT(reporter, clamp == clamp2); | 
 | 242 |     } | 
 | 243 |      | 
 | 244 |     for (i = 0; i < 100000; i++) { | 
 | 245 |         SkPoint p; | 
 | 246 |          | 
 | 247 |         p.setLength(rand.nextS(), rand.nextS(), SK_Scalar1); | 
 | 248 |         check_length(reporter, p, SK_Scalar1); | 
 | 249 |         p.setLength(rand.nextS() >> 13, rand.nextS() >> 13, SK_Scalar1); | 
 | 250 |         check_length(reporter, p, SK_Scalar1); | 
 | 251 |     } | 
 | 252 |      | 
 | 253 |     { | 
 | 254 |         SkFixed result = SkFixedDiv(100, 100); | 
 | 255 |         REPORTER_ASSERT(reporter, result == SK_Fixed1); | 
 | 256 |         result = SkFixedDiv(1, SK_Fixed1); | 
 | 257 |         REPORTER_ASSERT(reporter, result == 1); | 
 | 258 |     } | 
 | 259 |      | 
 | 260 | #ifdef SK_CAN_USE_FLOAT | 
 | 261 |     unittest_fastfloat(reporter); | 
 | 262 | #endif | 
 | 263 |      | 
 | 264 | #ifdef SkLONGLONG | 
 | 265 |     for (i = 0; i < 100000; i++) { | 
 | 266 |         SkFixed numer = rand.nextS(); | 
 | 267 |         SkFixed denom = rand.nextS(); | 
 | 268 |         SkFixed result = SkFixedDiv(numer, denom); | 
 | 269 |         SkLONGLONG check = ((SkLONGLONG)numer << 16) / denom; | 
 | 270 |          | 
 | 271 |         (void)SkCLZ(numer); | 
 | 272 |         (void)SkCLZ(denom); | 
 | 273 |          | 
 | 274 |         REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32); | 
 | 275 |         if (check > SK_MaxS32) { | 
 | 276 |             check = SK_MaxS32; | 
 | 277 |         } else if (check < -SK_MaxS32) { | 
 | 278 |             check = SK_MinS32; | 
 | 279 |         } | 
 | 280 |         REPORTER_ASSERT(reporter, result == (int32_t)check); | 
 | 281 |          | 
 | 282 |         result = SkFractDiv(numer, denom); | 
 | 283 |         check = ((SkLONGLONG)numer << 30) / denom; | 
 | 284 |          | 
 | 285 |         REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32); | 
 | 286 |         if (check > SK_MaxS32) { | 
 | 287 |             check = SK_MaxS32; | 
 | 288 |         } else if (check < -SK_MaxS32) { | 
 | 289 |             check = SK_MinS32; | 
 | 290 |         } | 
 | 291 |         REPORTER_ASSERT(reporter, result == (int32_t)check); | 
 | 292 |          | 
 | 293 |         // make them <= 2^24, so we don't overflow in fixmul | 
 | 294 |         numer = numer << 8 >> 8; | 
 | 295 |         denom = denom << 8 >> 8; | 
 | 296 |          | 
 | 297 |         result = SkFixedMul(numer, denom); | 
 | 298 |         SkFixed r2 = symmetric_fixmul(numer, denom); | 
 | 299 |         //        SkASSERT(result == r2); | 
 | 300 |          | 
 | 301 |         result = SkFixedMul(numer, numer); | 
 | 302 |         r2 = SkFixedSquare(numer); | 
 | 303 |         REPORTER_ASSERT(reporter, result == r2); | 
 | 304 |          | 
 | 305 | #ifdef SK_CAN_USE_FLOAT | 
 | 306 |         if (numer >= 0 && denom >= 0) { | 
 | 307 |             SkFixed mean = SkFixedMean(numer, denom); | 
 | 308 |             float fm = sk_float_sqrt(sk_float_abs(SkFixedToFloat(numer) * SkFixedToFloat(denom))); | 
 | 309 |             SkFixed mean2 = SkFloatToFixed(fm); | 
 | 310 |             int diff = SkAbs32(mean - mean2); | 
 | 311 |             REPORTER_ASSERT(reporter, diff <= 1); | 
 | 312 |         } | 
 | 313 |          | 
 | 314 |         { | 
 | 315 |             SkFixed mod = SkFixedMod(numer, denom); | 
 | 316 |             float n = SkFixedToFloat(numer); | 
 | 317 |             float d = SkFixedToFloat(denom); | 
 | 318 |             float m = sk_float_mod(n, d); | 
 | 319 |             REPORTER_ASSERT(reporter, mod == 0 || (mod < 0) == (m < 0)); // ensure the same sign | 
 | 320 |             int diff = SkAbs32(mod - SkFloatToFixed(m)); | 
 | 321 |             REPORTER_ASSERT(reporter, (diff >> 7) == 0); | 
 | 322 |         } | 
 | 323 | #endif | 
 | 324 |     } | 
 | 325 | #endif | 
 | 326 |      | 
 | 327 | #ifdef SK_CAN_USE_FLOAT | 
 | 328 |     for (i = 0; i < 100000; i++) { | 
 | 329 |         SkFract x = rand.nextU() >> 1; | 
 | 330 |         double xx = (double)x / SK_Fract1; | 
 | 331 |         SkFract xr = SkFractSqrt(x); | 
 | 332 |         SkFract check = SkFloatToFract(sqrt(xx)); | 
 | 333 |         REPORTER_ASSERT(reporter, xr == check || xr == check-1 || xr == check+1); | 
 | 334 |          | 
 | 335 |         xr = SkFixedSqrt(x); | 
 | 336 |         xx = (double)x / SK_Fixed1; | 
 | 337 |         check = SkFloatToFixed(sqrt(xx)); | 
 | 338 |         REPORTER_ASSERT(reporter, xr == check || xr == check-1); | 
 | 339 |          | 
 | 340 |         xr = SkSqrt32(x); | 
 | 341 |         xx = (double)x; | 
 | 342 |         check = (int32_t)sqrt(xx); | 
 | 343 |         REPORTER_ASSERT(reporter, xr == check || xr == check-1); | 
 | 344 |     } | 
 | 345 | #endif | 
 | 346 |      | 
 | 347 | #if !defined(SK_SCALAR_IS_FLOAT) && defined(SK_CAN_USE_FLOAT) | 
 | 348 |     { | 
 | 349 |         SkFixed s, c; | 
 | 350 |         s = SkFixedSinCos(0, &c); | 
 | 351 |         REPORTER_ASSERT(reporter, s == 0); | 
 | 352 |         REPORTER_ASSERT(reporter, c == SK_Fixed1); | 
 | 353 |     } | 
 | 354 |      | 
 | 355 |     int maxDiff = 0; | 
 | 356 |     for (i = 0; i < 10000; i++) { | 
 | 357 |         SkFixed rads = rand.nextS() >> 10; | 
 | 358 |         double frads = SkFixedToFloat(rads); | 
 | 359 |          | 
 | 360 |         SkFixed s, c; | 
 | 361 |         s = SkScalarSinCos(rads, &c); | 
 | 362 |          | 
 | 363 |         double fs = sin(frads); | 
 | 364 |         double fc = cos(frads); | 
 | 365 |          | 
 | 366 |         SkFixed is = SkFloatToFixed(fs); | 
 | 367 |         SkFixed ic = SkFloatToFixed(fc); | 
 | 368 |          | 
 | 369 |         maxDiff = SkMax32(maxDiff, SkAbs32(is - s)); | 
 | 370 |         maxDiff = SkMax32(maxDiff, SkAbs32(ic - c)); | 
 | 371 |     } | 
 | 372 |     SkDebugf("SinCos: maximum error = %d\n", maxDiff); | 
 | 373 | #endif | 
 | 374 | } | 
 | 375 |  | 
| reed@android.com | d8730ea | 2009-02-27 22:06:06 +0000 | [diff] [blame^] | 376 | #include "TestClassDef.h" | 
 | 377 | DEFINE_TESTCLASS("Math", MathTestClass, TestMath) |