Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/tests/lib/libm Fix up libm tests.



details:   https://anonhg.NetBSD.org/src/rev/741d6bfd7e22
branches:  trunk
changeset: 445636:741d6bfd7e22
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Wed Nov 07 03:59:36 2018 +0000

description:
Fix up libm tests.

- Fix up last few digits of a lot of known-answer tests.

  Confirmed with GNU mpfr to 200 bits of precision and cross-checked
  with whatever libm Ubuntu ships with.

- Test relative error, not absolute error.

- Set bounds in terms of *_EPSILON, not magic numbers.

  *_EPSILON is twice the largest relative error of a correctly
  rounded operation, and equal to the largest relative error of an
  operation with up to 1ulp error.

  Most of the operations we're testing are not correctly rounded, but
  they ought to be no more than 1ulp away.  For the few cases where
  that's not a priori clear (like comparing cbrt and pow(x, 1/3)),
  use twice *_EPSILON to allow some leeway.

- Write the success condition positively as error <= eps.

  This comes out false if the result is a NaN, meaning failure.  In
  contrast, if we write error > eps for the _failure_ condition, then
  if the result is a NaN, it will also come out false, but meaning
  success, which is not what we want.

- Fix the trigonometric test cases near bad spots.

  sin(pi - d) for nonzero d is not zero; it is d + O(d^3).  pi is not
  a floating-point number, so these results should be approximately
  the nonzero error of our approximation to pi.  Likewise with
  cos(pi/2 - d) and tan(pi + d).

  (Yes, I know the sin _function_ is ill-conditioned near pi so you
  shouldn't pass approximate inputs near there, but that's separate
  from whether a sin _implementation_ gives an answer that is wrong
  by quintillions of ulps.)

  Since on x86 (i386 and amd64 alike) we currently use x87 hardware
  trigonometric instructions, which are bad, these are marked xfail
  on x86 for now until we switch to software implementations (coming
  soon to a repository near you).

- Use %.8g, %.17g, %.35g to print float, double, long double in failures.

  This should be enough to identify the problematic outputs and/or
  reproduce the computation, even if long double is binary128 with
  115 bits of precision.

If there are any new libm test failures after this, tell me what
architecture you're on and send me the atf output and I'll try to
figure it out.

diffstat:

 tests/lib/libm/t_acos.c   |   4 +-
 tests/lib/libm/t_asin.c   |  33 +++++++++-----
 tests/lib/libm/t_cbrt.c   |  77 ++++++++++++++++++++++++-----------
 tests/lib/libm/t_cos.c    |  82 +++++++++++++++++++++++++-------------
 tests/lib/libm/t_cosh.c   |  58 +++++++++++++--------------
 tests/lib/libm/t_exp.c    |  52 +++++++++++------------
 tests/lib/libm/t_ldexp.c  |  37 +++++++---------
 tests/lib/libm/t_libm.h   |   6 +-
 tests/lib/libm/t_log.c    |  18 ++++---
 tests/lib/libm/t_scalbn.c |  31 +++++++++-----
 tests/lib/libm/t_sin.c    |  99 ++++++++++++++++++++++++++++++++++------------
 tests/lib/libm/t_sinh.c   |  56 ++++++++++++-------------
 tests/lib/libm/t_sqrt.c   |  78 ++++++++++++++++++++++--------------
 tests/lib/libm/t_tan.c    |  94 +++++++++++++++++++++++++++++++++-----------
 14 files changed, 448 insertions(+), 277 deletions(-)

diffs (truncated from 1264 to 300 lines):

