fast-math-rs 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fast_math_rs-0.1.0/.github/workflows/ci.yml +108 -0
- fast_math_rs-0.1.0/.github/workflows/release.yml +86 -0
- fast_math_rs-0.1.0/.github/workflows/wheels.yml +99 -0
- fast_math_rs-0.1.0/.gitignore +20 -0
- fast_math_rs-0.1.0/CHANGELOG.md +26 -0
- fast_math_rs-0.1.0/Cargo.lock +132 -0
- fast_math_rs-0.1.0/Cargo.toml +42 -0
- fast_math_rs-0.1.0/GLOSSARY.md +51 -0
- fast_math_rs-0.1.0/LICENSE +21 -0
- fast_math_rs-0.1.0/Makefile +74 -0
- fast_math_rs-0.1.0/PKG-INFO +144 -0
- fast_math_rs-0.1.0/README.md +112 -0
- fast_math_rs-0.1.0/benchmarks/run.py +176 -0
- fast_math_rs-0.1.0/docs/benchmarks/py3.14-arm64.json +56 -0
- fast_math_rs-0.1.0/docs/benchmarks.md +44 -0
- fast_math_rs-0.1.0/docs/guide/development.md +61 -0
- fast_math_rs-0.1.0/docs/guide/semantics.md +90 -0
- fast_math_rs-0.1.0/pyproject.toml +119 -0
- fast_math_rs-0.1.0/python/fast_math/__init__.py +46 -0
- fast_math_rs-0.1.0/python/fast_math/_core.pyi +98 -0
- fast_math_rs-0.1.0/python/fast_math/py.typed +0 -0
- fast_math_rs-0.1.0/rustfmt.toml +1 -0
- fast_math_rs-0.1.0/scripts/smoke.sh +27 -0
- fast_math_rs-0.1.0/scripts/version.py +107 -0
- fast_math_rs-0.1.0/src/arith.rs +277 -0
- fast_math_rs-0.1.0/src/lib.rs +10 -0
- fast_math_rs-0.1.0/src/number.rs +37 -0
- fast_math_rs-0.1.0/src/python.rs +154 -0
- fast_math_rs-0.1.0/src/theory.rs +185 -0
- fast_math_rs-0.1.0/tests/__init__.py +0 -0
- fast_math_rs-0.1.0/tests/conftest.py +8 -0
- fast_math_rs-0.1.0/tests/reference.py +56 -0
- fast_math_rs-0.1.0/tests/test_arguments.py +66 -0
- fast_math_rs-0.1.0/tests/test_arithmetic.py +116 -0
- fast_math_rs-0.1.0/tests/test_docs.py +51 -0
- fast_math_rs-0.1.0/tests/test_number_theory.py +108 -0
- fast_math_rs-0.1.0/tests/test_threads.py +32 -0
- fast_math_rs-0.1.0/tests/test_version_script.py +77 -0
- fast_math_rs-0.1.0/uv.lock +687 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
# A new push to a pull request supersedes the run of the previous one; runs on master all finish
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
|
12
|
+
|
|
13
|
+
env:
|
|
14
|
+
CARGO_TERM_COLOR: always
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
version:
|
|
18
|
+
# A pull request into master is a release once merged, so it must carry a new version
|
|
19
|
+
if: github.event_name == 'pull_request'
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v5
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0 # the base branch and the tags
|
|
25
|
+
- uses: astral-sh/setup-uv@v6
|
|
26
|
+
- run: uv run --no-project python scripts/version.py check "origin/${{ github.base_ref }}"
|
|
27
|
+
|
|
28
|
+
lint:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v5
|
|
32
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
33
|
+
with:
|
|
34
|
+
components: rustfmt, clippy
|
|
35
|
+
- uses: Swatinem/rust-cache@v2
|
|
36
|
+
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
- run: uv sync --locked
|
|
38
|
+
- run: uv run ruff check .
|
|
39
|
+
- run: uv run ruff format --check .
|
|
40
|
+
- run: uv run mypy
|
|
41
|
+
- run: uvx pyright@1.1.414 # the pin of the Makefile
|
|
42
|
+
- run: uv run stubtest fast_math
|
|
43
|
+
- run: cargo fmt --check
|
|
44
|
+
- run: cargo clippy --all-targets --all-features -- -D warnings
|
|
45
|
+
env:
|
|
46
|
+
# The bindings are configured against an interpreter: the one of the venv
|
|
47
|
+
PYO3_PYTHON: ${{ github.workspace }}/.venv/bin/python
|
|
48
|
+
|
|
49
|
+
rust-test:
|
|
50
|
+
# The core alone, without Python: `cargo test` builds without the `python` feature
|
|
51
|
+
runs-on: ${{ matrix.os }}
|
|
52
|
+
strategy:
|
|
53
|
+
fail-fast: false
|
|
54
|
+
matrix:
|
|
55
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v5
|
|
58
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
59
|
+
- uses: Swatinem/rust-cache@v2
|
|
60
|
+
- run: cargo test
|
|
61
|
+
|
|
62
|
+
test:
|
|
63
|
+
# Every operating system: the float results come from the platform's libm, as Python's own do
|
|
64
|
+
runs-on: ${{ matrix.os }}
|
|
65
|
+
strategy:
|
|
66
|
+
fail-fast: false
|
|
67
|
+
matrix:
|
|
68
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
69
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v5
|
|
72
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
73
|
+
- uses: Swatinem/rust-cache@v2
|
|
74
|
+
- uses: astral-sh/setup-uv@v6
|
|
75
|
+
with:
|
|
76
|
+
python-version: ${{ matrix.python-version }}
|
|
77
|
+
- run: uv sync --locked
|
|
78
|
+
- run: uv run pytest --cov --cov-report=term
|
|
79
|
+
|
|
80
|
+
free-threaded:
|
|
81
|
+
# The tests on CPython 3.14t without PYTHON_GIL=0: importing the extension must leave the GIL off by itself
|
|
82
|
+
runs-on: ubuntu-latest
|
|
83
|
+
steps:
|
|
84
|
+
- uses: actions/checkout@v5
|
|
85
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
86
|
+
- uses: Swatinem/rust-cache@v2
|
|
87
|
+
- uses: astral-sh/setup-uv@v6
|
|
88
|
+
with:
|
|
89
|
+
python-version: "3.14t"
|
|
90
|
+
- run: make test-free-threaded
|
|
91
|
+
|
|
92
|
+
benchmarks:
|
|
93
|
+
# A smoke run of benchmarks/run.py, so it keeps working; the figures of a GitHub runner are too noisy to
|
|
94
|
+
# gate on, docs/benchmarks.md holds the baseline
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
continue-on-error: true
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v5
|
|
99
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
100
|
+
- uses: Swatinem/rust-cache@v2
|
|
101
|
+
- uses: astral-sh/setup-uv@v6
|
|
102
|
+
- run: uv sync --locked
|
|
103
|
+
- run: uv run python benchmarks/run.py --quick
|
|
104
|
+
|
|
105
|
+
wheels:
|
|
106
|
+
# Every release target builds on every pull request, so a platform that breaks fails before the merge
|
|
107
|
+
if: github.event_name == 'pull_request'
|
|
108
|
+
uses: ./.github/workflows/wheels.yml
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Every push to master releases the version in pyproject.toml. The version job of CI makes sure a pull
|
|
4
|
+
# request bumps it; a change that reaches master without a bump fails here. See scripts/version.py.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: release
|
|
11
|
+
cancel-in-progress: false
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
version:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
outputs:
|
|
17
|
+
version: ${{ steps.version.outputs.version }}
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v5
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0 # the tags tell which versions are released
|
|
22
|
+
- uses: astral-sh/setup-uv@v6
|
|
23
|
+
- id: version
|
|
24
|
+
name: Check that the version is not released yet
|
|
25
|
+
run: |
|
|
26
|
+
version=$(uv run --no-project python scripts/version.py unreleased)
|
|
27
|
+
echo "version=${version}" >> "$GITHUB_OUTPUT"
|
|
28
|
+
|
|
29
|
+
test:
|
|
30
|
+
needs: version
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v5
|
|
34
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
35
|
+
- uses: Swatinem/rust-cache@v2
|
|
36
|
+
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
- run: cargo test
|
|
38
|
+
- run: uv sync --locked
|
|
39
|
+
- run: uv run pytest
|
|
40
|
+
|
|
41
|
+
wheels:
|
|
42
|
+
needs: version
|
|
43
|
+
uses: ./.github/workflows/wheels.yml
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
needs: [test, wheels]
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment:
|
|
49
|
+
name: pypi
|
|
50
|
+
url: https://pypi.org/project/fast-math-rs/
|
|
51
|
+
permissions:
|
|
52
|
+
id-token: write # PyPI Trusted Publishing
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/download-artifact@v4
|
|
55
|
+
with:
|
|
56
|
+
pattern: wheels-*
|
|
57
|
+
merge-multiple: true
|
|
58
|
+
path: dist/
|
|
59
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
|
|
61
|
+
tag:
|
|
62
|
+
needs: [version, publish]
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
permissions:
|
|
65
|
+
contents: write
|
|
66
|
+
env:
|
|
67
|
+
VERSION: ${{ needs.version.outputs.version }}
|
|
68
|
+
GH_TOKEN: ${{ github.token }}
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v5
|
|
71
|
+
- uses: astral-sh/setup-uv@v6
|
|
72
|
+
- uses: actions/download-artifact@v4
|
|
73
|
+
with:
|
|
74
|
+
pattern: wheels-*
|
|
75
|
+
merge-multiple: true
|
|
76
|
+
path: dist/
|
|
77
|
+
- name: Tag the release
|
|
78
|
+
run: |
|
|
79
|
+
git config user.name "github-actions[bot]"
|
|
80
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
81
|
+
git tag -a "v${VERSION}" -m "fast-math-rs ${VERSION}"
|
|
82
|
+
git push origin "v${VERSION}"
|
|
83
|
+
- name: Publish the release notes from CHANGELOG.md, with the wheels and the sdist
|
|
84
|
+
run: |
|
|
85
|
+
uv run --no-project python scripts/version.py notes > notes.md
|
|
86
|
+
gh release create "v${VERSION}" --verify-tag --title "fast-math-rs ${VERSION}" --notes-file notes.md dist/*
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
name: Wheels
|
|
2
|
+
|
|
3
|
+
# The wheels of every release target and the sdist, as artifacts named wheels-*; called by CI on a pull request
|
|
4
|
+
# and by Release. Each target builds an abi3 wheel for CPython 3.11+ and one for free-threaded 3.14t (ADR-0004),
|
|
5
|
+
# and a target the runner can run imports both before they are uploaded.
|
|
6
|
+
on:
|
|
7
|
+
workflow_call:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
linux:
|
|
11
|
+
runs-on: ${{ matrix.runner }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
include:
|
|
16
|
+
- { runner: ubuntu-latest, target: x86_64, platform: manylinux_2_28, smoke: true }
|
|
17
|
+
- { runner: ubuntu-24.04-arm, target: aarch64, platform: manylinux_2_28, smoke: true }
|
|
18
|
+
- { runner: ubuntu-latest, target: x86_64, platform: musllinux_1_2, smoke: false }
|
|
19
|
+
- { runner: ubuntu-24.04-arm, target: aarch64, platform: musllinux_1_2, smoke: false }
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v5
|
|
22
|
+
- uses: PyO3/maturin-action@v1
|
|
23
|
+
with:
|
|
24
|
+
target: ${{ matrix.target }}
|
|
25
|
+
manylinux: ${{ matrix.platform }}
|
|
26
|
+
args: --release --out dist --interpreter 3.11 3.14t
|
|
27
|
+
- uses: astral-sh/setup-uv@v6
|
|
28
|
+
if: matrix.smoke
|
|
29
|
+
- name: Import the wheels
|
|
30
|
+
if: matrix.smoke
|
|
31
|
+
shell: bash
|
|
32
|
+
run: scripts/smoke.sh dist
|
|
33
|
+
- uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: wheels-linux-${{ matrix.target }}-${{ matrix.platform }}
|
|
36
|
+
path: dist
|
|
37
|
+
|
|
38
|
+
macos:
|
|
39
|
+
runs-on: ${{ matrix.runner }}
|
|
40
|
+
strategy:
|
|
41
|
+
fail-fast: false
|
|
42
|
+
matrix:
|
|
43
|
+
include:
|
|
44
|
+
- { runner: macos-15-intel, target: x86_64 }
|
|
45
|
+
- { runner: macos-latest, target: aarch64 }
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v5
|
|
48
|
+
- uses: actions/setup-python@v6
|
|
49
|
+
with:
|
|
50
|
+
python-version: |
|
|
51
|
+
3.11
|
|
52
|
+
3.14t
|
|
53
|
+
- uses: PyO3/maturin-action@v1
|
|
54
|
+
with:
|
|
55
|
+
target: ${{ matrix.target }}
|
|
56
|
+
args: --release --out dist --interpreter 3.11 3.14t
|
|
57
|
+
- uses: astral-sh/setup-uv@v6
|
|
58
|
+
- name: Import the wheels
|
|
59
|
+
shell: bash
|
|
60
|
+
run: scripts/smoke.sh dist
|
|
61
|
+
- uses: actions/upload-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: wheels-macos-${{ matrix.target }}
|
|
64
|
+
path: dist
|
|
65
|
+
|
|
66
|
+
windows:
|
|
67
|
+
runs-on: windows-latest
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v5
|
|
70
|
+
- uses: actions/setup-python@v6
|
|
71
|
+
with:
|
|
72
|
+
python-version: |
|
|
73
|
+
3.11
|
|
74
|
+
3.14t
|
|
75
|
+
- uses: PyO3/maturin-action@v1
|
|
76
|
+
with:
|
|
77
|
+
target: x64
|
|
78
|
+
args: --release --out dist --interpreter 3.11 3.14t
|
|
79
|
+
- uses: astral-sh/setup-uv@v6
|
|
80
|
+
- name: Import the wheels
|
|
81
|
+
shell: bash
|
|
82
|
+
run: scripts/smoke.sh dist
|
|
83
|
+
- uses: actions/upload-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: wheels-windows-x64
|
|
86
|
+
path: dist
|
|
87
|
+
|
|
88
|
+
sdist:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v5
|
|
92
|
+
- uses: PyO3/maturin-action@v1
|
|
93
|
+
with:
|
|
94
|
+
command: sdist
|
|
95
|
+
args: --out dist
|
|
96
|
+
- uses: actions/upload-artifact@v4
|
|
97
|
+
with:
|
|
98
|
+
name: wheels-sdist
|
|
99
|
+
path: dist
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
*.egg-info/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.mypy_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.hypothesis/
|
|
11
|
+
.coverage
|
|
12
|
+
coverage.xml
|
|
13
|
+
htmlcov/
|
|
14
|
+
.DS_Store
|
|
15
|
+
.idea/
|
|
16
|
+
.vscode/
|
|
17
|
+
# Rust: the build tree, and the extension that an editable install builds into the Python sources
|
|
18
|
+
target/
|
|
19
|
+
python/fast_math/*.so
|
|
20
|
+
python/fast_math/*.pyd
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and the project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-10-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- The Rust core and its Python package `fast_math`:
|
|
14
|
+
- arithmetic with the semantics of the Python operators: `add`, `sub`, `mul`, `div`, `floordiv`, `mod`,
|
|
15
|
+
`pow`, `abs`, `sqrt`; an `int` with an `int` gives an `int`, anything with a `float` a `float`;
|
|
16
|
+
- number theory on 64-bit integers: `gcd`, `lcm`, `factorial`, `fibonacci`, `is_prime` (a deterministic
|
|
17
|
+
Miller-Rabin test, exact for every 64-bit integer) and `primes_up_to` (a sieve that releases the GIL).
|
|
18
|
+
- 64-bit integers with checked arithmetic: a result or an argument beyond 64 bits raises `OverflowError`.
|
|
19
|
+
- Type stubs, checked against the extension by `stubtest`, and `py.typed`.
|
|
20
|
+
- abi3 wheels for CPython 3.11+ and wheels for free-threaded CPython 3.14t, on which the module keeps the GIL
|
|
21
|
+
off; Linux (glibc, musl; x86_64, aarch64), macOS (x86_64, arm64) and Windows (x64).
|
|
22
|
+
- Property tests of every function against Python itself with hypothesis, Rust unit tests of the core, and
|
|
23
|
+
benchmarks against the builtins and plain Python (`docs/benchmarks.md`).
|
|
24
|
+
|
|
25
|
+
[Unreleased]: https://github.com/troyan-dy/fast_math/compare/v0.1.0...HEAD
|
|
26
|
+
[0.1.0]: https://github.com/troyan-dy/fast_math/releases/tag/v0.1.0
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "fast-math"
|
|
7
|
+
version = "0.0.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"pyo3",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[[package]]
|
|
13
|
+
name = "heck"
|
|
14
|
+
version = "0.5.0"
|
|
15
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
16
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
17
|
+
|
|
18
|
+
[[package]]
|
|
19
|
+
name = "libc"
|
|
20
|
+
version = "0.2.191"
|
|
21
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
22
|
+
checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
|
|
23
|
+
|
|
24
|
+
[[package]]
|
|
25
|
+
name = "once_cell"
|
|
26
|
+
version = "1.21.4"
|
|
27
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
28
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
29
|
+
|
|
30
|
+
[[package]]
|
|
31
|
+
name = "portable-atomic"
|
|
32
|
+
version = "1.15.0"
|
|
33
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
34
|
+
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "proc-macro2"
|
|
38
|
+
version = "1.0.107"
|
|
39
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
40
|
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
|
41
|
+
dependencies = [
|
|
42
|
+
"unicode-ident",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[[package]]
|
|
46
|
+
name = "pyo3"
|
|
47
|
+
version = "0.30.1"
|
|
48
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
49
|
+
checksum = "229ca13b8a15bb0d1487b81ab975bfcd97513416499a8312011b6036e42e0de4"
|
|
50
|
+
dependencies = [
|
|
51
|
+
"libc",
|
|
52
|
+
"once_cell",
|
|
53
|
+
"portable-atomic",
|
|
54
|
+
"pyo3-build-config",
|
|
55
|
+
"pyo3-ffi",
|
|
56
|
+
"pyo3-macros",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[[package]]
|
|
60
|
+
name = "pyo3-build-config"
|
|
61
|
+
version = "0.30.1"
|
|
62
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
63
|
+
checksum = "70130e2b6dd1ee589a8788026a429561ca5c40fa7a2fa7914c2282eddae24700"
|
|
64
|
+
dependencies = [
|
|
65
|
+
"target-lexicon",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[[package]]
|
|
69
|
+
name = "pyo3-ffi"
|
|
70
|
+
version = "0.30.1"
|
|
71
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
72
|
+
checksum = "5e7ff73c555c286d212d4ce7e5fbda845a973c4f61bd5f160f5f2c3c2a04d1c4"
|
|
73
|
+
dependencies = [
|
|
74
|
+
"libc",
|
|
75
|
+
"pyo3-build-config",
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
[[package]]
|
|
79
|
+
name = "pyo3-macros"
|
|
80
|
+
version = "0.30.1"
|
|
81
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
82
|
+
checksum = "c46d2e5862c7bb8207e3b639f713dda3c499933444784154c11d013c5a691b60"
|
|
83
|
+
dependencies = [
|
|
84
|
+
"proc-macro2",
|
|
85
|
+
"pyo3-macros-backend",
|
|
86
|
+
"quote",
|
|
87
|
+
"syn",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
[[package]]
|
|
91
|
+
name = "pyo3-macros-backend"
|
|
92
|
+
version = "0.30.1"
|
|
93
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
94
|
+
checksum = "38b89f066f2ae72a2aef52d1537ca2fcd104440ebfadee06e97aa90738a25b9b"
|
|
95
|
+
dependencies = [
|
|
96
|
+
"heck",
|
|
97
|
+
"proc-macro2",
|
|
98
|
+
"quote",
|
|
99
|
+
"syn",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[[package]]
|
|
103
|
+
name = "quote"
|
|
104
|
+
version = "1.0.47"
|
|
105
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
106
|
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
|
107
|
+
dependencies = [
|
|
108
|
+
"proc-macro2",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
[[package]]
|
|
112
|
+
name = "syn"
|
|
113
|
+
version = "3.0.9"
|
|
114
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
115
|
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
|
116
|
+
dependencies = [
|
|
117
|
+
"proc-macro2",
|
|
118
|
+
"quote",
|
|
119
|
+
"unicode-ident",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
[[package]]
|
|
123
|
+
name = "target-lexicon"
|
|
124
|
+
version = "0.13.5"
|
|
125
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
126
|
+
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
|
127
|
+
|
|
128
|
+
[[package]]
|
|
129
|
+
name = "unicode-ident"
|
|
130
|
+
version = "1.0.27"
|
|
131
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
132
|
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "fast-math"
|
|
3
|
+
# The version of the package lives in pyproject.toml, which maturin reads; the crate is never published
|
|
4
|
+
version = "0.0.0"
|
|
5
|
+
edition = "2024"
|
|
6
|
+
rust-version = "1.85"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
publish = false
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
name = "_core"
|
|
13
|
+
# cdylib: the Python extension; rlib: what `cargo test` links the unit tests of the pure Rust core against
|
|
14
|
+
crate-type = ["cdylib", "rlib"]
|
|
15
|
+
|
|
16
|
+
[dependencies]
|
|
17
|
+
# abi3-py311: one wheel per platform for every CPython from 3.11 on; free-threaded builds get a wheel of
|
|
18
|
+
# their own, since the stable ABI does not cover them (ADR-0004)
|
|
19
|
+
pyo3 = { version = "0.30.1", features = ["abi3-py311"], optional = true }
|
|
20
|
+
|
|
21
|
+
[features]
|
|
22
|
+
# The Python extension; off for `cargo test`, which needs no interpreter then. [tool.maturin] turns it on
|
|
23
|
+
python = ["dep:pyo3"]
|
|
24
|
+
|
|
25
|
+
[profile.release]
|
|
26
|
+
lto = "fat"
|
|
27
|
+
codegen-units = 1
|
|
28
|
+
strip = true
|
|
29
|
+
|
|
30
|
+
[lints.rust]
|
|
31
|
+
unsafe_code = "forbid"
|
|
32
|
+
|
|
33
|
+
[lints.clippy]
|
|
34
|
+
pedantic = { level = "warn", priority = -1 }
|
|
35
|
+
# The core casts between i64, u64 and f64 on purpose, each cast follows the semantics of Python
|
|
36
|
+
cast_possible_truncation = "allow"
|
|
37
|
+
cast_possible_wrap = "allow"
|
|
38
|
+
cast_precision_loss = "allow"
|
|
39
|
+
cast_sign_loss = "allow"
|
|
40
|
+
float_cmp = "allow"
|
|
41
|
+
# Every error of the core is a Python exception, documented in the stubs of python/fast_math/_core.pyi
|
|
42
|
+
missing_errors_doc = "allow"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# fast-math-rs
|
|
2
|
+
|
|
3
|
+
Arithmetic and number theory on Python numbers, computed by a Rust core.
|
|
4
|
+
|
|
5
|
+
## Language
|
|
6
|
+
|
|
7
|
+
**Core**:
|
|
8
|
+
The Rust code that computes: `src/arith.rs`, `src/theory.rs` and `src/number.rs`. It knows nothing of Python and
|
|
9
|
+
is tested by `cargo test` on its own.
|
|
10
|
+
_Avoid_: Backend, engine, native code
|
|
11
|
+
|
|
12
|
+
**Bindings**:
|
|
13
|
+
`src/python.rs`: the conversion of Python objects into **Numbers**, of **Math errors** into exceptions, and the
|
|
14
|
+
`fast_math._core` module. Built only with the `python` cargo feature.
|
|
15
|
+
_Avoid_: Wrapper, glue, FFI layer
|
|
16
|
+
|
|
17
|
+
**Extension**:
|
|
18
|
+
The compiled module `fast_math._core` that maturin builds from the **Core** and the **Bindings**; the package
|
|
19
|
+
`fast_math` re-exports it.
|
|
20
|
+
_Avoid_: Shared library, `.so`
|
|
21
|
+
|
|
22
|
+
**Number**:
|
|
23
|
+
An argument or result of an arithmetic operation: an **Integer** or a **Float**.
|
|
24
|
+
_Avoid_: Value, scalar, numeric
|
|
25
|
+
|
|
26
|
+
**Integer**:
|
|
27
|
+
A Python `int` (or `bool`) in `[-2**63, 2**63 - 1]`, an `i64` in the **Core** (ADR-0002).
|
|
28
|
+
_Avoid_: Long, bigint, int64 (in prose)
|
|
29
|
+
|
|
30
|
+
**Float**:
|
|
31
|
+
A Python `float`, an `f64` in the **Core**.
|
|
32
|
+
_Avoid_: Double, real, decimal
|
|
33
|
+
|
|
34
|
+
**Overflow**:
|
|
35
|
+
An **Integer** result or argument outside 64 bits, or a finite **Float** `pow` whose result is infinite;
|
|
36
|
+
raises `OverflowError`. Never a wrapped, saturated or rounded result.
|
|
37
|
+
_Avoid_: Wrap-around, truncation
|
|
38
|
+
|
|
39
|
+
**Reference**:
|
|
40
|
+
The Python operator or `math` function whose semantics a fast_math function has; the tests compare the two
|
|
41
|
+
on generated arguments (ADR-0003).
|
|
42
|
+
_Avoid_: Oracle, spec, expected value
|
|
43
|
+
|
|
44
|
+
**Departure**:
|
|
45
|
+
A documented case where fast_math differs from its **Reference** on purpose: **Overflow** of **Integers**, and
|
|
46
|
+
`ValueError` for a negative base to a fractional power.
|
|
47
|
+
_Avoid_: Bug, incompatibility, quirk
|
|
48
|
+
|
|
49
|
+
**Math error**:
|
|
50
|
+
`MathError` of the **Core**: overflow, division by zero, domain or memory; each kind is one Python exception.
|
|
51
|
+
_Avoid_: Failure, exception (inside the Core)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dmitriy Troyan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
.DEFAULT_GOAL := help
|
|
2
|
+
|
|
3
|
+
PY_VERSIONS := 3.11 3.12 3.13 3.14
|
|
4
|
+
# Not a dev dependency: uvx keeps it out of uv.lock; the same pin is in .github/workflows/ci.yml
|
|
5
|
+
PYRIGHT := pyright@1.1.414
|
|
6
|
+
|
|
7
|
+
.PHONY: help
|
|
8
|
+
help: ## Show available targets
|
|
9
|
+
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
|
10
|
+
|
|
11
|
+
.PHONY: install
|
|
12
|
+
install: ## Install the dev dependencies and build the extension into .venv
|
|
13
|
+
uv sync --locked
|
|
14
|
+
|
|
15
|
+
.PHONY: lint
|
|
16
|
+
lint: ## Run ruff, mypy, pyright and stubtest on Python; rustfmt and clippy on Rust
|
|
17
|
+
uv run ruff check .
|
|
18
|
+
uv run ruff format --check .
|
|
19
|
+
uv run mypy
|
|
20
|
+
uvx $(PYRIGHT)
|
|
21
|
+
uv run stubtest fast_math
|
|
22
|
+
cargo fmt --check
|
|
23
|
+
cargo clippy --all-targets --all-features -- -D warnings
|
|
24
|
+
|
|
25
|
+
.PHONY: format
|
|
26
|
+
format: ## Autofix lint issues and format the Python and Rust code
|
|
27
|
+
uv run ruff check --fix .
|
|
28
|
+
uv run ruff format .
|
|
29
|
+
cargo fmt
|
|
30
|
+
|
|
31
|
+
.PHONY: test
|
|
32
|
+
test: ## Run the Python tests
|
|
33
|
+
uv run pytest
|
|
34
|
+
|
|
35
|
+
.PHONY: rust-test
|
|
36
|
+
rust-test: ## Run the Rust unit tests of the core
|
|
37
|
+
cargo test
|
|
38
|
+
|
|
39
|
+
.PHONY: cov
|
|
40
|
+
cov: ## Run the Python tests with a coverage report
|
|
41
|
+
uv run pytest --cov --cov-report=term --cov-report=html
|
|
42
|
+
|
|
43
|
+
.PHONY: test-all
|
|
44
|
+
test-all: ## Run the Python tests on every supported Python version
|
|
45
|
+
@for v in $(PY_VERSIONS); do \
|
|
46
|
+
echo "==> Python $$v"; \
|
|
47
|
+
uv run --isolated --python $$v pytest || exit 1; \
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
.PHONY: test-free-threaded
|
|
51
|
+
test-free-threaded: ## Run the Python tests on free-threaded Python 3.14t, as CI does; the GIL must stay off by itself
|
|
52
|
+
uv run --python 3.14t --isolated --no-default-groups --with pytest --with hypothesis pytest -p no:cacheprovider
|
|
53
|
+
|
|
54
|
+
.PHONY: bench
|
|
55
|
+
bench: ## Run the benchmarks, see docs/benchmarks.md
|
|
56
|
+
uv run python benchmarks/run.py
|
|
57
|
+
|
|
58
|
+
.PHONY: check-version
|
|
59
|
+
check-version: ## Check that the version is bumped against origin/master, as CI does for a pull request
|
|
60
|
+
git fetch --quiet --tags origin master
|
|
61
|
+
uv run --no-project python scripts/version.py check origin/master
|
|
62
|
+
|
|
63
|
+
.PHONY: check
|
|
64
|
+
check: lint rust-test test ## Run everything CI runs
|
|
65
|
+
|
|
66
|
+
.PHONY: wheels
|
|
67
|
+
wheels: ## Build the release wheels of this platform (abi3 and 3.14t) and the sdist into dist/
|
|
68
|
+
uvx maturin build --release --out dist --interpreter 3.11 3.14t
|
|
69
|
+
uvx maturin sdist --out dist
|
|
70
|
+
|
|
71
|
+
.PHONY: clean
|
|
72
|
+
clean: ## Remove build artifacts and caches; the extension built into python/fast_math/ stays, `uv run` needs it
|
|
73
|
+
rm -rf build dist target *.egg-info htmlcov .coverage coverage.xml .pytest_cache .mypy_cache .ruff_cache .hypothesis
|
|
74
|
+
find . -type d -name __pycache__ -not -path './.venv/*' -exec rm -rf {} +
|