aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/ScalarTest.cpp
blob: 6c2df73199369ea50c313cd4333bcb72d6980d7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Test.h"
#include "SkFloatingPoint.h"
#include "SkMath.h"
#include "SkPoint.h"
#include "SkRandom.h"

#ifdef SK_CAN_USE_FLOAT

static bool isFinite_int(float x) {
    uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
    int exponent = bits << 1 >> 24;
    return exponent != 0xFF;
}

static bool isFinite_float(float x) {
    return sk_float_isfinite(x);
}

static bool isFinite_mulzero(float x) {
    float y = x * 0;
    return y == y;
}

// return true if the float is finite
typedef bool (*IsFiniteProc1)(float);

static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
    return proc(x) && proc(y);
}

static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
    return proc(x * 0 + y * 0);
}

// return true if both floats are finite
typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);

#endif

static void test_isfinite(skiatest::Reporter* reporter) {
#ifdef SK_CAN_USE_FLOAT
    struct Rec {
        float   fValue;
        bool    fIsFinite;
    };
    
    float max = 3.402823466e+38f;
    float inf = max * max;
    float nan = 1 / sk_float_sin(0);

    const Rec data[] = {
        {   0,          true    },
        {   1,          true    },
        {  -1,          true    },
        {  max * 0.75,  true    },
        {  max,         true    },
        {  -max * 0.75, true    },
        {  -max,        true    },
        {  inf,         false   },
        { -inf,         false   },
        {  nan,         false   },
    };

    const IsFiniteProc1 gProc1[] = {
        isFinite_int,
        isFinite_float,
        isFinite_mulzero
    };
    const IsFiniteProc2 gProc2[] = {
        isFinite2_and,
        isFinite2_mulzeroadd
    };

    int i, n = SK_ARRAY_COUNT(data);

    for (i = 0; i < n; ++i) {
        for (int k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
            const Rec& rec = data[i];
            bool finite = gProc1[k](rec.fValue);
            REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
        }
    }

    for (i = 0; i < n; ++i) {
        const Rec& rec0 = data[i];
        for (int j = 0; j < n; ++j) {
            const Rec& rec1 = data[j];
            for (int k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
                IsFiniteProc1 proc1 = gProc1[k];
                
                for (int m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
                    bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
                    bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
                    REPORTER_ASSERT(reporter, finite2 == finite);
                }
            }
        }
    }
#endif
}

static void TestScalar(skiatest::Reporter* reporter) {
    test_isfinite(reporter);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)