Skip to main content

Fused multiply-add with 32-bit float support and configurable IEEE 754 rounding modes

Project description

python-fma

coverage tests

A Python fused multiply-add (FMA) binding with 32 and 64-bit float support and configurable IEEE 754 rounding modes.

Python 3.13+ provides math.fma, but it operates on float (IEEE 754 double) only and does not expose the rounding direction. This module fills both gaps:

  • Accepts ct.c_double (float64) and ct.c_float (float32).
  • Lets the caller select the rounding mode per-call.
  • Detects and reports IEEE 754 floating-point exceptions (invalid, overflow, underflow, inexact, divide-by-zero).
  • Restores the original FP rounding state after each operation.

Note

I write this project with vibe coding, but I carefully read every line in /src/ and /csrc/ folder, and I glanced at test code (and provides some data for rounding test), so the core logic should be ok.

The coverage test rate is high, and all non-platform-dependent code is covered in test.


Installation

$ pip install python-fma

The package ships a pre-built wheel for Linux, Windows and MacOS, support x86 and ARM architecture.

Requirements

  • Python >= 3.10

if you want to build from source:

  • C11 compiler
  • CMake >= 3.25

API

fma(x, y, z, round=None, unsuppressed_exception=...)

import ctypes as ct

from python_fma import fma, DivByZeroException, OverflowException

r = fma(ct.c_double(2.0), ct.c_double(3.0), ct.c_double(1.0))
# r.value == 7.0
Parameter Type Default Description
x, y, z ct.c_double or ct.c_float Operands (must all be the same type)
round str or None None Rounding mode (see below). None leaves the current FP mode unchanged.
unsuppressed_exception set of exception classes {DivByZeroException, OverflowException} Exception types allowed to propagate; all others are silently suppressed.

Rounding mode strings:

Name Behaviour
"FE_TONEAREST" Round to nearest, ties to even
"FE_UPWARD" Round toward +infinity
"FE_DOWNWARD" Round toward -infinity
"FE_TOWARDZERO" Truncate toward zero

Returns: ct.c_double or ct.c_float (same type as the inputs).

Raises:

  • TypeError — inputs are not all the same type or not a supported type.
  • ValueError — unrecognised rounding-mode string.
  • FeatureNotCompiledError — the rounding mode or an exception flag was not detected at compile time.
  • UnsupportedRoundingModeError — the platform does not support the requested rounding mode at runtime.
  • DivByZeroException, OverflowException — by default; other exceptions (InvalidException, UnderflowException, InexactException) are suppressed unless explicitly included in unsuppressed_exception.

exception_compiled(name)

Return whether detection of the floating-point exception name is available in the C build.

from python_fma import exception_compiled, InvalidException

exception_compiled(InvalidException)   # True / False

round_mode_compiled(name)

Return whether the rounding mode name was detected at compile time.

from python_fma import round_mode_compiled

round_mode_compiled("FE_UPWARD")   # True / False

round_mode_supported(name)

Return whether the rounding mode name is supported at runtime.

from python_fma import round_mode_supported

round_mode_supported("FE_TOWARDZERO")   # True / False

Exception hierarchy

Exception
  └── FloatException
        ├── InvalidException          (FE_INVALID)
        ├── DivByZeroException        (FE_DIVBYZERO)
        ├── OverflowException         (FE_OVERFLOW)
        ├── UnderflowException        (FE_UNDERFLOW)
        ├── InexactException          (FE_INEXACT)
        ├── FeatureNotCompiledError   (query/compile-time support)
        └── UnsupportedRoundingModeError  (also a ValueError)

Usage examples

Basic FMA

import ctypes as ct
from python_fma import fma

r = fma(ct.c_double(2.0), ct.c_double(3.0), ct.c_double(1.0))
# 2.0 * 3.0 + 1.0 = 7.0

Single-precision FMA

r = fma(ct.c_float(1.5), ct.c_float(2.0), ct.c_float(0.5))
# r.value == 3.5, type(r) is ct.c_float

Explicit rounding mode

r = fma(ct.c_double(1.0), ct.c_double(1.0), ct.c_double(0.1),
        round="FE_UPWARD")

Controlling which exceptions propagate

# Only allow InvalidException to propagate; suppress everything else.
r = fma(ct.c_double(float("inf")), ct.c_double(0.0), ct.c_double(0.0),
        unsuppressed_exception={InvalidException})

Querying compile-time feature support

from python_fma import exception_compiled, round_mode_compiled, InvalidException

if not round_mode_compiled("FE_UPWARD"):
    print("FE_UPWARD not available in this build")
if not exception_compiled(InvalidException):
    print("Invalid exception detection not available in this build")

Development

Setup

$ python -m venv .venv
$ source .venv/bin/activate
$ pip install -e .

Lint and type-check

$ ruff check src/ tests/
$ ruff format --check src/ tests/
$ npx pyright src/ tests/

Test

$ python -m pytest tests/ -v

Build a wheel

$ pip install build
$ python -m build

CI / Docker build

Manylinux wheels are built via Docker:

$ docker build \
  --build-arg BASE_IMAGE=quay.io/pypa/manylinux2014_x86_64 \
  -t builder .
$ docker run --rm -v "$PWD/wheelhouse:/wheelhouse" builder

Windows and macOS wheels are built natively on GitHub Actions runners. See .github/workflows/build.yml for the full CI matrix.


Project structure