diff -r 8a61a6a5a664 -r 741d6bfd7e22 tests/lib/libm/t_acos.c
--- a/tests/lib/libm/t_acos.c   Wed Nov 07 03:56:18 2018 +0000
+++ b/tests/lib/libm/t_acos.c   Wed Nov 07 03:59:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_acos.c,v 1.10 2014/03/05 20:14:46 dsl Exp $ */
+/* $NetBSD: t_acos.c,v 1.11 2018/11/07 03:59:36 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -72,7 +72,7 @@
                {  0,    M_PI / 2,          },
                {  0.1,  1.470628905633337, },
                {  0.5,  1.047197551196598, },
-               {  0.99, 0.141539473324427, },
+               {  0.99, 0.1415394733244273, },
        };
        unsigned int i;
 
diff -r 8a61a6a5a664 -r 741d6bfd7e22 tests/lib/libm/t_asin.c
--- a/tests/lib/libm/t_asin.c   Wed Nov 07 03:56:18 2018 +0000
+++ b/tests/lib/libm/t_asin.c   Wed Nov 07 03:59:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_asin.c,v 1.3 2014/03/03 10:39:08 martin Exp $ */
+/* $NetBSD: t_asin.c,v 1.4 2018/11/07 03:59:36 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -30,6 +30,7 @@
  */
 
 #include <atf-c.h>
