123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- /*
- * 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_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
- set_float_default_nan_pattern(0b01000000, &qsf);
- 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;
- }
|