AI Skill Report Card

Using Decimal Arithmetic

A-84·Sep 5, 2026·Source: Web
14 / 15
Python
from decimal import Decimal, getcontext, ROUND_HALF_UP # Create Decimals from strings (not floats!) for exactness price = Decimal("19.99") tax_rate = Decimal("0.075") tax = (price * tax_rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) total = price + tax print(total) # Decimal('21.49') # Compare: float arithmetic introduces error print(0.1 + 0.2) # 0.30000000000000004 print(Decimal("0.1") + Decimal("0.2")) # 0.3
Recommendation
Add an example showing a bad outcome from a real bug scenario (e.g., what happens if float is used for money over many transactions, showing accumulated error)
14 / 15

Progress:

  • Step 1: Identify why float is insufficient (money, exact decimal rules, auditability)
  • Step 2: Construct Decimals from strings or integers, never from floats directly
  • Step 3: Set global context precision if defaults (28 digits) are insufficient
  • Step 4: Perform arithmetic — operators (+, -, *, /) work naturally
  • Step 5: Round/quantize results to the desired number of decimal places
  • Step 6: Choose an explicit rounding mode matching business/legal requirements
  • Step 7: Handle exceptional conditions (DivisionByZero, InvalidOperation, Overflow) if inputs are untrusted
  • Step 8: Use localcontext() for temporary precision/rounding changes scoped to a block

Step 1: Constructing Decimals correctly

Python
# CORRECT — exact d1 = Decimal("0.1") d2 = Decimal(10) d3 = Decimal((0, (3, 1, 4), -2)) # sign, digits tuple, exponent -> 3.14 # WRONG — inherits binary float imprecision d_bad = Decimal(0.1) # Decimal('0.1000000000000000055511151231257827021181583404541015625')

Step 2: Setting precision

Python
from decimal import getcontext getcontext().prec = 50 # global precision (significant digits), default 28

Step 3: Scoped precision with localcontext

Python
from decimal import localcontext with localcontext() as ctx: ctx.prec = 6 result = Decimal(1) / Decimal(7) # only affects this block # outside the block, precision reverts to previous setting

Step 4: Rounding and quantizing

Python
from decimal import ( ROUND_CEILING, ROUND_FLOOR, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_DOWN, ROUND_UP, ROUND_05UP ) value = Decimal("2.675") value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) # 2.68 value.quantize(Decimal("0.01"), rounding=ROUND_HALF_EVEN) # 2.67 (banker's rounding, module default)

Step 5: Handling exceptions

Python
from decimal import Decimal, DivisionByZero, InvalidOperation, localcontext with localcontext() as ctx: ctx.traps[DivisionByZero] = True # raise instead of returning Infinity try: Decimal(1) / Decimal(0) except DivisionByZero: print("cannot divide by zero")
Recommendation
Include guidance on serialization/deserialization with JSON since Decimal isn't natively JSON-serializable, a common real-world pitfall
16 / 20

Example 1: Currency total with tax Input:

Python
items = [Decimal("12.50"), Decimal("7.25"), Decimal("3.10")] subtotal = sum(items) tax = (subtotal * Decimal("0.08")).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

Output:

subtotal = Decimal('22.85')
tax = Decimal('1.83')

Example 2: Setting precision for scientific-style computation Input:

Python
from decimal import Decimal, localcontext with localcontext() as ctx: ctx.prec = 10 result = Decimal(22) / Decimal(7)

Output:

result = Decimal('3.142857143')

Example 3: Comparing Decimal to float safely Input:

Python
Decimal("0.1") == 0.1

Output:

False  # never mix Decimal and float directly in comparisons/arithmetic;
       # convert float via str first: Decimal(str(0.1))
Recommendation
The workflow checklist and step-by-step 'Step 1-5' headers duplicate content awkwardly (checklist has 8 steps but only 5 are detailed) — align these for clarity
  • Always construct Decimal from a string or integer; converting from float propagates binary imprecision.
  • Use quantize() for fixed-point rounding to a specific number of decimal places (e.g., cents).
  • Prefer ROUND_HALF_UP for typical financial rounding, ROUND_HALF_EVEN (default) for statistically unbiased rounding.
  • Use localcontext() to scope temporary precision/rounding changes instead of mutating the global context permanently.
  • Set prec high enough for intermediate calculations; only round/quantize the final displayed or stored value.
  • Never mix Decimal and float in arithmetic or equality comparisons — convert explicitly first.
  • Use Decimal.is_nan(), .is_infinite(), .is_zero() for safe special-value checks instead of comparisons.
  • For serialization, use str(decimal_value) to preserve exact representation.
  • Passing a float literal to Decimal() (e.g., Decimal(0.1)) — silently imports float's imprecision.
  • Forgetting that getcontext().prec sets significant digits, not decimal places — use quantize() for decimal-place control.
  • Assuming round() behaves like quantize()round() on Decimal follows context rounding but doesn't fix exponent/decimal places the same way.
  • Ignoring InvalidOperation, Overflow, or DivisionByZero traps when processing untrusted input, causing NaN/Infinity to propagate silently.
  • Mutating the global context (getcontext().prec = X) instead of using localcontext(), causing precision leaks across unrelated code.
  • Comparing Decimal and float directly, which can raise errors or produce misleading equality results.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
14/15
Examples
16/20
Completeness
17/20
Format
14/15
Conciseness
13/15