diff --git a/jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/numeric/PythonDecimal.java b/jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/numeric/PythonDecimal.java index 9429195..6c7a4b3 100644 --- a/jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/numeric/PythonDecimal.java +++ b/jpyinterpreter/src/main/java/ai/timefold/jpyinterpreter/types/numeric/PythonDecimal.java @@ -346,7 +346,10 @@ public int hashCode() { // Other methods // *************************** public PythonInteger $method$adjusted() { - return PythonInteger.valueOf(getExponent()); + // scale is the negative exponent that the big int is multiplied by + // len(unscaled) - 1 = floor(log_10(unscaled)) + // floor(log_10(unscaled)) - scale = exponent in engineering notation + return PythonInteger.valueOf(value.unscaledValue().toString().length() - 1 - value.scale()); } public PythonLikeTuple $method$as_integer_ratio() { @@ -370,21 +373,14 @@ public int hashCode() { PythonInteger.valueOf(reducedDenominator)); } - private int getExponent() { - // scale is the negative exponent that the big int is multiplied by - // len(unscaled) - 1 = floor(log_10(unscaled)) - // floor(log_10(unscaled)) - scale = exponent in engineering notation - return value.unscaledValue().toString().length() - 1 - value.scale(); - } - public PythonLikeTuple $method$as_tuple() { // TODO: Use named tuple - return PythonLikeTuple.fromItems(PythonInteger.valueOf(value.signum()), - value.unscaledValue().toString() + return PythonLikeTuple.fromItems(PythonInteger.valueOf(value.signum() >= 0 ? 0 : 1), + value.unscaledValue().abs().toString() .chars() .mapToObj(digit -> PythonInteger.valueOf(digit - '0')) .collect(Collectors.toCollection(PythonLikeTuple::new)), - PythonInteger.valueOf(getExponent())); + PythonInteger.valueOf(-value.scale())); } public PythonDecimal $method$canonical() { diff --git a/jpyinterpreter/tests/test_decimal.py b/jpyinterpreter/tests/test_decimal.py index bdf54ca..d513c5f 100644 --- a/jpyinterpreter/tests/test_decimal.py +++ b/jpyinterpreter/tests/test_decimal.py @@ -301,15 +301,21 @@ def as_integer_ratio(a: Decimal) -> tuple[int, int]: adjusted_verifier.verify(Decimal('-3.14'), expected_result=(-157, 50)) -# TODO: Use named tuples -# def test_as_tuple(): -# def as_tuple(a: Decimal) -> tuple[int, int, int]: -# return a.as_tuple() -# -# as_tuple_verifier = verifier_for(as_tuple) -# as_tuple_verifier.verify(Decimal(100), expected_result=(0, (1, 0, 0), 0)) -# as_tuple_verifier.verify(Decimal(-100), expected_result=(1, (1, 0, 0), 0)) -# as_tuple_verifier.verify(Decimal('123.45'), expected_result=(0, (1, 2, 3, 4, 5), -2)) +# TODO: Make as_tuple use NamedTuple +def test_as_tuple(): + def as_tuple(a: Decimal) -> tuple[int, tuple[int,...], int]: + return a.as_tuple() + + def matches_tuple(t: tuple[int, tuple[int,...], int]) -> Callable[[tuple[int, tuple[int,...], int]], bool]: + def predicate(tested: tuple[int, tuple[int,...], int]) -> bool: + return t == tested + + return predicate + + as_tuple_verifier = verifier_for(as_tuple) + as_tuple_verifier.verify_property(Decimal(100), predicate=matches_tuple((0, (1, 0, 0), 0))) + as_tuple_verifier.verify_property(Decimal(-100), predicate=matches_tuple((1, (1, 0, 0), 0))) + as_tuple_verifier.verify_property(Decimal('123.45'), predicate=matches_tuple((0, (1, 2, 3, 4, 5), -2))) def test_canonical():