Skip to content

Test suite failure on non-AVX512 due to glibc (version-dependent) bug on f64 underflow #19192

@h-vetinari

Description

@h-vetinari

While trying to build 1.21.0rc1 for conda-forge, a new bug appeared, for agents without AVX512 support.

Test suite failure for TestSpecialFloats.test_exp_values
=================================== FAILURES ===================================
______________________ TestSpecialFloats.test_exp_values _______________________

self = <numpy.core.tests.test_umath.TestSpecialFloats object at 0x7f1a528bb820>

    def test_exp_values(self):
        x = [np.nan,  np.nan, np.inf, 0.]
        y = [np.nan, -np.nan, np.inf, -np.inf]
        for dt in ['f', 'd', 'g']:
            xf = np.array(x, dtype=dt)
            yf = np.array(y, dtype=dt)
            assert_equal(np.exp(yf), xf)
    
        with np.errstate(over='raise'):
            assert_raises(FloatingPointError, np.exp, np.float32(100.))
            assert_raises(FloatingPointError, np.exp, np.float32(1E19))
            assert_raises(FloatingPointError, np.exp, np.float64(800.))
            assert_raises(FloatingPointError, np.exp, np.float64(1E19))
    
        with np.errstate(under='raise'):
            assert_raises(FloatingPointError, np.exp, np.float32(-1000.))
            assert_raises(FloatingPointError, np.exp, np.float32(-1E19))
>           assert_raises(FloatingPointError, np.exp, np.float64(-1000.))

../[...]/lib/python3.9/site-packages/numpy/core/tests/test_umath.py:998: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../[...]/lib/python3.9/unittest/case.py:733: in assertRaises
    return context.handle('assertRaises', args, kwargs)
../[...]/lib/python3.9/unittest/case.py:201: in handle
    callable_obj(*args, **kwargs)
../[...]/lib/python3.9/unittest/case.py:223: in __exit__
    self._raiseFailure("{} not raised by {}".format(exc_name,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <unittest.case._AssertRaisesContext object at 0x7f1a528bba90>
standardMsg = 'FloatingPointError not raised by exp'

    def _raiseFailure(self, standardMsg):
        msg = self.test_case._formatMessage(self.msg, standardMsg)
E       AssertionError: FloatingPointError not raised by exp

../[...]/lib/python3.9/unittest/case.py:163: AssertionError
=============================== warnings summary ===============================

@seiko2plus commented:

It makes sense now the error disappears when the machine has AVX512 support, it seems we are dealing with compiler/libc that doesn't respect underflow error since the current exp/f64 SIMD kernel only optimizes CPUs with AVX512 Skylake features.

[...]

However, Could you try the following patch?

Details
index 41e0bf37b..89798f74a 100644
--- a/numpy/core/src/umath/loops_exponent_log.dispatch.c.src
+++ b/numpy/core/src/umath/loops_exponent_log.dispatch.c.src
@@ -1248,6 +1248,7 @@ NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(FLOAT_@func@)
 /**begin repeat
  * #func = exp, log#
  * #scalar = npy_exp, npy_log#
+ * #underflow = 1, 0#
  */
 NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(DOUBLE_@func@)
 (char **args, npy_intp const *dimensions, npy_intp const *steps, void *NPY_UNUSED(data))
@@ -1260,6 +1261,13 @@ NPY_NO_EXPORT void NPY_CPU_DISPATCH_CURFX(DOUBLE_@func@)
 #endif
     UNARY_LOOP {
         const npy_double in1 = *(npy_double *)ip1;
+    #if @underflow@
+        if (NPY_UNLIKELY(!npy_isnan(in1) && in1 < -0x1.74910d52d3053p+9)) {
+            *(npy_double *)op1 = 0;
+            npy_set_floatstatus_underflow();
+            continue;
+        }
+    #endif
         *(npy_double *)op1 = @scalar@(in1);
     }
 }

if the patch passes the test, then we will need to determine which versions of glibc are affected by this bug.

And indeed, the test passes with that patch, which is why I'm opening this issue.

Sidenote: based on the mention of (g)libc, this might be somewhat similar to #15179? The corresponding test is currently being skipped in conda-forge, but does pass with the following patch (suggested by @r-devulap):

Details
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index 9d1b13b53..faa2ca8f0 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -1188,8 +1188,6 @@ def test_sincos_float32(self):
         M = np.int_(N/20)
         index = np.random.randint(low=0, high=N, size=M)
         x_f32 = np.float32(np.random.uniform(low=-100.,high=100.,size=N))
-        # test coverage for elements > 117435.992f for which glibc is used
-        x_f32[index] = np.float32(10E+10*np.random.rand(M))
         x_f64 = np.float64(x_f32)
         assert_array_max_ulp(np.sin(x_f32), np.float32(np.sin(x_f64)), maxulp=2)
         assert_array_max_ulp(np.cos(x_f32), np.float32(np.cos(x_f64)), maxulp=2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions