diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 66263a5f..628ae796 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -42,7 +42,7 @@ jobs: - run: echo "PKG_CONFIG_PATH=${{ github.workspace }}/.local/lib/pkgconfig" >> $env:GITHUB_ENV if: ${{ startsWith(matrix.os, 'windows') }} - name: Build wheels - uses: pypa/cibuildwheel@v4.0.0 + uses: pypa/cibuildwheel@v4.1.0 - uses: actions/upload-artifact@v7 with: name: wheels-${{ matrix.os }} diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a61a1043..313354df 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -17,8 +17,6 @@ build: python: install: - path: . - extra_requirements: - - docs sphinx: fail_on_warning: true configuration: docs/conf.py diff --git a/pyproject.toml b/pyproject.toml index 5806366e..4b1fe020 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,16 +44,9 @@ Homepage = "https://github.com/diofant/python-gmp" Documentation = "https://python-gmp.readthedocs.io/en/latest/" [project.optional-dependencies] -tests = ["pytest", "hypothesis", "mpmath"] +tests = ["pytest", "hypothesis"] ci = ["python-gmp[tests]", "pytest-xdist"] -docs = ["sphinx>=8.2"] -develop = ["python-gmp[tests,docs]", "pre-commit", "pyperf"] - -[tool.meson-python.args] -compile = ["--verbose"] - -[tool.pytest.ini_options] -xfail_strict = true +develop = ["python-gmp[tests]", "prek", "pyperf"] [tool.ruff] line-length = 79 @@ -79,10 +72,8 @@ CFLAGS = "-Wall -Wpedantic -Werror -Wconversion" [tool.cibuildwheel.windows] archs = ["auto64"] before-all = "msys2 -c scripts/cibw_before_all.sh" -before-build = "pip install delvewheel" -repair-wheel-command = """delvewheel repair -w {dest_dir} {wheel} \ - --add-path .local/bin""" [tool.cibuildwheel.windows.environment] PYTEST_ADDOPTS = "-n 2" CFLAGS = "" +PATH = ".\\\\.local\\\\bin;$PATH" diff --git a/tests/test_functions.py b/tests/test_functions.py index 41adf211..d89efc3c 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -22,6 +22,8 @@ from hypothesis.strategies import booleans, integers, lists, sampled_from from utils import ( bigints, + mpmath_from_man_exp, + mpmath_normalize, python_gcdext, python_isqrtrem, ) @@ -137,11 +139,10 @@ def test_lcm_nary(xs): @example(1, 6277101735386680763495507056286727952638980837032266301441, 0, 64, "f") def test_mpmath_normalize(sign, man, exp, prec, rnd): - mpmath = pytest.importorskip("mpmath") mman = mpz(man) sign = int(sign) bc = mman.bit_length() - res = mpmath.libmp.libmpf._normalize(sign, man, exp, bc, prec, rnd) + res = mpmath_normalize(sign, man, exp, bc, prec, rnd) assert all(type(_) is int for _ in res) assert _mpmath_normalize(sign, mman, exp, bc, prec, rnd) == res @@ -152,9 +153,8 @@ def test_mpmath_normalize(sign, man, exp, prec, rnd): @example(-6277101735386680763495507056286727952638980837032266301441, 0, 64, "f") def test_mpmath_create(man, exp, prec, rnd): - mpmath = pytest.importorskip("mpmath") mman = mpz(man) - res = mpmath.libmp.from_man_exp(man, exp, prec, rnd) + res = mpmath_from_man_exp(man, exp, prec, rnd) assert all(type(_) is int for _ in res) assert _mpmath_create(mman, exp, prec, rnd) == res assert mman == man diff --git a/tests/utils.py b/tests/utils.py index 9ee2a9c1..1b0935e6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -182,3 +182,54 @@ def numbers(draw): if draw(booleans()): return draw(floats()) return draw(complex_numbers()) + + +def mpmath_normalize(sign, man, exp, bc, prec, rnd): + """ + Create a raw mpf tuple with value (-1)**sign * man * 2**exp and + normalized mantissa. The mantissa is rounded in the specified + direction if its size exceeds the precision. Trailing zero bits + are also stripped from the mantissa to ensure that the + representation is canonical. + """ + if not man: + return 0, 0, 0, 0 + # Cut mantissa down to size if larger than target precision + n = bc - prec + if n > 0: + # The >> operator rounds to floor. shifts_down[rnd][sign] + # tells whether this is the right direction to use, or if the + # number should be negated before shifting + shifts_down = {"f": (1, 0), "c": (0, 1), "d": (1, 1), "u": (0, 0)} + if rnd == "n": + t = man >> (n - 1) + if t & 1 and ((t & 2) or (man & ((1 << (n - 1)) - 1))): + man = (t >> 1) + 1 + else: + man = t >> 1 + elif shifts_down[rnd][sign]: + man >>= n + else: + man = -((-man) >> n) + exp += n + # Strip trailing bits + while man & 1 == 0: + man >>= 1 + exp += 1 + return sign, man, exp, man.bit_length() + + +def mpmath_from_man_exp(man, exp, prec=0, rnd="d"): + """ + Create raw mpf from (man, exp) pair. The mantissa may be signed. + If no precision is specified, the mantissa is stored exactly. + """ + if man < 0: + sign = 1 + man = -man + else: + sign = 0 + bc = man.bit_length() + if not prec: + prec = bc + return mpmath_normalize(sign, man, exp, bc, prec, rnd)