Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-29282: Add math.fma(): fused multiply-add function #17987

Open
wants to merge 1 commit into
base: master
from

Conversation

@vstinner
Copy link
Member

vstinner commented Jan 13, 2020

Co-Authored-By: Mark Dickinson <mdickinson@enthought.com>
@vstinner

This comment has been minimized.

Copy link
Member Author

vstinner commented Jan 13, 2020

This PR is a copy the following https://hg.python.org/cpython/rev/b33012ef1417 written by Mark Dickinson. This change has been reverted, see: https://bugs.python.org/issue29282#msg285956

I created this PR to reconsider math.fma() and to use this PR as a starting point to fix the implementation. I'm now waiting the CIs to see how things are going on.

If tests continue to fail on some platforms, I plan to manually handle NaN and INF in the C code, before calling libc fma().

@vstinner

This comment has been minimized.

Copy link
Member Author

vstinner commented Jan 13, 2020

I would prefer to get the same behavior for fma(x, y, z) than (x * y) + z if possible. Here I don't understand why math.fma(math.inf, 0, 0) doesn't return nan. Is it a requirement of IEEE 754, or a Python deliberate choice?

>>> math.fma(math.inf, 0, math.nan)
nan
>>> math.fma(math.inf, 0, 0)
ValueError: invalid operation in fma

>>> (math.inf * 0) + math.nan
nan
>>> (math.inf * 0) + 0
nan

cc @mdickinson

@bedevere-bot

This comment has been minimized.

Copy link

bedevere-bot commented Jan 13, 2020

🤖 New build scheduled with the buildbot fleet by @vstinner for commit 17d570c 🤖

If you want to schedule another build, you need to add the "🔨 test-with-buildbots" label again.

@vstinner

This comment has been minimized.

Copy link
Member Author

vstinner commented Jan 13, 2020

Strange. Tests passed on Linux and Windows pre-commit CIs. Let me try on stable buildbots.

@mdickinson

This comment has been minimized.

Copy link
Member

mdickinson commented Jan 13, 2020

Is it a requirement of IEEE 754, or a Python deliberate choice?

fma is a standard IEEE 754 function, so yes, the behaviour in corner cases is fully specified by IEEE 754, and we should expect to follow that behaviour.

@mdickinson

This comment has been minimized.

Copy link
Member

mdickinson commented Jan 13, 2020

Here I don't understand why math.fma(math.inf, 0, 0) doesn't return nan.

This is the usual rule about propagating NaNs, together with Python's rules for wrapping existing functions (as articulated at the top of mathmodule.c). In situations where IEEE 754 signals a floating-point exception, Python should be raising. But if any of the three arguments to fma is a NaN, then a NaN is silently propagated, and no floating-point exception is signaled.

Think of fma as a 3-argument operation, not as exactly equivalent to a*b + c.

@mdickinson

This comment has been minimized.

Copy link
Member

mdickinson commented Jan 13, 2020

Think of fma as a 3-argument operation, not as exactly equivalent to a*b + c.

You can also look at Decimal's implementation, which should also be following IEEE 754 rules (but with the added complication of having to handle signalling NaNs correctly).

@vstinner

This comment has been minimized.

Copy link
Member Author

vstinner commented Jan 13, 2020

test_fma_zero_result() fails on FreeBSD:

FAIL: test_fma_zero_result (test.test_math.FMATests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/home/buildbot/python/pull_request.koobs-freebsd-9e36.nondebug/build/Lib/test/test_math.py", line 2213, in test_fma_zero_result
    self.assertIsNegativeZero(math.fma(x-y, x+y, -z))
  File "/usr/home/buildbot/python/pull_request.koobs-freebsd-9e36.nondebug/build/Lib/test/test_math.py", line 2316, in assertIsNegativeZero
    self.assertTrue(
AssertionError: False is not true : Expected a negative zero, got 0.0

Shared pythoninfo:

CC.version: FreeBSD clang version 9.0.1 (git@github.com:llvm/llvm-project.git c1a0a213378a458fbea1a5c77b315c7dce08fd05) (based on LLVM 9.0.1)
...
platform.libc_ver: libc 7
platform.platform: FreeBSD-13.0-CURRENT-amd64-64bit-ELF

Non-debug pythoninfo:

CC.version: FreeBSD clang version 8.0.1 (tags/RELEASE_801/final 366581) (based on LLVM 8.0.1)
...
platform.libc_ver: libc 7
platform.platform: FreeBSD-12.1-RELEASE-p1-amd64-64bit-ELF

Note: PPC64 Fedora PR failure is unrelated (test_distutils: https://bugs.python.org/issue39248).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.