Visitar URL original
test_math.test_fma_zero_result() fails with the musl C library · Issue #131032 · python/cpython · GitHub
Skip to content

test_math.test_fma_zero_result() fails with the musl C library #131032

Description

@prashanthallu

Bug report

Bug description:

  1. While installing Python 3.13 version in docker:dind endingup without installation, getting the issue like as mentioned below

    675.0 0:00:26 load avg: 0.94 [18/44] test_fstring
    675.0 /Python-3.13.2/Lib/test/test_fstring.py:1655: SyntaxWarning: invalid escape sequence '\N'
    675.0   self.assertEqual(f'{b"\N{OX}"=}', 'b"\\N{OX}"=b\'\\\\N{OX}\'')
    691.8 0:00:43 load avg: 0.96 [19/44] test_functools
    692.5 0:00:44 load avg: 0.96 [20/44] test_generators
    692.9 0:00:44 load avg: 0.96 [21/44] test_hashlib
    693.7 0:00:45 load avg: 0.96 [22/44] test_heapq
    694.4 0:00:46 load avg: 0.96 [23/44] test_int
    695.2 0:00:47 load avg: 0.96 [24/44] test_itertools
    699.8 0:00:51 load avg: 0.96 [25/44] test_json
    704.2 0:00:56 load avg: 0.96 [26/44] test_long
    706.7 0:00:58 load avg: 0.97 [27/44] test_lzma
    706.8 0:00:58 load avg: 0.97 [28/44] test_math -- test_lzma skipped
    709.6 test test_math failed
    709.6 0:01:01 load avg: 0.97 [29/44] test_memoryview -- test_math failed (1 failure)
    710.1 0:01:01 load avg: 0.97 [30/44] test_operator
    710.3 0:01:02 load avg: 0.97 [31/44] test_ordered_dict
    711.5 0:01:03 load avg: 0.97 [32/44] test_patma
    711.7 0:01:03 load avg: 0.97 [33/44] test_pickle
    718.3 0:01:10 load avg: 0.97 [34/44] test_pprint
    718.6 0:01:10 load avg: 0.97 [35/44] test_re
    719.7 test test_re failed
    719.7 0:01:11 load avg: 0.98 [36/44] test_set -- test_re failed (2 failures)
    724.7 0:01:16 load avg: 0.98 [37/44] test_sqlite3
    725.6 0:01:17 load avg: 0.98 [38/44] test_statistics
    733.0 0:01:24 load avg: 0.98 [39/44] test_str
    735.1 0:01:26 load avg: 0.98 [40/44] test_struct
    735.8 0:01:27 load avg: 0.98 [41/44] test_tabnanny
    736.3 0:01:28 load avg: 0.98 [42/44] test_time
    739.5 0:01:31 load avg: 0.98 [43/44] test_xml_etree
    740.2 0:01:32 load avg: 0.98 [44/44] test_xml_etree_c
    741.3
    741.3 Total duration: 1 min 33 sec
    741.3 Total tests: run=9,178 failures=3 skipped=203
    741.3 Total test files: run=44/44 failed=2 skipped=2
    741.3 Result: FAILURE
    741.3 make: *** [Makefile:886: profile-run-stamp] Error 2
    
  2. Which is happening in only docker:dind, when I am trying in centos, ubuntu able to install.

  3. And one more with the Python 3.12.9 version able to install in in docker:dind and logs are

    #15 578.8 0:00:21 load avg: 1.50 [18/44] test_fstring
    #15 578.8 /Python-3.12.9/Lib/test/test_fstring.py:1769: SyntaxWarning: invalid escape sequence '\N'
    #15 578.8   self.assertEqual(f'{b"\N{OX}"=}', 'b"\\N{OX}"=b\'\\\\N{OX}\'')
    #15 593.3 0:00:35 load avg: 1.39 [19/44] test_functools
    #15 593.8 0:00:36 load avg: 1.36 [20/44] test_generators
    #15 594.1 0:00:36 load avg: 1.36 [21/44] test_hashlib
    #15 594.8 0:00:37 load avg: 1.36 [22/44] test_heapq
    #15 595.3 0:00:37 load avg: 1.36 [23/44] test_int
    #15 595.7 0:00:38 load avg: 1.36 [24/44] test_itertools
    #15 599.2 0:00:41 load avg: 1.33 [25/44] test_json
    #15 629.5 0:01:11 load avg: 1.20 [26/44] test_long -- test_json passed in 30.3 sec
    #15 631.7 0:01:13 load avg: 1.20 [27/44] test_lzma
    #15 631.8 0:01:14 load avg: 1.20 [28/44] test_math -- test_lzma skipped
    #15 633.8 0:01:16 load avg: 1.20 [29/44] test_memoryview
    #15 634.4 0:01:16 load avg: 1.18 [30/44] test_operator
    #15 634.5 0:01:16 load avg: 1.18 [31/44] test_ordered_dict
    #15 635.5 0:01:17 load avg: 1.18 [32/44] test_patma
    #15 635.8 0:01:18 load avg: 1.18 [33/44] test_pickle
    #15 641.0 0:01:23 load avg: 1.17 [34/44] test_pprint
    #15 641.3 0:01:23 load avg: 1.17 [35/44] test_re
    #15 642.1 test test_re failed
    #15 642.1 0:01:24 load avg: 1.17 [36/44] test_set -- test_re failed (2 failures)
    #15 646.1 0:01:28 load avg: 1.15 [37/44] test_sqlite3
    #15 646.9 0:01:29 load avg: 1.15 [38/44] test_statistics
    #15 648.3 0:01:30 load avg: 1.15 [39/44] test_struct
    #15 648.9 0:01:31 load avg: 1.22 [40/44] test_tabnanny
    #15 649.4 0:01:31 load avg: 1.22 [41/44] test_time
    #15 652.5 0:01:34 load avg: 1.22 [42/44] test_unicode
    #15 654.5 0:01:36 load avg: 1.20 [43/44] test_xml_etree
    #15 655.0 0:01:37 load avg: 1.20 [44/44] test_xml_etree_c
    #15 655.9 
    #15 655.9 Total duration: 1 min 38 sec
    #15 655.9 Total tests: run=8,930 failures=2 skipped=192
    #15 655.9 Total test files: run=44/44 failed=1 skipped=2
    #15 655.9 Result: FAILURE
    #15 656.0 true
    #15 656.0 # Remove profile generation binary since we are done with it.
    #15 656.0 make clean-retain-profile
    #15 656.1 make[1]: Entering directory '/Python-3.12.9'
    #15 656.1 find . -depth -name '__pycache__' -exec rm -rf {} ';'
    #15 656.2 find . -name '*.py[co]' -exec rm -f {} ';'
    #15 656.2 find . -name '*.[oa]' -exec rm -f {} ';'
    #15 656.5 find . -name '*.s[ol]' -exec rm -f {} ';'
    #15 656.6 find . -name '*.so.[0-9]*.[0-9]*' -exec rm -f {} ';'
    #15 656.7 find . -name '*.lto' -exec rm -f {} ';'
    #15 656.7 find . -name '*.wasm' -exec rm -f {} ';'
    #15 656.7 find . -name '*.lst' -exec rm -f {} ';'
    #15 656.8 find build -name 'fficonfig.h' -exec rm -f {} ';' || true
    #15 656.8 find build -name '*.py' -exec rm -f {} ';' || true
    #15 656.8 find build -name '*.py[co]' -exec rm -f {} ';' || true
    #15 656.8 rm -f pybuilddir.txt
    #15 656.8 rm -f Lib/lib2to3/*Grammar*.pickle
    
  4. So what could be the issue ?.

  5. I am using following Dockerfile code to install Python

    # Use the official Docker DinD image as the base image
    ARG PYTHON_VERSION=3.13.2
    FROM docker:dind
    
    # Install necessary packages and dependencies
    RUN apk add --no-cache \
    	build-base \
    	bzip2-dev \
    	ncurses-dev \
    	gdbm-dev \
    	xz-dev \
    	tk-dev \
    	util-linux-dev \
    	readline-dev \
    	zlib-dev \
    	openssl-dev \
    	libffi-dev \
    	wget
    
    RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz \
    	&& tar xvf Python-${PYTHON_VERSION}.tgz \
    	&& cd Python-${PYTHON_VERSION} \
    	&& ./configure --enable-optimizations \
    	&& make altinstall \
    	&& pip3.13 install --upgrade pip
    

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

