1 /*
2 * fp-test-log2.c - test QEMU's softfloat log2
3 *
4 * Copyright (C) 2020, Linaro, Ltd.
5 *
6 * License: GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
9 #ifndef HW_POISON_H
10 #error Must define HW_POISON_H to work around TARGET_* poisoning
11 #endif
12
13 #include "qemu/osdep.h"
14 #include "qemu/cutils.h"
15 #include <math.h>
16 #include "fpu/softfloat.h"
17
18 typedef union {
19 double d;
20 float64 i;
21 } ufloat64;
22
23 static int errors;
24
compare(ufloat64 test,ufloat64 real,ufloat64 soft,bool exact)25 static void compare(ufloat64 test, ufloat64 real, ufloat64 soft, bool exact)
26 {
27 int msb;
28 uint64_t ulp = UINT64_MAX;
29
30 if (real.i == soft.i) {
31 return;
32 }
33 msb = 63 - __builtin_clzll(real.i ^ soft.i);
34
35 if (msb < 52) {
36 if (real.i > soft.i) {
37 ulp = real.i - soft.i;
38 } else {
39 ulp = soft.i - real.i;
40 }
41 }
42
43 /* glibc allows 3 ulp error in its libm-test-ulps; allow 4 here */
44 if (!exact && ulp <= 4) {
45 return;
46 }
47
48 printf("test: %016" PRIx64 " %+.13a\n"
49 " sf: %016" PRIx64 " %+.13a\n"
50 "libm: %016" PRIx64 " %+.13a\n",
51 test.i, test.d, soft.i, soft.d, real.i, real.d);
52
53 if (msb == 63) {
54 printf("Error in sign!\n\n");
55 } else if (msb >= 52) {
56 printf("Error in exponent: %d\n\n",
57 (int)(soft.i >> 52) - (int)(real.i >> 52));
58 } else {
59 printf("Error in fraction: %" PRIu64 " ulp\n\n", ulp);
60 }
61
62 if (++errors == 20) {
63 exit(1);
64 }
65 }
66
main(int ac,char ** av)67 int main(int ac, char **av)
68 {
69 ufloat64 test, real, soft;
70 float_status qsf = {0};
71 int i;
72
73 set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
74 set_float_default_nan_pattern(0b01000000, &qsf);
75 set_float_rounding_mode(float_round_nearest_even, &qsf);
76
77 test.d = 0.0;
78 real.d = -__builtin_inf();
79 soft.i = float64_log2(test.i, &qsf);
80 compare(test, real, soft, true);
81
82 test.d = 1.0;
83 real.d = 0.0;
84 soft.i = float64_log2(test.i, &qsf);
85 compare(test, real, soft, true);
86
87 test.d = 2.0;
88 real.d = 1.0;
89 soft.i = float64_log2(test.i, &qsf);
90 compare(test, real, soft, true);
91
92 test.d = 4.0;
93 real.d = 2.0;
94 soft.i = float64_log2(test.i, &qsf);
95 compare(test, real, soft, true);
96
97 test.d = 0x1p64;
98 real.d = 64.0;
99 soft.i = float64_log2(test.i, &qsf);
100 compare(test, real, soft, true);
101
102 test.d = __builtin_inf();
103 real.d = __builtin_inf();
104 soft.i = float64_log2(test.i, &qsf);
105 compare(test, real, soft, true);
106
107 for (i = 0; i < 10000; ++i) {
108 test.d = drand48() + 1.0; /* [1.0, 2.0) */
109 real.d = log2(test.d);
110 soft.i = float64_log2(test.i, &qsf);
111 compare(test, real, soft, false);
112
113 test.d = drand48() * 100; /* [0.0, 100) */
114 real.d = log2(test.d);
115 soft.i = float64_log2(test.i, &qsf);
116 compare(test, real, soft, false);
117 }
118
119 return 0;
120 }
121