2
0

fp-test-log2.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. #include "qemu/osdep.h"
  13. #include "qemu/cutils.h"
  14. #include <math.h>
  15. #include "fpu/softfloat.h"
  16. typedef union {
  17. double d;
  18. float64 i;
  19. } ufloat64;
  20. static int errors;
  21. static void compare(ufloat64 test, ufloat64 real, ufloat64 soft, bool exact)
  22. {
  23. int msb;
  24. uint64_t ulp = UINT64_MAX;
  25. if (real.i == soft.i) {
  26. return;
  27. }
  28. msb = 63 - __builtin_clzll(real.i ^ soft.i);
  29. if (msb < 52) {
  30. if (real.i > soft.i) {
  31. ulp = real.i - soft.i;
  32. } else {
  33. ulp = soft.i - real.i;
  34. }
  35. }
  36. /* glibc allows 3 ulp error in its libm-test-ulps; allow 4 here */
  37. if (!exact && ulp <= 4) {
  38. return;
  39. }
  40. printf("test: %016" PRIx64 " %+.13a\n"
  41. " sf: %016" PRIx64 " %+.13a\n"
  42. "libm: %016" PRIx64 " %+.13a\n",
  43. test.i, test.d, soft.i, soft.d, real.i, real.d);
  44. if (msb == 63) {
  45. printf("Error in sign!\n\n");
  46. } else if (msb >= 52) {
  47. printf("Error in exponent: %d\n\n",
  48. (int)(soft.i >> 52) - (int)(real.i >> 52));
  49. } else {
  50. printf("Error in fraction: %" PRIu64 " ulp\n\n", ulp);
  51. }
  52. if (++errors == 20) {
  53. exit(1);
  54. }
  55. }
  56. int main(int ac, char **av)
  57. {
  58. ufloat64 test, real, soft;
  59. float_status qsf = {0};
  60. int i;
  61. set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
  62. set_float_default_nan_pattern(0b01000000, &qsf);
  63. set_float_rounding_mode(float_round_nearest_even, &qsf);
  64. test.d = 0.0;
  65. real.d = -__builtin_inf();
  66. soft.i = float64_log2(test.i, &qsf);
  67. compare(test, real, soft, true);
  68. test.d = 1.0;
  69. real.d = 0.0;
  70. soft.i = float64_log2(test.i, &qsf);
  71. compare(test, real, soft, true);
  72. test.d = 2.0;
  73. real.d = 1.0;
  74. soft.i = float64_log2(test.i, &qsf);
  75. compare(test, real, soft, true);
  76. test.d = 4.0;
  77. real.d = 2.0;
  78. soft.i = float64_log2(test.i, &qsf);
  79. compare(test, real, soft, true);
  80. test.d = 0x1p64;
  81. real.d = 64.0;
  82. soft.i = float64_log2(test.i, &qsf);
  83. compare(test, real, soft, true);
  84. test.d = __builtin_inf();
  85. real.d = __builtin_inf();
  86. soft.i = float64_log2(test.i, &qsf);
  87. compare(test, real, soft, true);
  88. for (i = 0; i < 10000; ++i) {
  89. test.d = drand48() + 1.0; /* [1.0, 2.0) */
  90. real.d = log2(test.d);
  91. soft.i = float64_log2(test.i, &qsf);
  92. compare(test, real, soft, false);
  93. test.d = drand48() * 100; /* [0.0, 100) */
  94. real.d = log2(test.d);
  95. soft.i = float64_log2(test.i, &qsf);
  96. compare(test, real, soft, false);
  97. }
  98. return 0;
  99. }