qemu/tests/fp/fp-test-log2.c
<<
>>
Prefs
   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
  18typedef union {
  19    double d;
  20    float64 i;
  21} ufloat64;
  22
  23static int errors;
  24
  25static 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
  67int 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