python-fma/
├── csrc/                  # C source (fma_module.c, fma_module.h, CMakeLists.txt)
├── src/
│   └── python_fma/
│       ├── __init__.py    # Public Python API
│       └── _binding.py    # ctypes bindings to the C library
├── badges/                # generated coverage badge
├── tests/                 # pytest test suite
├── pyproject.toml         # Build configuration (scikit-build-core, ruff)
├── README.md              # This file
├── Dockerfile             # manylinux wheel builder
└── .github/workflows/     # CI workflows

License

MPL

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

python_fma-1.0.0-py3-none-win_arm64.whl (17.2 kB view details)

Uploaded Python 3Windows ARM64

python_fma-1.0.0-py3-none-win_amd64.whl (18.0 kB view details)

Uploaded Python 3Windows x86-64

python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl (15.7 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_34_aarch64.whl (15.9 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64manylinux: glibc 2.34+ ARM64

python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl (15.9 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64manylinux: glibc 2.28+ ARM64

python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_34_x86_64.manylinux_2_5_x86_64.whl (15.7 kB view details)

Uploaded Python 3manylinux: glibc 2.34+ x86-64manylinux: glibc 2.5+ x86-64

python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (15.7 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64manylinux: glibc 2.5+ x86-64

python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (15.7 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

python_fma-1.0.0-py3-none-macosx_26_0_x86_64.whl (14.2 kB view details)

Uploaded Python 3macOS 26.0+ x86-64

python_fma-1.0.0-py3-none-macosx_15_0_arm64.whl (14.4 kB view details)

Uploaded Python 3macOS 15.0+ ARM64

File details

Details for the file python_fma-1.0.0-py3-none-win_arm64.whl.

File metadata

  • Download URL: python_fma-1.0.0-py3-none-win_arm64.whl
  • Upload date:
  • Size: 17.2 kB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for python_fma-1.0.0-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 77f321206906bd02a499f29b87632621e253c247e7e30ea3beb272cfd22e20ae
MD5 966885a0ed9db914ca4c57c4405d5d85
BLAKE2b-256 5b5c726a1662474aaa1ba9567f7f881e135fc0fa9af68092e8ba88b664caf767

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-win_arm64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: python_fma-1.0.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 18.0 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for python_fma-1.0.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 dea6b1e3f8fac17a6b5d170a6d87ab7b05b9f6c382ccda53417bc44ac33007d2
MD5 e2a550e03429e747a547938be2f3e249
BLAKE2b-256 276a107b9202fc925f27dff9d51c6c7da5523a690b6fbd9bb8f34c9d4d4d7fbf

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-win_amd64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 2de5377976b6e2002618854ce63131dbd7d8211abe30a8e77f832a3b509a8d90
MD5 64882eda185c799f9c3ab8a585508d6a
BLAKE2b-256 79c60678ba4bc296e952d6dc0f2cee12e53ff9db551c47172f3af3ad91bfd620

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_34_aarch64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 2c814f4bcdd2856d0bf7053d1395d0606e2f629ef90f15de3d632ac852c7b500
MD5 368b6190f576e5f756f47e0399b1cc16
BLAKE2b-256 91bfe3b3a34172783848b08ebace99a5c495b4644f46e1cb2b83050f2499295d

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_34_aarch64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6a77ffe3b7d03449ed31845709e92ff963de3dfda75e9fd58ece44fffc2d7acb
MD5 ca9a4822f00e737d1e05286b9dacb106
BLAKE2b-256 a7aadf15f71799016a1d8af4451f45e832e5ba56619cc8bab3f079ca636dbc1d

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_34_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_34_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 157ccef32d5844778dc8c590eacb11d51ac0babfa83f0c5de8e31b8d50839d7e
MD5 1804ae5413077472a9859a4dcb8fc91e
BLAKE2b-256 74d4db8902c718430c4b9f53487c371def5ae67dd0b4094c87c7f182528f9fa1

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_34_x86_64.manylinux_2_5_x86_64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 b9ceb7cc2005f93b65a1b69892131bc5755257ce5f0c44080724039eb55e5122
MD5 06f86af6a8f2a77e690c7f2c387f4c9f
BLAKE2b-256 8abd26176100c6852ff5b53723c5e16baedd9538631eec8342c830ec78b4bbd2

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 154e0cf92136d318f002feaef8c45e3858f67f47a1b94ec733adbe0421417f8e
MD5 e37fb57595dbdb76da1a1d380502dda2
BLAKE2b-256 781a6ef5d9fd9cea078698837d6cf00e8a08789a532f042410301e47fdf233d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-macosx_26_0_x86_64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-macosx_26_0_x86_64.whl
Algorithm Hash digest
SHA256 fdfdd3f0b2d5633c9451ea7439e005e2ada2e7e392d88501709d5ac803481b51
MD5 866f1f7f99ff22880cda966910878197
BLAKE2b-256 deee604844cc1a2456673cb7e39864fe0434efaed37038633c541aa17fb5c52b

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-macosx_26_0_x86_64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_fma-1.0.0-py3-none-macosx_15_0_arm64.whl.

File metadata

File hashes

Hashes for python_fma-1.0.0-py3-none-macosx_15_0_arm64.whl
Algorithm Hash digest
SHA256 75df694e10caf5689e8dc35e73994189f194facd747b7edceaaa783bf053a638
MD5 c32b1ec509c1f524160030fab8835c08
BLAKE2b-256 884fb1ed9498bf5736fd0f16102910042fd81c3bb8ef8a0a87236a0315fb1420

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_fma-1.0.0-py3-none-macosx_15_0_arm64.whl:

Publisher: release.yml on LXYan2333/python_fma

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page