source: trunk/test/unit/real.cpp @ 1130

Last change on this file since 1130 was 1130, checked in by sam, 8 years ago

math: implement ulp() for reals, which returns the smallest real y > 0 such
that x + y != x, and nextafter() which behaves like the C function.

File size: 10.1 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cmath>
16
17#include "core.h"
18#include "lol/unit.h"
19
20namespace lol
21{
22
23LOLUNIT_FIXTURE(RealTest)
24{
25    LOLUNIT_TEST(Constants)
26    {
27        double a0 = real::R_0;
28        double a1 = real::R_1;
29        double a2 = real::R_2;
30        double a10 = real::R_10;
31
32        LOLUNIT_ASSERT_EQUAL(a0, 0.0);
33        LOLUNIT_ASSERT_EQUAL(a1, 1.0);
34        LOLUNIT_ASSERT_EQUAL(a2, 2.0);
35        LOLUNIT_ASSERT_EQUAL(a10, 10.0);
36
37        double b1 = log(real::R_E);
38        double b2 = log2(real::R_2);
39        LOLUNIT_ASSERT_EQUAL(b1, 1.0);
40        LOLUNIT_ASSERT_EQUAL(b2, 1.0);
41
42        double c1 = exp(re(real::R_LOG2E));
43        double c2 = log(exp2(real::R_LOG2E));
44        LOLUNIT_ASSERT_EQUAL(c1, 2.0);
45        LOLUNIT_ASSERT_EQUAL(c2, 1.0);
46
47        double d1 = exp(re(real::R_LOG10E));
48        LOLUNIT_ASSERT_EQUAL(d1, 10.0);
49
50        double e1 = exp(real::R_LN2);
51        LOLUNIT_ASSERT_EQUAL(e1, 2.0);
52
53        double f1 = exp(real::R_LN10);
54        LOLUNIT_ASSERT_EQUAL(f1, 10.0);
55
56        double g1 = sin(real::R_PI);
57        double g2 = cos(real::R_PI);
58        LOLUNIT_ASSERT_DOUBLES_EQUAL(g1, 0.0, 1e-100);
59        LOLUNIT_ASSERT_EQUAL(g2, -1.0);
60
61        double h1 = sin(real::R_PI_2);
62        double h2 = cos(real::R_PI_2);
63        LOLUNIT_ASSERT_EQUAL(h1, 1.0);
64        LOLUNIT_ASSERT_DOUBLES_EQUAL(h2, 0.0, 1e-100);
65
66        double i1 = sin(real::R_PI_4) * sin(real::R_PI_4);
67        double i2 = cos(real::R_PI_4) * cos(real::R_PI_4);
68        LOLUNIT_ASSERT_EQUAL(i1, 0.5);
69        LOLUNIT_ASSERT_EQUAL(i2, 0.5);
70    }
71
72    LOLUNIT_TEST(FloatToReal)
73    {
74        float a1 = real(0.0f);
75        float a2 = real(-0.0f);
76        float a3 = real(1.0f);
77        float a4 = real(-1.0f);
78        float a5 = real(1.5f);
79        float a6 = real(12345678.0f);
80
81        LOLUNIT_ASSERT_EQUAL(a1, 0.0f);
82        LOLUNIT_ASSERT_EQUAL(a2, -0.0f);
83        LOLUNIT_ASSERT_EQUAL(a3, 1.0f);
84        LOLUNIT_ASSERT_EQUAL(a4, -1.0f);
85        LOLUNIT_ASSERT_EQUAL(a5, 1.5f);
86        LOLUNIT_ASSERT_EQUAL(a6, 12345678.0f);
87    }
88
89    LOLUNIT_TEST(DoubleToReal)
90    {
91        double a1 = real(0.0);
92        double a2 = real(-0.0);
93        double a3 = real(1.0);
94        double a4 = real(-1.0);
95        double a5 = real(1.5);
96        double a6 = real(1234567876543210.0);
97
98        LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, 0.0, 0.0);
99        LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, -0.0, 0.0);
100        LOLUNIT_ASSERT_DOUBLES_EQUAL(a3, 1.0, 0.0);
101        LOLUNIT_ASSERT_DOUBLES_EQUAL(a4, -1.0, 0.0);
102        LOLUNIT_ASSERT_DOUBLES_EQUAL(a5, 1.5, 0.0);
103        LOLUNIT_ASSERT_DOUBLES_EQUAL(a6, 1234567876543210.0, 0.0);
104    }
105
106    LOLUNIT_TEST(StringToReal)
107    {
108        float a1 = real("0");
109        float a2 = real("1");
110        float a3 = real("-1");
111        /* 2^-128 * 2^128 */
112        float a4 = real("0.0000000000000000000000000000000000000029387358770"
113                        "557187699218413430556141945466638919302188037718792"
114                        "6569604314863681793212890625")
115                 * real("340282366920938463463374607431768211456");
116
117        LOLUNIT_ASSERT_EQUAL(a1, 0.0f);
118        LOLUNIT_ASSERT_EQUAL(a2, 1.0f);
119        LOLUNIT_ASSERT_EQUAL(a3, -1.0f);
120        LOLUNIT_ASSERT_EQUAL(a4, 1.0f);
121    }
122
123    LOLUNIT_TEST(UnaryMinus)
124    {
125        float a1 = - real(1.0f);
126        float a2 = - real(-1.0f);
127        float a3 = - real(0.0f);
128        float a4 = - real(-0.0f);
129
130        LOLUNIT_ASSERT_EQUAL(a1, -1.0f);
131        LOLUNIT_ASSERT_EQUAL(a2, 1.0f);
132        LOLUNIT_ASSERT_EQUAL(a3, -0.0f);
133        LOLUNIT_ASSERT_EQUAL(a4, 0.0f);
134    }
135
136    LOLUNIT_TEST(Comparison)
137    {
138        LOLUNIT_ASSERT(real(1.0f) > real(0.5f));
139        LOLUNIT_ASSERT(real(1.0f) >= real(0.5f));
140        LOLUNIT_ASSERT(real(1.0f) >= real(1.0f));
141
142        LOLUNIT_ASSERT(real(-1.0f) < real(-0.5f));
143        LOLUNIT_ASSERT(real(-1.0f) <= real(-0.5f));
144        LOLUNIT_ASSERT(real(-1.0f) <= real(-1.0f));
145
146        LOLUNIT_ASSERT(real(-1.0f) < real(0.5f));
147        LOLUNIT_ASSERT(real(-0.5f) < real(1.0f));
148        LOLUNIT_ASSERT(real(-1.0f) <= real(0.5f));
149        LOLUNIT_ASSERT(real(-0.5f) <= real(1.0f));
150
151        LOLUNIT_ASSERT(real(1.0f) > real(-0.5f));
152        LOLUNIT_ASSERT(real(0.5f) > real(-1.0f));
153        LOLUNIT_ASSERT(real(1.0f) >= real(-0.5f));
154        LOLUNIT_ASSERT(real(0.5f) >= real(-1.0f));
155    }
156
157    LOLUNIT_TEST(Addition)
158    {
159        float a1 = real(1.0f) + real(0.0f);
160        float a2 = real(0.0f) + real(1.0f);
161        float a3 = real(1.0f) + real(1.0f);
162        float a4 = real(-1.0f) + real(-1.0f);
163        float a5 = real(1.0f) + real(0.125f);
164        double a6 = real(3.13609818956293918)
165                  + real(0.00005972154828114);
166        float a7 = real(1.0f) + real(-0.125f);
167        double a8 = real(0.10000000002) + real(-2.0e-11);
168
169        LOLUNIT_ASSERT_EQUAL(a1, 1.0f);
170        LOLUNIT_ASSERT_EQUAL(a2, 1.0f);
171        LOLUNIT_ASSERT_EQUAL(a3, 2.0f);
172        LOLUNIT_ASSERT_EQUAL(a4, -2.0f);
173        LOLUNIT_ASSERT_EQUAL(a5, 1.125f);
174        LOLUNIT_ASSERT_DOUBLES_EQUAL(a6, 3.1361579, 0.000001);
175        LOLUNIT_ASSERT_EQUAL(a7, 0.875f);
176        LOLUNIT_ASSERT_DOUBLES_EQUAL(a8, 0.1, 1.0e-13);
177    }
178
179    LOLUNIT_TEST(Subtraction)
180    {
181        float a1 = real(1.0f) + real(1e20f) - real(1e20f);
182
183        LOLUNIT_ASSERT_EQUAL(a1, 1.0f);
184    }
185
186    LOLUNIT_TEST(Multiplication)
187    {
188        real x(1.25f);
189        real y(1.5f);
190        real z(1.99999f);
191        real w(-1.5f);
192
193        float m1 = x * x;
194        float m2 = y * y;
195        float m3 = z * z;
196        float m4 = w * w;
197
198        LOLUNIT_ASSERT_EQUAL(m1, 1.25f * 1.25f);
199        LOLUNIT_ASSERT_EQUAL(m2, 1.5f * 1.5f);
200        LOLUNIT_ASSERT_EQUAL(m3, 1.99999f * 1.99999f);
201        LOLUNIT_ASSERT_EQUAL(m4, -1.5f * -1.5f);
202    }
203
204    LOLUNIT_TEST(ExactDivision)
205    {
206        float m1 = real::R_1 / real::R_1;
207        float m2 = real::R_2 / real::R_1;
208        float m3 = real::R_1 / real::R_2;
209        float m4 = real::R_2 / real::R_2;
210        float m5 = real::R_1 / -real::R_2;
211
212        LOLUNIT_ASSERT_EQUAL(m1, 1.0f);
213        LOLUNIT_ASSERT_EQUAL(m2, 2.0f);
214        LOLUNIT_ASSERT_EQUAL(m3, 0.5f);
215        LOLUNIT_ASSERT_EQUAL(m4, 1.0f);
216        LOLUNIT_ASSERT_EQUAL(m5, -0.5f);
217    }
218
219    LOLUNIT_TEST(InexactDivision)
220    {
221        /* 1 / 3 * 3 should be close to 1... check that it does not differ
222         * by more than 2^-k where k is the number of bits in the mantissa. */
223        real a = real::R_1 / real::R_3 * real::R_3;
224        real b = ldexp(real::R_1 - a, real::BIGITS * real::BIGIT_BITS);
225
226        LOLUNIT_ASSERT_LEQUAL((double)fabs(b), 1.0);
227    }
228
229    LOLUNIT_TEST(LoadExp)
230    {
231        real a1(1.5);
232        real a2(-1.5);
233        real a3(0.0);
234
235        LOLUNIT_ASSERT_EQUAL((double)ldexp(a1, 7), 192.0);
236        LOLUNIT_ASSERT_EQUAL((double)ldexp(a1, -7), 0.01171875);
237
238        LOLUNIT_ASSERT_EQUAL((double)ldexp(a2, 7), -192.0);
239        LOLUNIT_ASSERT_EQUAL((double)ldexp(a2, -7), -0.01171875);
240
241        LOLUNIT_ASSERT_EQUAL((double)ldexp(a3, 7), 0.0);
242        LOLUNIT_ASSERT_EQUAL((double)ldexp(a3, -7), 0.0);
243    }
244
245    LOLUNIT_TEST(Ulp)
246    {
247        real a1 = real::R_PI;
248
249        LOLUNIT_ASSERT_NOT_EQUAL((double)(a1 + ulp(a1) - a1), 0.0);
250        LOLUNIT_ASSERT_EQUAL((double)(a1 + ulp(a1) / 2 - a1), 0.0);
251    }
252
253    LOLUNIT_TEST(Bool)
254    {
255        real a = 0.0;
256        LOLUNIT_ASSERT(!a);
257
258        a = -0.0;
259        LOLUNIT_ASSERT(!a);
260
261        a = 1234.0;
262        LOLUNIT_ASSERT(a);
263        LOLUNIT_ASSERT(!!a);
264
265        a = -1234.0;
266        LOLUNIT_ASSERT(a);
267        LOLUNIT_ASSERT(!!a);
268    }
269
270    LOLUNIT_TEST(AsinAcos)
271    {
272        double tests[] =
273        {
274            -1024.0, -1023.0, -513.0, -512.0, -511.0, -1.0, -0.0,
275            0.0, 1.0, 511.0, 512.0, 513.0, 1023.0, 1024.0
276        };
277
278        for (unsigned int n = 0; n < sizeof(tests) / sizeof(*tests); n++)
279        {
280            double a = tests[n] / 1024;
281            double b = sin(asin((real)a));
282            double c = cos(acos((real)a));
283
284            LOLUNIT_SET_CONTEXT(a);
285            LOLUNIT_ASSERT_DOUBLES_EQUAL(b, a, 1e-100);
286            LOLUNIT_ASSERT_DOUBLES_EQUAL(c, a, 1e-100);
287        }
288    }
289
290    LOLUNIT_TEST(FloorCeilEtc)
291    {
292        double tests[] =
293        {
294            -2.0,  -2.0, -2.0,  -2.0,
295            -1.5,  -2.0, -1.0,  -2.0,
296            -1.0,  -1.0, -1.0,  -1.0,
297            -0.0,  -0.0, -0.0,  -0.0,
298             0.0,   0.0,  0.0,   0.0,
299             0.25,  0.0,  1.0,   0.0,
300             0.375, 0.0,  1.0,   0.0,
301             0.5,   0.0,  1.0,   1.0,
302             1.0,   1.0,  1.0,   1.0,
303             1.5,   1.0,  2.0,   2.0,
304             2.0,   2.0,  2.0,   2.0,
305             2.5,   2.0,  3.0,   3.0,
306             3.0,   3.0,  3.0,   3.0,
307            8192.0,     8192.0, 8192.0, 8192.0,
308            8192.03125, 8192.0, 8193.0, 8192.0,
309            8192.5,     8192.0, 8193.0, 8193.0,
310            8193.0,     8193.0, 8193.0, 8193.0,
311            549755813888.0,     549755813888.0, 549755813888.0, 549755813888.0,
312            549755813888.03125, 549755813888.0, 549755813889.0, 549755813888.0,
313            549755813888.5,     549755813888.0, 549755813889.0, 549755813889.0,
314            549755813889.0,     549755813889.0, 549755813889.0, 549755813889.0,
315        };
316
317        for (unsigned int n = 0; n < sizeof(tests) / sizeof(*tests); n += 4)
318        {
319            double a0 = floor((real)tests[n]);
320            double b0 = tests[n + 1];
321            double a1 = ceil((real)tests[n]);
322            double b1 = tests[n + 2];
323            double a2 = round((real)tests[n]);
324            double b2 = tests[n + 3];
325
326            LOLUNIT_ASSERT_EQUAL(b0, a0);
327            LOLUNIT_ASSERT_EQUAL(b1, a1);
328            LOLUNIT_ASSERT_EQUAL(b2, a2);
329        }
330    }
331
332    LOLUNIT_TEST(Pow)
333    {
334        double a1 = pow(-real::R_2, real::R_2);
335        double b1 = 4.0;
336        LOLUNIT_ASSERT_DOUBLES_EQUAL(a1, b1, 1.0e-13);
337
338        double a2 = pow(-real::R_2, real::R_3);
339        double b2 = -8.0;
340        LOLUNIT_ASSERT_DOUBLES_EQUAL(a2, b2, 1.0e-13);
341    }
342};
343
344} /* namespace lol */
345
Note: See TracBrowser for help on using the repository browser.