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