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
14#ifdef SK_CAN_USE_FLOAT
15
16static bool isFinite_int(float x) {
17    uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
18    int exponent = bits << 1 >> 24;
19    return exponent != 0xFF;
20}
21
22static bool isFinite_float(float x) {
23    return sk_float_isfinite(x);
24}
25
26static bool isFinite_mulzero(float x) {
27    float y = x * 0;
28    return y == y;
29}
30
31// return true if the float is finite
32typedef bool (*IsFiniteProc1)(float);
33
34static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
35    return proc(x) && proc(y);
36}
37
38static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
39    return proc(x * 0 + y * 0);
40}
41
42// return true if both floats are finite
43typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
44
45#endif
46
47enum FloatClass {
48    kFinite,
49    kInfinite,
50    kNaN
51};
52
53static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
54    // our sk_float_is... function may return int instead of bool,
55    // hence the double ! to turn it into a bool
56    REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
57    REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
58    REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
59}
60
61static void test_isfinite(skiatest::Reporter* reporter) {
62#ifdef SK_CAN_USE_FLOAT
63    struct Rec {
64        float   fValue;
65        bool    fIsFinite;
66    };
67
68    float max = 3.402823466e+38f;
69    float inf = max * max;
70    float nan = inf * 0;
71
72    test_floatclass(reporter,    0, kFinite);
73    test_floatclass(reporter,  max, kFinite);
74    test_floatclass(reporter, -max, kFinite);
75    test_floatclass(reporter,  inf, kInfinite);
76    test_floatclass(reporter, -inf, kInfinite);
77    test_floatclass(reporter,  nan, kNaN);
78    test_floatclass(reporter, -nan, kNaN);
79
80    const Rec data[] = {
81        {   0,          true    },
82        {   1,          true    },
83        {  -1,          true    },
84        {  max * 0.75,  true    },
85        {  max,         true    },
86        {  -max * 0.75, true    },
87        {  -max,        true    },
88        {  inf,         false   },
89        { -inf,         false   },
90        {  nan,         false   },
91    };
92
93    const IsFiniteProc1 gProc1[] = {
94        isFinite_int,
95        isFinite_float,
96        isFinite_mulzero
97    };
98    const IsFiniteProc2 gProc2[] = {
99        isFinite2_and,
100        isFinite2_mulzeroadd
101    };
102
103    size_t i, n = SK_ARRAY_COUNT(data);
104
105    for (i = 0; i < n; ++i) {
106        for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
107            const Rec& rec = data[i];
108            bool finite = gProc1[k](rec.fValue);
109            REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
110        }
111    }
112
113    for (i = 0; i < n; ++i) {
114        const Rec& rec0 = data[i];
115        for (size_t j = 0; j < n; ++j) {
116            const Rec& rec1 = data[j];
117            for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
118                IsFiniteProc1 proc1 = gProc1[k];
119
120                for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
121                    bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
122                    bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
123                    REPORTER_ASSERT(reporter, finite2 == finite);
124                }
125            }
126        }
127    }
128#endif
129}
130
131static void TestScalar(skiatest::Reporter* reporter) {
132    test_isfinite(reporter);
133}
134
135#include "TestClassDef.h"
136DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)
137
138