1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "Test.h"
9#include "SkRandom.h"
10#include <math.h>
11
12struct BoolTable {
13    int8_t  zero, pos, neg, toBool, sign;
14};
15
16static void bool_table_test(skiatest::Reporter* reporter,
17                            const Sk64& a, const BoolTable& table)
18{
19    REPORTER_ASSERT(reporter, a.isZero() != a.nonZero());
20
21    REPORTER_ASSERT(reporter, !a.isZero() == !table.zero);
22    REPORTER_ASSERT(reporter, !a.isPos() == !table.pos);
23    REPORTER_ASSERT(reporter, !a.isNeg() == !table.neg);
24    REPORTER_ASSERT(reporter, a.getSign() == table.sign);
25}
26
27#ifdef SkLONGLONG
28    static SkLONGLONG asLL(const Sk64& a)
29    {
30        return ((SkLONGLONG)a.fHi << 32) | a.fLo;
31    }
32#endif
33
34static void TestSk64(skiatest::Reporter* reporter) {
35    enum BoolTests {
36        kZero_BoolTest,
37        kPos_BoolTest,
38        kNeg_BoolTest
39    };
40    static const BoolTable gBoolTable[] = {
41        { 1, 0, 0, 0, 0 },
42        { 0, 1, 0, 1, 1 },
43        { 0, 0, 1, 1, -1 }
44    };
45
46    Sk64    a, b, c;
47
48    a.fHi = a.fLo = 0;
49    b.set(0);
50    c.setZero();
51    REPORTER_ASSERT(reporter, a == b);
52    REPORTER_ASSERT(reporter, a == c);
53    bool_table_test(reporter, a, gBoolTable[kZero_BoolTest]);
54
55    a.fHi = 0;  a.fLo = 5;
56    b.set(5);
57    REPORTER_ASSERT(reporter, a == b);
58    REPORTER_ASSERT(reporter, a.is32() && a.get32() == 5 && !a.is64());
59    bool_table_test(reporter, a, gBoolTable[kPos_BoolTest]);
60
61    a.fHi = -1; a.fLo = (uint32_t)-5;
62    b.set(-5);
63    REPORTER_ASSERT(reporter, a == b);
64    REPORTER_ASSERT(reporter, a.is32() && a.get32() == -5 && !a.is64());
65    bool_table_test(reporter, a, gBoolTable[kNeg_BoolTest]);
66
67    a.setZero();
68    b.set(6);
69    c.set(-6);
70    REPORTER_ASSERT(reporter, a != b && b != c && a != c);
71    REPORTER_ASSERT(reporter, !(a == b) && !(a == b) && !(a == b));
72    REPORTER_ASSERT(reporter, a < b && b > a && a <= b && b >= a);
73    REPORTER_ASSERT(reporter, c < a && a > c && c <= a && a >= c);
74    REPORTER_ASSERT(reporter, c < b && b > c && c <= b && b >= c);
75
76    // Now test add/sub
77
78    SkRandom    rand;
79    int         i;
80
81    for (i = 0; i < 1000; i++)
82    {
83        int aa = rand.nextS() >> 1;
84        int bb = rand.nextS() >> 1;
85        a.set(aa);
86        b.set(bb);
87        REPORTER_ASSERT(reporter, a.get32() == aa && b.get32() == bb);
88        c = a; c.add(bb);
89        REPORTER_ASSERT(reporter, c.get32() == aa + bb);
90        c = a; c.add(-bb);
91        REPORTER_ASSERT(reporter, c.get32() == aa - bb);
92        c = a; c.add(b);
93        REPORTER_ASSERT(reporter, c.get32() == aa + bb);
94        c = a; c.sub(b);
95        REPORTER_ASSERT(reporter, c.get32() == aa - bb);
96    }
97
98#ifdef SkLONGLONG
99    for (i = 0; i < 1000; i++)
100    {
101        rand.next64(&a); //a.fHi >>= 1; // avoid overflow
102        rand.next64(&b); //b.fHi >>= 1; // avoid overflow
103
104        if (!(i & 3))   // want to explicitly test these cases
105        {
106            a.fLo = 0;
107            b.fLo = 0;
108        }
109        else if (!(i & 7))  // want to explicitly test these cases
110        {
111            a.fHi = 0;
112            b.fHi = 0;
113        }
114
115        SkLONGLONG aa = asLL(a);
116        SkLONGLONG bb = asLL(b);
117
118        REPORTER_ASSERT(reporter, (a < b) == (aa < bb));
119        REPORTER_ASSERT(reporter, (a <= b) == (aa <= bb));
120        REPORTER_ASSERT(reporter, (a > b) == (aa > bb));
121        REPORTER_ASSERT(reporter, (a >= b) == (aa >= bb));
122        REPORTER_ASSERT(reporter, (a == b) == (aa == bb));
123        REPORTER_ASSERT(reporter, (a != b) == (aa != bb));
124
125        c = a; c.add(b);
126        REPORTER_ASSERT(reporter, asLL(c) == aa + bb);
127        c = a; c.sub(b);
128        REPORTER_ASSERT(reporter, asLL(c) == aa - bb);
129        c = a; c.rsub(b);
130        REPORTER_ASSERT(reporter, asLL(c) == bb - aa);
131        c = a; c.negate();
132        REPORTER_ASSERT(reporter, asLL(c) == -aa);
133
134        int bits = rand.nextU() & 63;
135        c = a; c.shiftLeft(bits);
136        REPORTER_ASSERT(reporter, asLL(c) == (aa << bits));
137        c = a; c.shiftRight(bits);
138        REPORTER_ASSERT(reporter, asLL(c) == (aa >> bits));
139        c = a; c.roundRight(bits);
140
141        SkLONGLONG tmp;
142
143        tmp = aa;
144        if (bits > 0)
145            tmp += (SkLONGLONG)1 << (bits - 1);
146        REPORTER_ASSERT(reporter, asLL(c) == (tmp >> bits));
147
148        c.setMul(a.fHi, b.fHi);
149        tmp = (SkLONGLONG)a.fHi * b.fHi;
150        REPORTER_ASSERT(reporter, asLL(c) == tmp);
151    }
152
153
154    for (i = 0; i < 100000; i++)
155    {
156        Sk64    wide;
157        int32_t denom = rand.nextS();
158
159        while (denom == 0)
160            denom = rand.nextS();
161        wide.setMul(rand.nextS(), rand.nextS());
162        SkLONGLONG check = wide.getLongLong();
163
164        wide.div(denom, Sk64::kTrunc_DivOption);
165        check /= denom;
166        SkLONGLONG w = wide.getLongLong();
167
168        REPORTER_ASSERT(reporter, check == w);
169
170#ifdef SK_CAN_USE_FLOAT
171        wide.setMul(rand.nextS(), rand.nextS());
172        wide.abs();
173        denom = wide.getSqrt();
174        int32_t ck = (int32_t)sqrt((double)wide.getLongLong());
175        int diff = denom - ck;
176        REPORTER_ASSERT(reporter, SkAbs32(diff) <= 1);
177
178        wide.setMul(rand.nextS(), rand.nextS());
179        Sk64    dwide;
180        dwide.setMul(rand.nextS(), rand.nextS());
181        SkFixed fixdiv = wide.getFixedDiv(dwide);
182        double dnumer = (double)wide.getLongLong();
183        double ddenom = (double)dwide.getLongLong();
184        double ddiv = dnumer / ddenom;
185        SkFixed dfixdiv;
186        if (ddiv >= (double)SK_MaxS32 / (double)SK_Fixed1)
187            dfixdiv = SK_MaxS32;
188        else if (ddiv <= -(double)SK_MaxS32 / (double)SK_Fixed1)
189            dfixdiv = SK_MinS32;
190        else
191            dfixdiv = SkFloatToFixed(dnumer / ddenom);
192        diff = fixdiv - dfixdiv;
193
194        if (SkAbs32(diff) > 1) {
195            SkDebugf(" %d === numer %g denom %g div %g xdiv %x fxdiv %x\n",
196                     i, dnumer, ddenom, ddiv, dfixdiv, fixdiv);
197        }
198        REPORTER_ASSERT(reporter, SkAbs32(diff) <= 1);
199#endif
200    }
201#endif
202}
203
204#include "TestClassDef.h"
205DEFINE_TESTCLASS("Sk64", Sk64TestClass, TestSk64)
206