Commit Graph
6 Commits
Author SHA1 Message Date
Jeongseop Lim a39d6c9676 Pass round() ndigits to __round__ unchanged (#8997)
round(x, ndigits) ran ndigits through __index__ before calling
__round__, so a user-defined __round__ never saw a non-integer ndigits
and an __index__ object reached it already converted to int. CPython's
builtin_round_impl() forwards ndigits as-is and leaves the conversion
to float.__round__ and int.__round__.

Forward the object, and take ndigits as ArgIndex in both slots so they
apply __index__ themselves. Calling the slots directly with an
__index__ object now works as in CPython instead of raising TypeError.

Assisted-by: Claude Code:claude-opus-5
Assisted-by: Claude Code:claude-opus-5-5
2026-10-07 23:18:55 +09:00
Jeongseop Lim 2e05364117 Normalize round() result to an exact int (#8511)
int.__round__ returned the receiver unchanged on the no-rounding path, so
round() on an int subclass handed back an instance of that subclass:
round(True) was True, not 1. CPython routes both no-op paths (ndigits is
None, and ndigits >= 0) through long_long(), which reuses the reference
only when the value is an exact int and otherwise copies it into a fresh
one.

Return zelf.__int__(vm).into_pyref(), which goes through into_exact_or()
and is the same normalization the neighbouring __trunc__, __floor__ and
__ceil__ already perform.

Assisted-by: Claude Code:claude-opus-5
2026-08-13 20:27:24 +09:00
ChangjoonandShaharNaveh 2d485de90b Round float at the decimal level to match CPython's _Py_dg_dtoa (#7761)
* Round float at the decimal level to match CPython's _Py_dg_dtoa

CPython's `float.__round__` (Objects/floatobject.c) routes through
`_Py_dg_dtoa` and rounds at the decimal level. The previous
`round_float_digits` multiplied by 10**ndigits and rounded at the
IEEE 754 binary level, which diverges for values that aren't exactly
representable. For example, 2.675 stores as 2.67499...; dtoa correctly
rounds it down to 2.67, but `(2.675 * 100.0).round() / 100.0` lands on
2.68 because the multiplication produces a phantom 267.5 tie that
round-half-to-even snaps up.

Rust's `{:.*}` float formatting uses dtoa-style algorithms (Grisu3 +
Dragon4 fallback) and matches CPython's `_Py_dg_dtoa` byte-for-byte.
Replace the multiply-then-round step with `format!` + `parse` for
ndigits >= 0. The ndigits < 0 path is unchanged because dividing
typical inputs by 10**|ndigits| produces genuine ties rather than
synthesizing them.

Verified byte-identical with CPython 3.14.4 over a 108-case random
fuzz plus targeted half-tie probes. Unmasks
`test_float.RoundTestCase.test_matches_float_format` and
`test_previous_round_bugs`.

* Use #[expect] with reason for float_cmp suppression

Co-authored-by: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com>

---------

Co-authored-by: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com>
2026-05-03 00:16:27 +09:00
Rex Ledesma 4e2e0b41c6 chore: add ruff format --check (#5774)
* chore: add `ruff format --check`

* fix tests
2025-05-12 14:20:01 +09:00
Jeong Yunwon bf0daabbae split math_basics.py to proper files 2022-05-04 00:53:20 +09:00
Jeong YunWon e62a164f4d Move tests -> extra_tests 2020-09-13 06:58:57 +09:00