Activity

  1. vstinner commented on Mar 10, 2025

    @vstinner
    Member

    Can you try to re-run test_math in verbose mode? Something like: ./python -m test test_math -v in the directory where you built Python.

  2. prashanthallu commented on Mar 11, 2025

    @prashanthallu
    Author

    the following is the result for the verbose mode.

    /Python-3.13.2 # ./python -m unittest -v test.test_math
    test_fma_infinities (test.test_math.FMATests.test_fma_infinities) ... ok
    test_fma_nan_results (test.test_math.FMATests.test_fma_nan_results) ... ok
    test_fma_overflow (test.test_math.FMATests.test_fma_overflow) ... ok
    test_fma_single_round (test.test_math.FMATests.test_fma_single_round) ... ok
    test_fma_zero_result (test.test_math.FMATests.test_fma_zero_result) ... FAIL
    test_random (test.test_math.FMATests.test_random) ... ok
    test_asymmetry (test.test_math.IsCloseTests.test_asymmetry) ... ok
    test_decimals (test.test_math.IsCloseTests.test_decimals) ... ok
    test_eight_decimal_places (test.test_math.IsCloseTests.test_eight_decimal_places) ... ok
    test_fractions (test.test_math.IsCloseTests.test_fractions) ... ok
    test_identical (test.test_math.IsCloseTests.test_identical) ... ok
    test_identical_infinite (test.test_math.IsCloseTests.test_identical_infinite) ... ok
    test_inf_ninf_nan (test.test_math.IsCloseTests.test_inf_ninf_nan) ... ok
    test_integers (test.test_math.IsCloseTests.test_integers) ... ok
    test_near_zero (test.test_math.IsCloseTests.test_near_zero) ... ok
    test_negative_tolerances (test.test_math.IsCloseTests.test_negative_tolerances) ... ok
    test_zero_tolerance (test.test_math.IsCloseTests.test_zero_tolerance) ... ok
    testAcos (test.test_math.MathTests.testAcos) ... ok
    testAcosh (test.test_math.MathTests.testAcosh) ... ok
    testAsin (test.test_math.MathTests.testAsin) ... ok
    testAsinh (test.test_math.MathTests.testAsinh) ... ok
    testAtan (test.test_math.MathTests.testAtan) ... ok
    testAtan2 (test.test_math.MathTests.testAtan2) ... ok
    testAtanh (test.test_math.MathTests.testAtanh) ... ok
    testCbrt (test.test_math.MathTests.testCbrt) ... ok
    testCeil (test.test_math.MathTests.testCeil) ... ok
    testComb (test.test_math.MathTests.testComb) ... ok
    testConstants (test.test_math.MathTests.testConstants) ... ok
    testCopysign (test.test_math.MathTests.testCopysign) ... ok
    testCos (test.test_math.MathTests.testCos) ... ok
    testCosh (test.test_math.MathTests.testCosh) ... ok
    testDegrees (test.test_math.MathTests.testDegrees) ... ok
    testDist (test.test_math.MathTests.testDist) ... ok
    testExp (test.test_math.MathTests.testExp) ... ok
    testExp2 (test.test_math.MathTests.testExp2) ... ok
    testFabs (test.test_math.MathTests.testFabs) ... ok
    testFactorial (test.test_math.MathTests.testFactorial) ... ok
    testFactorialHugeInputs (test.test_math.MathTests.testFactorialHugeInputs) ... ok
    testFactorialNonIntegers (test.test_math.MathTests.testFactorialNonIntegers) ... ok
    testFloor (test.test_math.MathTests.testFloor) ... ok
    testFmod (test.test_math.MathTests.testFmod) ... ok
    testFrexp (test.test_math.MathTests.testFrexp) ... ok
    testFsum (test.test_math.MathTests.testFsum) ... ok
    testGcd (test.test_math.MathTests.testGcd) ... ok
    testHypot (test.test_math.MathTests.testHypot) ... ok
    testHypotAccuracy (test.test_math.MathTests.testHypotAccuracy) ... ok
    testIsfinite (test.test_math.MathTests.testIsfinite) ... ok
    testIsinf (test.test_math.MathTests.testIsinf) ... ok
    testIsnan (test.test_math.MathTests.testIsnan) ... ok
    testIsqrt (test.test_math.MathTests.testIsqrt) ... ok
    testLdexp (test.test_math.MathTests.testLdexp) ... ok
    testLog (test.test_math.MathTests.testLog) ... ok
    testLog10 (test.test_math.MathTests.testLog10) ... ok
    testLog1p (test.test_math.MathTests.testLog1p) ... ok
    testLog2 (test.test_math.MathTests.testLog2) ... ok
    testLog2Exact (test.test_math.MathTests.testLog2Exact) ... ok
    testModf (test.test_math.MathTests.testModf) ... ok
    testPerm (test.test_math.MathTests.testPerm) ... ok
    testPow (test.test_math.MathTests.testPow) ... ok
    testRadians (test.test_math.MathTests.testRadians) ... ok
    testRemainder (test.test_math.MathTests.testRemainder) ... ok
    testSin (test.test_math.MathTests.testSin) ... ok
    testSinh (test.test_math.MathTests.testSinh) ... ok
    testSqrt (test.test_math.MathTests.testSqrt) ... ok
    testSumProd (test.test_math.MathTests.testSumProd) ... ok
    testTan (test.test_math.MathTests.testTan) ... ok
    testTanh (test.test_math.MathTests.testTanh) ... ok
    testTanhSign (test.test_math.MathTests.testTanhSign) ... ok
    test_exceptions (test.test_math.MathTests.test_exceptions) ... ok
    test_inf_constant (test.test_math.MathTests.test_inf_constant) ... ok
    test_input_exceptions (test.test_math.MathTests.test_input_exceptions) ... ok
    test_issue39871 (test.test_math.MathTests.test_issue39871) ... ok
    test_lcm (test.test_math.MathTests.test_lcm) ... ok
    test_math_dist_leak (test.test_math.MathTests.test_math_dist_leak) ... ok
    test_mtestfile (test.test_math.MathTests.test_mtestfile) ... ok
    test_nan_constant (test.test_math.MathTests.test_nan_constant) ... ok
    test_nextafter (test.test_math.MathTests.test_nextafter) ... ok
    test_prod (test.test_math.MathTests.test_prod) ... ok
    test_sumprod_accuracy (test.test_math.MathTests.test_sumprod_accuracy) ... ok
    test_sumprod_extended_precision_accuracy (test.test_math.MathTests.test_sumprod_extended_precision_accuracy) ... ok
    test_sumprod_stress (test.test_math.MathTests.test_sumprod_stress) ... ok
    test_testfile (test.test_math.MathTests.test_testfile) ... ok
    test_trunc (test.test_math.MathTests.test_trunc) ... ok
    test_ulp (test.test_math.MathTests.test_ulp) ... ok
    /Python-3.13.2/Lib/test/mathdata/ieee754.txt
    Doctest: ieee754.txt ... ok
    
    ======================================================================
    FAIL: test_fma_zero_result (test.test_math.FMATests.test_fma_zero_result)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/Python-3.13.2/Lib/test/test_math.py", line 2744, in test_fma_zero_result
        self.assertIsNegativeZero(math.fma(tiny, -tiny, 0.0))
        ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/Python-3.13.2/Lib/test/test_math.py", line 2860, in assertIsNegativeZero
        self.assertTrue(
        ~~~~~~~~~~~~~~~^
            value == 0 and math.copysign(1, value) < 0,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            msg="Expected a negative zero, got {!r}".format(value)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        )
        ^
    AssertionError: False is not true : Expected a negative zero, got 0.0
    
    ----------------------------------------------------------------------
    Ran 85 tests in 77.598s
    
    FAILED (failures=1)
    
  3. vstinner commented on Mar 11, 2025

    @vstinner
    Member

    You're building a docker image using Alpine Linux which uses the musl C library. It seems like musl has a bug in the fma() function.

  4. changed the title [-]Python 3.13 installation failing in docker:dind[/-] [+]test_math.test_fma_zero_result() fails with the musl C library[/+] on Mar 11, 2025
  5. added a commit that references this issue on Mar 11, 2025
  6. prashanthallu commented on Mar 11, 2025

    @prashanthallu
    Author

    is there any plan to release new version of python because of this change?

  7. vstinner commented on Mar 11, 2025

    @vstinner
    Member

    is there any plan to release new version of python because of this change?

    My fix is not merged yet, and no, there will not be a new release just because of this fix.

    You can tune the PGO task to ignore the failing test: see PROFILE_TASK variable in configure. Default:

    PROFILE_TASK=   -m test --pgo --timeout=$(TESTTIMEOUT)
    

    You can ignore the failing test using -i option. Example:

    ./configure --enable-optimizations PROFILE_TASK='-m test --pgo -i test_fma_zero_result'
    
  8. skirpichev commented on Mar 12, 2025

    @skirpichev
    Member

    @prashanthallu, maybe you can try this patch?

    diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
    index b4c15a143f..39e34307dc 100644
    --- a/Modules/mathmodule.c
    +++ b/Modules/mathmodule.c
    @@ -2344,7 +2344,19 @@ static PyObject *
     math_fma_impl(PyObject *module, double x, double y, double z)
     /*[clinic end generated code: output=4fc8626dbc278d17 input=e3ad1f4a4c89626e]*/
     {
    -    double r = fma(x, y, z);
    +    double r;
    +
    +    if (z) {
    +        r = fma(x, y, z);
    +    }
    +    else {
    +        if (x && y) {
    +            r = x * y;
    +        }
    +        else {
    +            r = copysign(1, z) == 1 ? x*y + z : x*y;
    +        }
    +    }
     
         /* Fast path: if we got a finite result, we're done. */
         if (isfinite(r)) {
  9. vstinner commented on Mar 12, 2025

    @vstinner
    Member

    @prashanthallu, maybe you can try this patch?

    This patch works with musl (test_math pass). Do you suggest to apply it on all platforms? musl has no #ifdef.

  10. skirpichev commented on Mar 12, 2025

    @skirpichev
    Member

    Do you suggest to apply it on all platforms?

    I would think of it, if this really solves problem on a lot of platforms. It might be the case: no other fma tests are skipped, thus there is a chance that problems restricted to few corner cases.

  11. added a commit that references this issue on Mar 12, 2025
  12. vstinner commented on Mar 12, 2025

    @vstinner
    Member

    Ok, I converted your patch to a PR: #131134. Let's see if test_math still pass on buildbots (ex: FreeBSD and WASI).

  13. prashanthallu commented on Mar 12, 2025

    @prashanthallu
    Author

    Python3.13_install_logs.txt

    is there any plan to release new version of python because of this change?

    My fix is not merged yet, and no, there will not be a new release just because of this fix.

    You can tune the PGO task to ignore the failing test: see PROFILE_TASK variable in configure. Default:

    PROFILE_TASK=   -m test --pgo --timeout=$(TESTTIMEOUT)
    

    You can ignore the failing test using -i option. Example:

    ./configure --enable-optimizations PROFILE_TASK='-m test --pgo -i test_fma_zero_result'
    

    with the help of PROFILE_TASK able to skip the test case but still python is not able to install in docker:dind and attached the Python installation logs

  14. vstinner commented on Mar 12, 2025

    @vstinner
    Member

    Python3.13_install_logs.txt

    413.9 0:01:24 load avg: 1.61 [35/44] test_re
    415.0 test test_re failed
    415.0 0:01:25 load avg: 1.61 [36/44] test_set -- test_re failed (2 failures)
    

    Again, you can please try to re-run test_re in verbose mode? Something like: ./python -m test test_re -v.

  15. 7 remaining items

  16. serhiy-storchaka commented on Mar 12, 2025

    @serhiy-storchaka
    Member

    It is more complicated, because we can get zero result with wrong sign also for non-zero z, and there are much more such cases. Fixing only case for zero z will make matters worse, because the function will no longer be monotonic. Fixing it for all cases means re-implementing the fma() function. This is a lot of work, and the general implementation can be slower than the specialized C library implementation. AFAIK, when the fma() function was added, it was decided to not add our own implementation, but use the C library implementation. If it is flawed, let it be so. The specific test should be skipped on such platforms.

  17. skirpichev commented on Mar 13, 2025

    @skirpichev
    Member

    because we can get zero result with wrong sign also for non-zero z, and there are much more such cases.

    Maybe. Can you prove this with broken tests?

    It's possible that on this platform - fma() not broken for non-zero arguments.

    The specific test should be skipped on such platforms.

    Yes, this is an alternative. In this case, test function must be split: it seems zero arguments aren't a problem for other platforms.

  18. prashanthallu commented on Mar 13, 2025

    @prashanthallu
    Author

    with the following command. I am able to install Python 3.13.2 version in docker:dind. Thank you @vstinner

    ./configure --enable-optimizations PROFILE_TASK='-m test --pgo -i test_fma_zero_result -i test_locale_caching -i test_locale_compiled'

  19. serhiy-storchaka commented on Mar 13, 2025

    @serhiy-storchaka
    Member

    What to prove? There is a test for x = a + b, y = a - b, z = -a*a, where a = 2**-500, b = 2**-550. The exact result of x * y + z is -b*b, which underflows to -0.0. But if fma() uses 64-bit floating point for intermediate result of x * y, it returns 0.0. You can try other values of a and b. It is very likely that you will get wrong result for b = 2**(-500-k), where k is from 27 to 52. It is even likely that you will get wrong result for many if not most of values of b between 2**-552 and 2**-527, not only for powers of 2. I am sure, that if you got wrong result for some x and y, you will get the same wrong result for x*2**j and y*2**-j for some j. You can also find examples in form of x*d, y/d, which will get similar wrong results for some d.

    If fma() returns wrong zero result, it is very likely that some non-zero results are also wrong.

    In this case, test function must be split: it seems zero arguments aren't a problem for other platforms.

    If assertions with zero and non-zero arguments fail on different platforms, we can split the test method. But we should not try to fix the implementation only for zero arguments.

  20. added a commit that references this issue on Mar 13, 2025
  21. skirpichev commented on Mar 13, 2025

    @skirpichev
    Member

    What to prove? There is a test for x = a + b, y = a - b, z = -a*a, where a = 2**-500, b = 2**-550.

    But it doesn't fail with musl C and above patch (which doesn't relevant in this case), see #131134.

    If fma() returns wrong zero result, it is very likely that some non-zero results are also wrong.

    Maybe. But our tests definitely lacks such case.

  22. added a commit that references this issue on Mar 13, 2025
  23. vstinner commented on Mar 13, 2025

    @vstinner
    Member

    I merged my PR skipping tests if Python is linked to musl (PR gh-131071). I close this issue.

    @prashanthallu: Would you mind to open a new issue for the two test_re failures? Thanks for your bug report.

  24. vstinner commented on Mar 13, 2025

    @vstinner
    Member

    @serhiy-storchaka:

    AFAIK, when the fma() function was added, it was decided to not add our own implementation, but use the C library implementation. If it is flawed, let it be so. The specific test should be skipped on such platforms.

    I agree with Serhiy.

  25. added a commit that references this issue on Mar 13, 2025
  26. prashanthallu commented on Mar 17, 2025

    @prashanthallu
    Author

    Hi @vstinner created new issue for test_re
    #131342

  27. added a commit that references this issue on Mar 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions