xref: /openbmc/qemu/tests/fp/fp-test-log2.c (revision 1cbd2d91)
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_rounding_mode(float_round_nearest_even, &qsf);
74 
75     test.d = 0.0;
76     real.d = -__builtin_inf();
77     soft.i = float64_log2(test.i, &qsf);
78     compare(test, real, soft, true);
79 
80     test.d = 1.0;
81     real.d = 0.0;
82     soft.i = float64_log2(test.i, &qsf);
83     compare(test, real, soft, true);
84 
85     test.d = 2.0;
86     real.d = 1.0;
87     soft.i = float64_log2(test.i, &qsf);
88     compare(test, real, soft, true);
89 
90     test.d = 4.0;
91     real.d = 2.0;
92     soft.i = float64_log2(test.i, &qsf);
93     compare(test, real, soft, true);
94 
95     test.d = 0x1p64;
96     real.d = 64.0;
97     soft.i = float64_log2(test.i, &qsf);
98     compare(test, real, soft, true);
99 
100     test.d = __builtin_inf();
101     real.d = __builtin_inf();
102     soft.i = float64_log2(test.i, &qsf);
103     compare(test, real, soft, true);
104 
105     for (i = 0; i < 10000; ++i) {
106         test.d = drand48() + 1.0;    /* [1.0, 2.0) */
107         real.d = log2(test.d);
108         soft.i = float64_log2(test.i, &qsf);
109         compare(test, real, soft, false);
110 
111         test.d = drand48() * 100;    /* [0.0, 100) */
112         real.d = log2(test.d);
113         soft.i = float64_log2(test.i, &qsf);
114         compare(test, real, soft, false);
115     }
116 
117     return 0;
118 }
119