From 8fcc0655628620417a6caf31c2e5ccebf8ab36d7 Mon Sep 17 00:00:00 2001 From: Chris Rink Date: Fri, 22 Nov 2024 14:03:42 -0500 Subject: [PATCH] Fix a bug where integer results of integer division are always returned as fractions (#1141) Fixes #1140 --- CHANGELOG.md | 1 + src/basilisp/lang/runtime.py | 4 +++- tests/basilisp/runtime_test.py | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e2803a8..f9478aa5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fix a bug where tags in data readers were resolved as Vars within syntax quotes, rather than using standard data readers rules (#1129) * Fix a bug where `keyword` and `symbol` functions did not treat string arguments as potentially namespaced (#1131) * Fix a bug where `condp` would throw an exception if a result expression was `nil` (#1137) + * Fix a bug where integer division which resulted in an integer would return a `fractions.Fraction` (#1140) ## [v0.3.2] ### Added diff --git a/src/basilisp/lang/runtime.py b/src/basilisp/lang/runtime.py index c4f575cd..c05067ad 100644 --- a/src/basilisp/lang/runtime.py +++ b/src/basilisp/lang/runtime.py @@ -1655,7 +1655,9 @@ def divide(x: LispNumber, y: LispNumber) -> LispNumber: @divide.register(int) def _divide_ints(x: int, y: LispNumber) -> LispNumber: if isinstance(y, int): - return Fraction(x, y) + frac = Fraction(x, y) + # fractions.Fraction.is_integer() wasn't added until 3.12 + return frac.numerator if frac.denominator == 1 else frac return x / y diff --git a/tests/basilisp/runtime_test.py b/tests/basilisp/runtime_test.py index f736b5fd..31155176 100644 --- a/tests/basilisp/runtime_test.py +++ b/tests/basilisp/runtime_test.py @@ -1,3 +1,4 @@ +import fractions import platform import sys from decimal import Decimal @@ -599,6 +600,23 @@ def test_not_equals(v1, v2): assert not runtime.equals(v2, v1) +@pytest.mark.parametrize( + "v1,v2,expected_result,result_type", + [ + (3, 3, 1, int), + (3, 1, 3, int), + (3, 1.001, 3 / 1.001, float), + (3000, 1000, 3, int), + (3000, 1001, fractions.Fraction(3000, 1001), fractions.Fraction), + (3001, 1000, fractions.Fraction(3001, 1000), fractions.Fraction), + ], +) +def test_divide(v1, v2, expected_result, result_type): + result = runtime.divide(v1, v2) + assert result == expected_result + assert isinstance(result, result_type) + + def test_pop_thread_bindings(): with pytest.raises(runtime.RuntimeException): runtime.pop_thread_bindings()