mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-30 01:47:31 +00:00 
			
		
		
		
	 2fa3546c8f
			
		
	
	
		2fa3546c8f
		
	
	
	
	
		
			
			Rename to parts$N_log2. Though this is partly a ruse, since I do not believe the code will succeed for float128 without work. Which is ok for now, because we do not need this for more than float32 and float64. Since berkeley-testfloat-3 doesn't support log2, compare float64_log2 vs the system log2. Fix the errors for inputs near 1.0: test: 3ff00000000000b0 +0x1.00000000000b0p+0 sf: 3d2fa00000000000 +0x1.fa00000000000p-45 libm: 3d2fbd422b1bd36f +0x1.fbd422b1bd36fp-45 Error in fraction: 32170028290927 ulp test: 3feec24f6770b100 +0x1.ec24f6770b100p-1 sf: bfad3740d13c9ec0 -0x1.d3740d13c9ec0p-5 libm: bfad3740d13c9e98 -0x1.d3740d13c9e98p-5 Error in fraction: 40 ulp Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
		
			
				
	
	
		
			119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * fp-test-log2.c - test QEMU's softfloat log2
 | |
|  *
 | |
|  * Copyright (C) 2020, Linaro, Ltd.
 | |
|  *
 | |
|  * License: GNU GPL, version 2 or later.
 | |
|  *   See the COPYING file in the top-level directory.
 | |
|  */
 | |
| #ifndef HW_POISON_H
 | |
| #error Must define HW_POISON_H to work around TARGET_* poisoning
 | |
| #endif
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu/cutils.h"
 | |
| #include <math.h>
 | |
| #include "fpu/softfloat.h"
 | |
| 
 | |
| typedef union {
 | |
|     double d;
 | |
|     float64 i;
 | |
| } ufloat64;
 | |
| 
 | |
| static int errors;
 | |
| 
 | |
| static void compare(ufloat64 test, ufloat64 real, ufloat64 soft, bool exact)
 | |
| {
 | |
|     int msb;
 | |
|     uint64_t ulp = UINT64_MAX;
 | |
| 
 | |
|     if (real.i == soft.i) {
 | |
|         return;
 | |
|     }
 | |
|     msb = 63 - __builtin_clzll(real.i ^ soft.i);
 | |
| 
 | |
|     if (msb < 52) {
 | |
|         if (real.i > soft.i) {
 | |
|             ulp = real.i - soft.i;
 | |
|         } else {
 | |
|             ulp = soft.i - real.i;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* glibc allows 3 ulp error in its libm-test-ulps; allow 4 here */
 | |
|     if (!exact && ulp <= 4) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     printf("test: %016" PRIx64 "  %+.13a\n"
 | |
|            "  sf: %016" PRIx64 "  %+.13a\n"
 | |
|            "libm: %016" PRIx64 "  %+.13a\n",
 | |
|            test.i, test.d, soft.i, soft.d, real.i, real.d);
 | |
| 
 | |
|     if (msb == 63) {
 | |
|         printf("Error in sign!\n\n");
 | |
|     } else if (msb >= 52) {
 | |
|         printf("Error in exponent: %d\n\n",
 | |
|                (int)(soft.i >> 52) - (int)(real.i >> 52));
 | |
|     } else {
 | |
|         printf("Error in fraction: %" PRIu64 " ulp\n\n", ulp);
 | |
|     }
 | |
| 
 | |
|     if (++errors == 20) {
 | |
|         exit(1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| int main(int ac, char **av)
 | |
| {
 | |
|     ufloat64 test, real, soft;
 | |
|     float_status qsf = {0};
 | |
|     int i;
 | |
| 
 | |
|     set_float_rounding_mode(float_round_nearest_even, &qsf);
 | |
| 
 | |
|     test.d = 0.0;
 | |
|     real.d = -__builtin_inf();
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     test.d = 1.0;
 | |
|     real.d = 0.0;
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     test.d = 2.0;
 | |
|     real.d = 1.0;
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     test.d = 4.0;
 | |
|     real.d = 2.0;
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     test.d = 0x1p64;
 | |
|     real.d = 64.0;
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     test.d = __builtin_inf();
 | |
|     real.d = __builtin_inf();
 | |
|     soft.i = float64_log2(test.i, &qsf);
 | |
|     compare(test, real, soft, true);
 | |
| 
 | |
|     for (i = 0; i < 10000; ++i) {
 | |
|         test.d = drand48() + 1.0;    /* [1.0, 2.0) */
 | |
|         real.d = log2(test.d);
 | |
|         soft.i = float64_log2(test.i, &qsf);
 | |
|         compare(test, real, soft, false);
 | |
| 
 | |
|         test.d = drand48() * 100;    /* [0.0, 100) */
 | |
|         real.d = log2(test.d);
 | |
|         soft.i = float64_log2(test.i, &qsf);
 | |
|         compare(test, real, soft, false);
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 |