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_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