+#include <float.h>
 #include <math.h>
 
 static const struct {
@@ -117,13 +118,14 @@
 
 ATF_TC_BODY(asin_inrange, tc)
 {
-       const double eps = 1.0e-15;
-       double y;
+       const double eps = DBL_EPSILON;
        size_t i;
 
        for (i = 0; i < __arraycount(values); i++) {
-               y = asin(values[i].x);
-               if (fabs(y - values[i].y) > eps)
+               double x = values[i].x;
+               double y = values[i].y;
+
+               if (!(fabs((asin(x) - y)/y) <= eps))
                        atf_tc_fail_nonfatal("asin(%g) != %g",
                                values[i].x, values[i].y);
        }
@@ -230,16 +232,23 @@
 
 ATF_TC_BODY(asinf_inrange, tc)
 {
-       const float eps = 1.0e-6;
-       float x;
-       float y;
+       const float eps = FLT_EPSILON;
        size_t i;
 
        for (i = 0; i < __arraycount(values); i++) {
-               x = values[i].x;
-               y = values[i].y;
-               if (fabs(asinf(x) - y) > eps)
-                       atf_tc_fail_nonfatal("asinf(%g) != %g", x, y);
+               float x = values[i].x;
+               float y = values[i].y;
+
+               if (fabs(x) == 0.5)
+                       atf_tc_expect_fail("asinf is busted,"
+                           " gives ~2ulp error");
+               if (!(fabsf((asinf(x) - y)/y) <= eps)) {
+                       atf_tc_fail_nonfatal("asinf(%.8g) = %.8g != %.8g,"
+                           " error=~%.1fulp",
+                           x, asinf(x), y, fabsf(((asinf(x) - y)/y)/eps));
+               }
+               if (fabs(x) == 0.5)
+                       atf_tc_expect_pass();
        }
 }
 
diff -r 8a61a6a5a664 -r 741d6bfd7e22 tests/lib/libm/t_cbrt.c
--- a/tests/lib/libm/t_cbrt.c   Wed Nov 07 03:56:18 2018 +0000
+++ b/tests/lib/libm/t_cbrt.c   Wed Nov 07 03:59:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_cbrt.c,v 1.3 2014/03/03 10:39:08 martin Exp $ */
+/* $NetBSD: t_cbrt.c,v 1.4 2018/11/07 03:59:36 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,9 +29,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_cbrt.c,v 1.3 2014/03/03 10:39:08 martin Exp $");
+__RCSID("$NetBSD: t_cbrt.c,v 1.4 2018/11/07 03:59:36 riastradh Exp $");
 
 #include <atf-c.h>
+#include <float.h>
 #include <math.h>
 #include <stdio.h>
 
@@ -61,18 +62,26 @@
 ATF_TC_BODY(cbrt_pow, tc)
 {
        const double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
-       const double eps = 1.0e-14;
-       double y, z;
+       /* Neither cbrt nor pow is required to be correctly rounded.  */
+       const double eps = 2*DBL_EPSILON;
        size_t i;
 
        for (i = 0; i < __arraycount(x); i++) {
-
-               y = cbrt(x[i]);
-               z = pow(x[i], 1.0 / 3.0);
+               double x_cbrt = cbrt(x[i]);
+               double x_pow13 = pow(x[i], 1.0 / 3.0);
+               bool ok;
 
-               if (fabs(y - z) > eps)
-                       atf_tc_fail_nonfatal("cbrt(%0.03f) != "
-                           "pow(%0.03f, 1/3)\n", x[i], x[i]);
+               if (x[i] == 0) {
+                       ok = (x_cbrt == x_pow13);
+               } else {
+                       ok = (fabs((x_cbrt - x_pow13)/x_cbrt) <= eps);
+               }
+
+               if (!ok) {
+                       atf_tc_fail_nonfatal("cbrt(%.17g) = %.17g != "
+                           "pow(%.17g, 1/3) = %.17g\n",
+                           x[i], x_cbrt, x[i], x_pow13);
+               }
        }
 }
 
@@ -162,18 +171,27 @@
 ATF_TC_BODY(cbrtf_powf, tc)
 {
        const float x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
-       const float eps = 1.0e-5;
-       float y, z;
+       /* Neither cbrt nor pow is required to be correctly rounded.  */
+       const float eps = 2*FLT_EPSILON;
        size_t i;
 
        for (i = 0; i < __arraycount(x); i++) {
-
-               y = cbrtf(x[i]);
-               z = powf(x[i], 1.0 / 3.0);
+               float x_cbrt = cbrtf(x[i]);
+               float x_pow13 = powf(x[i], 1.0 / 3.0);
+               bool ok;
 
-               if (fabsf(y - z) > eps)
-                       atf_tc_fail_nonfatal("cbrtf(%0.03f) != "
-                           "powf(%0.03f, 1/3)\n", x[i], x[i]);
+               if (x[i] == 0) {
+                       ok = (x_cbrt == x_pow13);
+               } else {
+                       ok = (fabsf((x_cbrt - x_pow13)/x_cbrt) <= eps);
+               }
+
+               if (!ok) {
+                       atf_tc_fail_nonfatal("cbrtf(%.9g) = %.9g. != "
+                           "powf(%.9g, 1/3) = %.9g\n",
+                           (double)x[i], (double)x_cbrt,
+                           (double)x[i], (double)x_pow13);
+               }
        }
 }
 
@@ -263,18 +281,27 @@
 ATF_TC_BODY(cbrtl_powl, tc)
 {
        const long double x[] = { 0.0, 0.005, 1.0, 99.0, 123.123, 9999.0 };
-       const long double eps = 1.0e-15;
-       long double y, z;
+       /* Neither cbrt nor pow is required to be correctly rounded.  */
+       const long double eps = 2*LDBL_EPSILON;
        size_t i;
 
+       atf_tc_expect_fail("powl not yet implemented with full precision");
        for (i = 0; i < __arraycount(x); i++) {
+               long double x_cbrt = cbrtl(x[i]);
+               long double x_pow13 = powl(x[i], 1.0 / 3.0);
+               bool ok;
 
-               y = cbrtl(x[i]);
-               z = powl(x[i], 1.0 / 3.0);
+               if (x[i] == 0) {
+                       ok = (x_cbrt == x_pow13);
+               } else {
+                       ok = (fabsl((x_cbrt - x_pow13)/x_cbrt) <= eps);
+               }
 
-               if (fabsl(y - z) > eps * fabsl(1 + x[i]))
-                       atf_tc_fail_nonfatal("cbrtl(%0.03Lf) != "
-                           "powl(%0.03Lf, 1/3)\n", x[i], x[i]);
+               if (!ok) {
+                       atf_tc_fail_nonfatal("cbrtl(%.35Lg) = %.35Lg != "
+                           "powl(%.35Lg, 1/3) = %.35Lg\n",
+                           x[i], x_cbrt, x[i], x_pow13);
+               }
        }
 }
 
diff -r 8a61a6a5a664 -r 741d6bfd7e22 tests/lib/libm/t_cos.c
--- a/tests/lib/libm/t_cos.c    Wed Nov 07 03:56:18 2018 +0000
+++ b/tests/lib/libm/t_cos.c    Wed Nov 07 03:59:36 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: t_cos.c,v 1.4 2014/03/03 10:39:08 martin Exp $ */
+/* $NetBSD: t_cos.c,v 1.5 2018/11/07 03:59:36 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,29 +29,41 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <assert.h>
 #include <atf-c.h>
+#include <float.h>
 #include <math.h>
 
+#if defined(__i386__) || defined(__x86_64__)
+const int TRIG_BUSTED = 1;
+#else
+const int TRIG_BUSTED = 0;
+#endif
+
 static const struct {
        int             angle;
        double          x;
        double          y;
+       float           fy;
 } angles[] = {
-       { -180, -3.141592653589793, -1.0000000000000000 },
-       { -135, -2.356194490192345, -0.7071067811865476 },
-       {  -90, -1.570796326794897,  0.0000000000000000 },
-       {  -45, -0.785398163397448,  0.7071067811865476 },
-       {    0,  0.000000000000000,  1.0000000000000000 },
-       {   30,  0.523598775598299,  0.8660254037844386 },
-       {   45,  0.785398163397448,  0.7071067811865476 },
-       {   60,  1.047197551196598,  0.5000000000000000 },
-       {   90,  1.570796326794897,  0.0000000000000000 },
-       {  120,  2.094395102393195, -0.5000000000000000 },
-       {  135,  2.356194490192345, -0.7071067811865476 },
-       {  150,  2.617993877991494, -0.8660254037844386 },
-       {  180,  3.141592653589793, -1.0000000000000000 },
-       {  270,  4.712388980384690,  0.0000000000000000 },
-       {  360,  6.283185307179586,  1.0000000000000000 }
+       { -180, -3.141592653589793, -1.0000000000000000, 999 },
+       { -135, -2.356194490192345, -0.7071067811865476, 999 },
+       {  -90, -1.5707963267948966, 6.123233995736766e-17, -4.3711388e-08 },
+       {  -90, -1.5707963267948968, -1.6081226496766366e-16, -4.3711388e-08 },
+       {  -45, -0.785398163397448,  0.7071067811865478, 999 },
+       {    0,  0.000000000000000,  1.0000000000000000, 999 },
+       {   30,  0.523598775598299,  0.8660254037844386, 999 },
+       {   45,  0.785398163397448,  0.7071067811865478, 999 },
+       {   60,  1.0471975511965976,  0.5000000000000001, 999 },
+       {   60,  1.0471975511965979,  0.4999999999999999, 999 },
+       {   90,  1.570796326794897, -3.8285686989269494e-16, -4.3711388e-08 },
+       {  120,  2.0943951023931953, -0.4999999999999998, 999 },
+       {  120,  2.0943951023931957, -0.5000000000000002, 999 },
+       {  135,  2.356194490192345, -0.7071067811865476, 999 },
+       {  150,  2.617993877991494, -0.8660254037844386, 999 },
+       {  180,  3.141592653589793, -1.0000000000000000, 999 },
+       {  270,  4.712388980384690, -1.8369701987210297e-16, 1.1924881e-08 },
+       {  360,  6.283185307179586,  1.0000000000000000, 999 },
 };
 
 /*
@@ -65,14 +77,24 @@
 
 ATF_TC_BODY(cos_angles, tc)
 {
-       const double eps = 1.0e-15;
+       const double eps = DBL_EPSILON;
        size_t i;
 
        for (i = 0; i < __arraycount(angles); i++) {
+               int deg = angles[i].angle;
+               double theta = angles[i].x;
+               double cos_theta = angles[i].y;
 
-               if (fabs(cos(angles[i].x) - angles[i].y) > eps)
-                       atf_tc_fail_nonfatal("cos(%d deg) != %0.01f",
-                           angles[i].angle, angles[i].y);
+               assert(cos_theta != 0);
+               if (TRIG_BUSTED && fabs(cos_theta) < 2*DBL_EPSILON)
+                       atf_tc_expect_fail("cos near +/-pi/2 is busted");
+               if (!(fabs((cos(theta) - cos_theta)/cos_theta) <= eps)) {
+                       atf_tc_fail_nonfatal("cos(%d deg = %.17g) = %.17g"
+                           " != %.17g",



Home | Main Index | Thread Index | Old Index