Compute a percentage from Decimal values without float conversion
Compute a percentage from Decimal values without float conversion
To compute a percentage from Decimal values without float conversion, multiply by Decimal("100") and divide by the Decimal total. With part = Decimal("1.5") and whole = Decimal("4"), the result is exactly Decimal("37.5").
The first calculation is the failing transformation: it converts both record values to float, so its result is a float, not a Decimal. This fixture prints 37.5 because 1.5, 4, and 37.5 happen to be exactly representable in binary floating point. That does not make the path Decimal-only; the type assertion exposes the conversion boundary without falsely claiming that this particular input visibly rounds.
The correction leaves the mapping unchanged and performs the calculation with Decimal operands. localcontext() creates a copy of the active context, and the example sets its precision to 6. Therefore, this assertion is independent of a caller's prior precision setting, but not of every possible caller context setting: exponent limits, rounding, and traps are retained unless a fully specified Context is supplied. Six significant digits are sufficient for this terminating result. The assertions show only that this synthetic record is unchanged, the converted path produces a float, and the Decimal calculation equals Decimal("37.5"). They do not validate a nonzero denominator or establish a display-rounding policy. For repeating results or a fixed number of display places, use quantize() with an explicit rounding rule.
The official decimal documentation covers string construction, float conversion, contexts, localcontext(), and quantize(). The Decimal APIs used here are long-established; this exact executable requires Python 3.6+ because it uses formatted string literals, introduced in Python 3.6.
AI assistance disclosure: this article was drafted with AI assistance using a synthetic, locally reproducible fixture.
from decimal import Decimal, localcontext
record = {"part": Decimal("1.5"), "whole": Decimal("4")}
original_record = record.copy()
float_percentage = float(record["part"]) * 100 / float(record["whole"])
try:
assert isinstance(float_percentage, Decimal)
except AssertionError:
failing_outcome = f"float result: {float_percentage}"
else:
raise AssertionError("the conversion path should produce a float")
with localcontext() as context:
context.prec = 6
percentage = record["part"] * Decimal("100") / record["whole"]
assert record == original_record
assert isinstance(float_percentage, float)
assert percentage == Decimal("37.5")
print(f"input: {record}")
print(f"float conversion: {failing_outcome}")
print(f"Decimal-only result: {percentage} percent")
input: {'part': Decimal('1.5'), 'whole': Decimal('4')}
float conversion: float result: 37.5
Decimal-only result: 37.5 percent