Math & Numbers
Decimal Introduction
Financial applications and accounting systems cannot tolerate the rounding errors inherent in binary floating-point numbers. The Decimal module provides exact decimal arithmetic, ensuring that $0.10 + $0.20 equals exactly $0.30, not 0.30000000000000004.
Decimal
A numeric type that represents decimal numbers exactly as humans write them, avoiding binary floating-point representation errors.
Creating Decimals
Always create Decimals from strings for precision:
create.py
Replay: real traced execution (multi-file project)
# Create Decimal
from decimal import Decimal, getcontext
# Create Decimal
print("Create Decimal:")
# From string (recommended)
d1 = Decimal('10.5')
print(f"From string: {d1}")
# From integer
d2 = Decimal(42)
print(f"From int: {d2}")
# From float (may have precision issues)
d3 = Decimal(10.5)
print(f"From float: {d3}") # May show extra digits
# Proper way from float
d4 = Decimal(str(10.5))
print(f"From str(float): {d4}")
# Very precise numbers
precise = Decimal('3.14159265358979323846264338327950288419716939937510')
print(f"\nPrecise pi: {precise}")
# Constants
print("\nConstants:")
print(f"Decimal('0'): {Decimal('0')}")
print(f"Decimal('1'): {Decimal('1')}")
print(f"Decimal('Infinity'): {Decimal('Infinity')}")
print(f"Decimal('-Infinity'): {Decimal('-Infinity')}")
print(f"Decimal('NaN'): {Decimal('NaN')}")
# Tuple representation
print("\nTuple representation:")
# (sign, digits, exponent)
d5 = Decimal((0, (1, 2, 3), -2)) # 1.23
print(f"From tuple (0, (1, 2, 3), -2): {d5}")
d6 = Decimal((1, (5, 0), 0)) # -50
print(f"From tuple (1, (5, 0), 0): {d6}")
# Precision context
print("\nPrecision context:")
print(f"Current precision: {getcontext().prec}")
getcontext().prec = 10
result = Decimal('1') / Decimal('3')
print(f"1/3 with prec=10: {result}")
getcontext().prec = 50
result = Decimal('1') / Decimal('3')
print(f"1/3 with prec=50: {result}")
# Reset to default
getcontext().prec = 28
# Convert to other types
print("\nConvert to other types:")
d = Decimal('42.75')
print(f"Decimal: {d}")
print(f"int: {int(d)}")
print(f"float: {float(d)}")
print(f"str: {str(d)}")
# Scientific notation
print("\nScientific notation:")
d7 = Decimal('1.23E+5')
print(f"1.23E+5: {d7}")
d8 = Decimal('4.56E-3')
print(f"4.56E-3: {d8}")
# Compare with float issues
print("\nFloat vs Decimal precision:")
print(f"Float: 0.1 + 0.1 + 0.1 = {0.1 + 0.1 + 0.1}")
print(f"Decimal: 0.1 + 0.1 + 0.1 = {Decimal('0.1') + Decimal('0.1') + Decimal('0.1')}")
print(f"\nFloat: 1.1 + 2.2 = {1.1 + 2.2}")
print(f"Decimal: 1.1 + 2.2 = {Decimal('1.1') + Decimal('2.2')}")
d1 ← 10.5, d2 ← 42, d3 ← 10.5, d4 ← 10.5, precise ← 3.14159265358979323846264338327950288419716939937510
5# Create Decimal6print("Create Decimal:")7# From string (recommended)8d1→ 10.5 = Decimal('10.5')9print(f"From string: {d110.5}")1011# From integer12d2→ 42 = Decimal(42)13print(f"From int: {d242}")1415# From float (may have precision issues)16d3→ 10.5 = Decimal(10.5)17print(f"From float: {d310.5}") # May show extra digits1819# Proper way from float20d4→ 10.5 = Decimal(str(10.5))21print(f"From str(float): {d410.5}")2223# Very precise numbers24precise→ 3.14159265358979323846264338327950288419716939937510 = Decimal('3.14159265358979323846264338327950288419716939937510')25print(f"\nPrecise pi: {precise3.14159265358979323846264338327950288419716939937510}")2627# Constants28print("\nConstants:")29print(f"Decimal('0'): {Decimal('0')}")30print(f"Decimal('1'): {Decimal('1')}")31print(f"Decimal('Infinity'): {Decimal('Infinity')}")32print(f"Decimal('-Infinity'): {Decimal('-Infinity')}")33print(f"Decimal('NaN'): {Decimal('NaN')}")3435# Tuple representation36print("\nTuple representation:")37# (sign, digits, exponent)38d5→ 1.23 = Decimal((0, (1, 2, 3), -2)) # 1.2339print(f"From tuple (0, (1, 2, 3), -2): {d51.23}")4041d6→ -50 = Decimal((1, (5, 0), 0)) # -5042print(f"From tuple (1, (5, 0), 0): {d6-50}")4344# Precision context45print("\nPrecision context:")46print(f"Current precision: {getcontext().prec}")47getcontext().prec = 1048result→ 0.3333333333 = Decimal('1') / Decimal('3')49print(f"1/3 with prec=10: {result0.3333333333}")5051getcontext().prec = 5052result→ 0.33333333333333333333333333333333333333333333333333 = Decimal('1') / Decimal('3')53print(f"1/3 with prec=50: {result0.33333333333333333333333333333333333333333333333333}")5455# Reset to default56getcontext().prec = 285758# Convert to other types59print("\nConvert to other types:")60d→ 42.75 = Decimal('42.75')61print(f"Decimal: {d42.75}")62print(f"int: {int(d42.75)}")63print(f"float: {float(d42.75)}")64print(f"str: {str(d42.75)}")6566# Scientific notation67print("\nScientific notation:")68d7→ 1.23E+5 = Decimal('1.23E+5')69print(f"1.23E+5: {d71.23E+5}")70d8→ 0.00456 = Decimal('4.56E-3')71print(f"4.56E-3: {d80.00456}")7273# Compare with float issues74print("\nFloat vs Decimal precision:")75print(f"Float: 0.1 + 0.1 + 0.1 = {0.1 + 0.1 + 0.1}")76print(f"Decimal: 0.1 + 0.1 + 0.1 = {Decimal('0.1') + Decimal('0.1') + Decimal('0.1')}")7778print(f"\nFloat: 1.1 + 2.2 = {1.1 + 2.2}")79print(f"Decimal: 1.1 + 2.2 = {Decimal('1.1') + Decimal('2.2')}")outputCreate Decimal: From string: 10.5 From int: 42 From float: 10.5 From str(float): 10.5 Precise pi: 3.14159265358979323846264338327950288419716939937510 Constants: Decimal('0'): 0 Decimal('1'): 1 Decimal('Infinity'): Infinity Decimal('-Infinity'): -Infinity Decimal('NaN'): NaN Tuple representation: From tuple (0, (1, 2, 3), -2): 1.23 From tuple (1, (5, 0), 0): -50 Precision context: Current precision: 28 1/3 with prec=10: 0.3333333333 1/3 with prec=50: 0.33333333333333333333333333333333333333333333333333 Convert to other types: Decimal: 42.75 int: 42 float: 42.75 str: 42.75 Scientific notation: 1.23E+5: 1.23E+5 4.56E-3: 0.00456 Float vs Decimal precision: Float: 0.1 + 0.1 + 0.1 = 0.30000000000000004 Decimal: 0.1 + 0.1 + 0.1 = 0.3 Float: 1.1 + 2.2 = 3.3000000000000003 Decimal: 1.1 + 2.2 = 3.3
string initialization
Creating Decimal from strings like Decimal('0.1') preserves exact values, while Decimal(0.1) inherits float imprecision.
Arithmetic Operations
Decimal supports all standard arithmetic:
arithmetic.py
Replay: real traced execution (multi-file project)
# Arithmetic operations
from decimal import Decimal, getcontext
# Arithmetic operations
a = Decimal('10.5')
b = Decimal('3.25')
print(f"a = {a}")
print(f"b = {b}")
print()
# Addition
print("Addition:")
print(f"a + b = {a + b}")
# Subtraction
print("\nSubtraction:")
print(f"a - b = {a - b}")
# Multiplication
print("\nMultiplication:")
print(f"a * b = {a * b}")
# Division
print("\nDivision:")
print(f"a / b = {a / b}")
# Floor division
print("\nFloor division:")
print(f"a // b = {a // b}")
# Modulo
print("\nModulo:")
print(f"a % b = {a % b}")
# Power
print("\nPower:")
print(f"a ** 2 = {a ** 2}")
print(f"2 ** 10 = {Decimal('2') ** 10}")
# Negation
print("\nNegation:")
print(f"-a = {-a}")
# Absolute value
print("\nAbsolute value:")
neg = Decimal('-42.5')
print(f"abs({neg}) = {abs(neg)}")
# divmod
print("\ndivmod:")
quotient, remainder = divmod(a, b)
print(f"divmod({a}, {b}) = ({quotient}, {remainder})")
# Chaining operations
print("\nChaining:")
result = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')
print(f"5 * 3 + 10 - 2 = {result}")
# Precision in operations
print("\nPrecision in operations:")
getcontext().prec = 10
x = Decimal('1') / Decimal('3')
print(f"1/3 with prec=10: {x}")
print(f"x * 3 = {x * Decimal('3')}")
getcontext().prec = 28 # Reset
# Square root
print("\nSquare root:")
d = Decimal('16')
print(f"sqrt({d}) = {d.sqrt()}")
d2 = Decimal('2')
print(f"sqrt({d2}) = {d2.sqrt()}")
# Exponential and log
print("\nExponential:")
d = Decimal('1')
print(f"exp({d}) = {d.exp()}")
print("\nNatural logarithm:")
d = Decimal('10')
print(f"ln({d}) = {d.ln()}")
print("\nBase-10 logarithm:")
d = Decimal('100')
print(f"log10({d}) = {d.log10()}")
# Compound calculations
print("\nCompound interest:")
principal = Decimal('1000')
rate = Decimal('0.05')
time = 10
amount = principal * (Decimal('1') + rate) ** time
print(f"Principal: ${principal}")
print(f"Rate: {rate * 100}%")
print(f"Time: {time} years")
print(f"Amount: ${amount:.2f}")
print(f"Interest: ${amount - principal:.2f}")
# Precise division
print("\nPrecise division:")
getcontext().prec = 50
result = Decimal('1') / Decimal('7')
print(f"1/7 = {result}")
getcontext().prec = 28 # Reset
# Arithmetic operations
from decimal import Decimal, getcontext
# Arithmetic operations
a = Decimal('10.5')
b = Decimal('3.25')
print(f"a = {a}")
print(f"b = {b}")
print()
# Addition
print("Addition:")
print(f"a + b = {a + b}")
# Subtraction
print("\nSubtraction:")
print(f"a - b = {a - b}")
# Multiplication
print("\nMultiplication:")
print(f"a * b = {a * b}")
# Division
print("\nDivision:")
print(f"a / b = {a / b}")
# Floor division
print("\nFloor division:")
print(f"a // b = {a // b}")
# Modulo
print("\nModulo:")
print(f"a % b = {a % b}")
# Power
print("\nPower:")
print(f"a ** 2 = {a ** 2}")
print(f"2 ** 10 = {Decimal('2') ** 10}")
# Negation
print("\nNegation:")
print(f"-a = {-a}")
# Absolute value
print("\nAbsolute value:")
neg = Decimal('-42.5')
print(f"abs({neg}) = {abs(neg)}")
# divmod
print("\ndivmod:")
quotient, remainder = divmod(a, b)
print(f"divmod({a}, {b}) = ({quotient}, {remainder})")
# Chaining operations
print("\nChaining:")
result = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')
print(f"5 * 3 + 10 - 2 = {result}")
# Precision in operations
print("\nPrecision in operations:")
getcontext().prec = 10
x = Decimal('1') / Decimal('3')
print(f"1/3 with prec=10: {x}")
print(f"x * 3 = {x * Decimal('3')}")
getcontext().prec = 28 # Reset
# Square root
print("\nSquare root:")
d = Decimal('16')
print(f"sqrt({d}) = {d.sqrt()}")
d2 = Decimal('2')
print(f"sqrt({d2}) = {d2.sqrt()}")
# Exponential and log
print("\nExponential:")
d = Decimal('1')
print(f"exp({d}) = {d.exp()}")
print("\nNatural logarithm:")
d = Decimal('10')
print(f"ln({d}) = {d.ln()}")
print("\nBase-10 logarithm:")
d = Decimal('100')
print(f"log10({d}) = {d.log10()}")
# Compound calculations
print("\nCompound interest:")
principal = Decimal('500')
rate = Decimal('0.05')
time = 10
amount = principal * (Decimal('1') + rate) ** time
print(f"Principal: ${principal}")
print(f"Rate: {rate * 100}%")
print(f"Time: {time} years")
print(f"Amount: ${amount:.2f}")
print(f"Interest: ${amount - principal:.2f}")
# Precise division
print("\nPrecise division:")
getcontext().prec = 50
result = Decimal('1') / Decimal('7')
print(f"1/7 = {result}")
getcontext().prec = 28 # Reset
# Arithmetic operations
from decimal import Decimal, getcontext
# Arithmetic operations
a = Decimal('10.5')
b = Decimal('3.25')
print(f"a = {a}")
print(f"b = {b}")
print()
# Addition
print("Addition:")
print(f"a + b = {a + b}")
# Subtraction
print("\nSubtraction:")
print(f"a - b = {a - b}")
# Multiplication
print("\nMultiplication:")
print(f"a * b = {a * b}")
# Division
print("\nDivision:")
print(f"a / b = {a / b}")
# Floor division
print("\nFloor division:")
print(f"a // b = {a // b}")
# Modulo
print("\nModulo:")
print(f"a % b = {a % b}")
# Power
print("\nPower:")
print(f"a ** 2 = {a ** 2}")
print(f"2 ** 10 = {Decimal('2') ** 10}")
# Negation
print("\nNegation:")
print(f"-a = {-a}")
# Absolute value
print("\nAbsolute value:")
neg = Decimal('-42.5')
print(f"abs({neg}) = {abs(neg)}")
# divmod
print("\ndivmod:")
quotient, remainder = divmod(a, b)
print(f"divmod({a}, {b}) = ({quotient}, {remainder})")
# Chaining operations
print("\nChaining:")
result = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')
print(f"5 * 3 + 10 - 2 = {result}")
# Precision in operations
print("\nPrecision in operations:")
getcontext().prec = 10
x = Decimal('1') / Decimal('3')
print(f"1/3 with prec=10: {x}")
print(f"x * 3 = {x * Decimal('3')}")
getcontext().prec = 28 # Reset
# Square root
print("\nSquare root:")
d = Decimal('16')
print(f"sqrt({d}) = {d.sqrt()}")
d2 = Decimal('2')
print(f"sqrt({d2}) = {d2.sqrt()}")
# Exponential and log
print("\nExponential:")
d = Decimal('1')
print(f"exp({d}) = {d.exp()}")
print("\nNatural logarithm:")
d = Decimal('10')
print(f"ln({d}) = {d.ln()}")
print("\nBase-10 logarithm:")
d = Decimal('100')
print(f"log10({d}) = {d.log10()}")
# Compound calculations
print("\nCompound interest:")
principal = Decimal('2500')
rate = Decimal('0.05')
time = 10
amount = principal * (Decimal('1') + rate) ** time
print(f"Principal: ${principal}")
print(f"Rate: {rate * 100}%")
print(f"Time: {time} years")
print(f"Amount: ${amount:.2f}")
print(f"Interest: ${amount - principal:.2f}")
# Precise division
print("\nPrecise division:")
getcontext().prec = 50
result = Decimal('1') / Decimal('7')
print(f"1/7 = {result}")
getcontext().prec = 28 # Reset
a ← 10.5, b ← 3.25, neg ← -42.5, quotient ← 3, remainder ← 0.75
5# Arithmetic operations6a→ 10.5 = Decimal('10.5')7b→ 3.25 = Decimal('3.25')89print(f"a = {a10.5}")10print(f"b = {b3.25}")11print()1213# Addition14print("Addition:")15print(f"a + b = {a10.5 + b3.25}")1617# Subtraction18print("\nSubtraction:")19print(f"a - b = {a10.5 - b3.25}")2021# Multiplication22print("\nMultiplication:")23print(f"a * b = {a10.5 * b3.25}")2425# Division26print("\nDivision:")27print(f"a / b = {a10.5 / b3.25}")2829# Floor division30print("\nFloor division:")31print(f"a // b = {a10.5 // b3.25}")3233# Modulo34print("\nModulo:")35print(f"a % b = {a10.5 % b3.25}")3637# Power38print("\nPower:")39print(f"a ** 2 = {a10.5 ** 2}")40print(f"2 ** 10 = {Decimal('2') ** 10}")4142# Negation43print("\nNegation:")44print(f"-a = {-a10.5}")4546# Absolute value47print("\nAbsolute value:")48neg→ -42.5 = Decimal('-42.5')49print(f"abs({neg-42.5}) = {abs(neg)}")5051# divmod52print("\ndivmod:")53quotient→ 3, remainder→ 0.75 = divmod(a10.5, b3.25)54print(f"divmod({a10.5}, {b3.25}) = ({quotient3}, {remainder0.75})")5556# Chaining operations57print("\nChaining:")58result→ 23 = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')59print(f"5 * 3 + 10 - 2 = {result23}")6061# Precision in operations62print("\nPrecision in operations:")63getcontext().prec = 1064x→ 0.3333333333 = Decimal('1') / Decimal('3')65print(f"1/3 with prec=10: {x0.3333333333}")66print(f"x * 3 = {x0.3333333333 * Decimal('3')}")6768getcontext().prec = 28 # Reset6970# Square root71print("\nSquare root:")72d→ 16 = Decimal('16')73print(f"sqrt({d16}) = {d.sqrt()}")7475d2→ 2 = Decimal('2')76print(f"sqrt({d22}) = {d2.sqrt()}")7778# Exponential and log79print("\nExponential:")80d→ 1 = Decimal('1')81print(f"exp({d1}) = {d.exp()}")8283print("\nNatural logarithm:")84d→ 10 = Decimal('10')85print(f"ln({d10}) = {d.ln()}")8687print("\nBase-10 logarithm:")88d→ 100 = Decimal('100')89print(f"log10({d100}) = {d.log10()}")9091# Compound calculations92print("\nCompound interest:")93principal→ 1000 = Decimal('1000') #@principal=Decimal('500'), Decimal('2500')94rate→ 0.05 = Decimal('0.05')95time→ 10 = 109697amount→ 1628.89462677744140625000 = principal1000 * (Decimal('1') + rate0.05) ** time1098print(f"Principal: ${principal1000}")99print(f"Rate: {rate0.05 * 100}%")100print(f"Time: {time10} years")101print(f"Amount: ${amount1628.89462677744140625000:.2f}")102print(f"Interest: ${amount1628.89462677744140625000 - principal1000:.2f}")103104# Precise division105print("\nPrecise division:")106getcontext().prec = 50107result→ 0.14285714285714285714285714285714285714285714285714 = Decimal('1') / Decimal('7')108print(f"1/7 = {result0.14285714285714285714285714285714285714285714285714}")109getcontext().prec = 28 # Resetoutputa = 10.5 b = 3.25 Addition: a + b = 13.75 Subtraction: a - b = 7.25 Multiplication: a * b = 34.125 Division: a / b = 3.230769230769230769230769231 Floor division: a // b = 3 Modulo: a % b = 0.75 Power: a ** 2 = 110.25 2 ** 10 = 1024 Negation: -a = -10.5 Absolute value: abs(-42.5) = 42.5 divmod: divmod(10.5, 3.25) = (3, 0.75) Chaining: 5 * 3 + 10 - 2 = 23 Precision in operations: 1/3 with prec=10: 0.3333333333 x * 3 = 0.9999999999 Square root: sqrt(16) = 4 sqrt(2) = 1.414213562373095048801688724 Exponential: exp(1) = 2.718281828459045235360287471 Natural logarithm: ln(10) = 2.302585092994045684017991455 Base-10 logarithm: log10(100) = 2 Compound interest: Principal: $1000 Rate: 5.00% Time: 10 years Amount: $1628.89 Interest: $628.89 Precise division: 1/7 = 0.14285714285714285714285714285714285714285714285714
a ← 10.5, b ← 3.25, neg ← -42.5, quotient ← 3, remainder ← 0.75
5# Arithmetic operations6a→ 10.5 = Decimal('10.5')7b→ 3.25 = Decimal('3.25')89print(f"a = {a10.5}")10print(f"b = {b3.25}")11print()1213# Addition14print("Addition:")15print(f"a + b = {a10.5 + b3.25}")1617# Subtraction18print("\nSubtraction:")19print(f"a - b = {a10.5 - b3.25}")2021# Multiplication22print("\nMultiplication:")23print(f"a * b = {a10.5 * b3.25}")2425# Division26print("\nDivision:")27print(f"a / b = {a10.5 / b3.25}")2829# Floor division30print("\nFloor division:")31print(f"a // b = {a10.5 // b3.25}")3233# Modulo34print("\nModulo:")35print(f"a % b = {a10.5 % b3.25}")3637# Power38print("\nPower:")39print(f"a ** 2 = {a10.5 ** 2}")40print(f"2 ** 10 = {Decimal('2') ** 10}")4142# Negation43print("\nNegation:")44print(f"-a = {-a10.5}")4546# Absolute value47print("\nAbsolute value:")48neg→ -42.5 = Decimal('-42.5')49print(f"abs({neg-42.5}) = {abs(neg)}")5051# divmod52print("\ndivmod:")53quotient→ 3, remainder→ 0.75 = divmod(a10.5, b3.25)54print(f"divmod({a10.5}, {b3.25}) = ({quotient3}, {remainder0.75})")5556# Chaining operations57print("\nChaining:")58result→ 23 = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')59print(f"5 * 3 + 10 - 2 = {result23}")6061# Precision in operations62print("\nPrecision in operations:")63getcontext().prec = 1064x→ 0.3333333333 = Decimal('1') / Decimal('3')65print(f"1/3 with prec=10: {x0.3333333333}")66print(f"x * 3 = {x0.3333333333 * Decimal('3')}")6768getcontext().prec = 28 # Reset6970# Square root71print("\nSquare root:")72d→ 16 = Decimal('16')73print(f"sqrt({d16}) = {d.sqrt()}")7475d2→ 2 = Decimal('2')76print(f"sqrt({d22}) = {d2.sqrt()}")7778# Exponential and log79print("\nExponential:")80d→ 1 = Decimal('1')81print(f"exp({d1}) = {d.exp()}")8283print("\nNatural logarithm:")84d→ 10 = Decimal('10')85print(f"ln({d10}) = {d.ln()}")8687print("\nBase-10 logarithm:")88d→ 100 = Decimal('100')89print(f"log10({d100}) = {d.log10()}")9091# Compound calculations92print("\nCompound interest:")93principal→ 500 = Decimal('500')94rate→ 0.05 = Decimal('0.05')95time→ 10 = 109697amount→ 814.44731338872070312500 = principal500 * (Decimal('1') + rate0.05) ** time1098print(f"Principal: ${principal500}")99print(f"Rate: {rate0.05 * 100}%")100print(f"Time: {time10} years")101print(f"Amount: ${amount814.44731338872070312500:.2f}")102print(f"Interest: ${amount814.44731338872070312500 - principal500:.2f}")103104# Precise division105print("\nPrecise division:")106getcontext().prec = 50107result→ 0.14285714285714285714285714285714285714285714285714 = Decimal('1') / Decimal('7')108print(f"1/7 = {result0.14285714285714285714285714285714285714285714285714}")109getcontext().prec = 28 # Resetoutputa = 10.5 b = 3.25 Addition: a + b = 13.75 Subtraction: a - b = 7.25 Multiplication: a * b = 34.125 Division: a / b = 3.230769230769230769230769231 Floor division: a // b = 3 Modulo: a % b = 0.75 Power: a ** 2 = 110.25 2 ** 10 = 1024 Negation: -a = -10.5 Absolute value: abs(-42.5) = 42.5 divmod: divmod(10.5, 3.25) = (3, 0.75) Chaining: 5 * 3 + 10 - 2 = 23 Precision in operations: 1/3 with prec=10: 0.3333333333 x * 3 = 0.9999999999 Square root: sqrt(16) = 4 sqrt(2) = 1.414213562373095048801688724 Exponential: exp(1) = 2.718281828459045235360287471 Natural logarithm: ln(10) = 2.302585092994045684017991455 Base-10 logarithm: log10(100) = 2 Compound interest: Principal: $500 Rate: 5.00% Time: 10 years Amount: $814.45 Interest: $314.45 Precise division: 1/7 = 0.14285714285714285714285714285714285714285714285714
a ← 10.5, b ← 3.25, neg ← -42.5, quotient ← 3, remainder ← 0.75
5# Arithmetic operations6a→ 10.5 = Decimal('10.5')7b→ 3.25 = Decimal('3.25')89print(f"a = {a10.5}")10print(f"b = {b3.25}")11print()1213# Addition14print("Addition:")15print(f"a + b = {a10.5 + b3.25}")1617# Subtraction18print("\nSubtraction:")19print(f"a - b = {a10.5 - b3.25}")2021# Multiplication22print("\nMultiplication:")23print(f"a * b = {a10.5 * b3.25}")2425# Division26print("\nDivision:")27print(f"a / b = {a10.5 / b3.25}")2829# Floor division30print("\nFloor division:")31print(f"a // b = {a10.5 // b3.25}")3233# Modulo34print("\nModulo:")35print(f"a % b = {a10.5 % b3.25}")3637# Power38print("\nPower:")39print(f"a ** 2 = {a10.5 ** 2}")40print(f"2 ** 10 = {Decimal('2') ** 10}")4142# Negation43print("\nNegation:")44print(f"-a = {-a10.5}")4546# Absolute value47print("\nAbsolute value:")48neg→ -42.5 = Decimal('-42.5')49print(f"abs({neg-42.5}) = {abs(neg)}")5051# divmod52print("\ndivmod:")53quotient→ 3, remainder→ 0.75 = divmod(a10.5, b3.25)54print(f"divmod({a10.5}, {b3.25}) = ({quotient3}, {remainder0.75})")5556# Chaining operations57print("\nChaining:")58result→ 23 = Decimal('5') * Decimal('3') + Decimal('10') - Decimal('2')59print(f"5 * 3 + 10 - 2 = {result23}")6061# Precision in operations62print("\nPrecision in operations:")63getcontext().prec = 1064x→ 0.3333333333 = Decimal('1') / Decimal('3')65print(f"1/3 with prec=10: {x0.3333333333}")66print(f"x * 3 = {x0.3333333333 * Decimal('3')}")6768getcontext().prec = 28 # Reset6970# Square root71print("\nSquare root:")72d→ 16 = Decimal('16')73print(f"sqrt({d16}) = {d.sqrt()}")7475d2→ 2 = Decimal('2')76print(f"sqrt({d22}) = {d2.sqrt()}")7778# Exponential and log79print("\nExponential:")80d→ 1 = Decimal('1')81print(f"exp({d1}) = {d.exp()}")8283print("\nNatural logarithm:")84d→ 10 = Decimal('10')85print(f"ln({d10}) = {d.ln()}")8687print("\nBase-10 logarithm:")88d→ 100 = Decimal('100')89print(f"log10({d100}) = {d.log10()}")9091# Compound calculations92print("\nCompound interest:")93principal→ 2500 = Decimal('2500')94rate→ 0.05 = Decimal('0.05')95time→ 10 = 109697amount→ 4072.23656694360351562500 = principal2500 * (Decimal('1') + rate0.05) ** time1098print(f"Principal: ${principal2500}")99print(f"Rate: {rate0.05 * 100}%")100print(f"Time: {time10} years")101print(f"Amount: ${amount4072.23656694360351562500:.2f}")102print(f"Interest: ${amount4072.23656694360351562500 - principal2500:.2f}")103104# Precise division105print("\nPrecise division:")106getcontext().prec = 50107result→ 0.14285714285714285714285714285714285714285714285714 = Decimal('1') / Decimal('7')108print(f"1/7 = {result0.14285714285714285714285714285714285714285714285714}")109getcontext().prec = 28 # Resetoutputa = 10.5 b = 3.25 Addition: a + b = 13.75 Subtraction: a - b = 7.25 Multiplication: a * b = 34.125 Division: a / b = 3.230769230769230769230769231 Floor division: a // b = 3 Modulo: a % b = 0.75 Power: a ** 2 = 110.25 2 ** 10 = 1024 Negation: -a = -10.5 Absolute value: abs(-42.5) = 42.5 divmod: divmod(10.5, 3.25) = (3, 0.75) Chaining: 5 * 3 + 10 - 2 = 23 Precision in operations: 1/3 with prec=10: 0.3333333333 x * 3 = 0.9999999999 Square root: sqrt(16) = 4 sqrt(2) = 1.414213562373095048801688724 Exponential: exp(1) = 2.718281828459045235360287471 Natural logarithm: ln(10) = 2.302585092994045684017991455 Base-10 logarithm: log10(100) = 2 Compound interest: Principal: $2500 Rate: 5.00% Time: 10 years Amount: $4072.24 Interest: $1572.24 Precise division: 1/7 = 0.14285714285714285714285714285714285714285714285714
Precision Context
Control the precision and rounding behavior:
context.py
Replay: real traced execution (multi-file project)
# Context and precision
from decimal import Decimal, getcontext, localcontext, Context, ROUND_HALF_UP, ROUND_DOWN, InvalidOperation
# Context settings
# Get current context
print("Current context:")
ctx = getcontext()
print(f"Precision: {ctx.prec}")
print(f"Rounding: {ctx.rounding}")
print(f"Emin: {ctx.Emin}")
print(f"Emax: {ctx.Emax}")
print()
# Set precision
print("Set precision:")
getcontext().prec = 10
result = Decimal('1') / Decimal('3')
print(f"1/3 with prec=10: {result}")
getcontext().prec = 50
result = Decimal('1') / Decimal('3')
print(f"1/3 with prec=50: {result}")
getcontext().prec = 28 # Reset to default
# Set rounding mode
print("\nSet rounding mode:")
getcontext().rounding = ROUND_HALF_UP
result = Decimal('2.5').quantize(Decimal('1'))
print(f"2.5 with ROUND_HALF_UP: {result}")
getcontext().rounding = ROUND_DOWN
result = Decimal('2.9').quantize(Decimal('1'))
print(f"2.9 with ROUND_DOWN: {result}")
from decimal import ROUND_HALF_EVEN
getcontext().rounding = ROUND_HALF_EVEN # Reset to default
# Local context (temporary changes)
print("\nLocal context:")
print(f"Global precision: {getcontext().prec}")
with localcontext() as ctx:
ctx.prec = 5
result = Decimal('1') / Decimal('7')
print(f"Inside local context (prec=5): {result}")
result = Decimal('1') / Decimal('7')
print(f"Outside local context: {result}")
# Create custom context
print("\nCustom context:")
custom_ctx = Context(prec=15, rounding=ROUND_DOWN)
with localcontext(custom_ctx):
result = Decimal('1') / Decimal('3')
print(f"Custom context (prec=15, ROUND_DOWN): {result}")
# Traps (control exceptions)
print("\nTraps:")
print(f"Default traps: {getcontext().traps}")
# Disable division by zero trap
print("\nDivision by zero:")
with localcontext() as ctx:
ctx.traps[InvalidOperation] = False
try:
result = Decimal('1') / Decimal('0')
print(f"1/0 = {result}")
print(f"Is infinite: {result.is_infinite()}")
except:
print("Division by zero raised exception")
# Flags (track what happened)
print("\nFlags:")
getcontext().clear_flags()
result = Decimal('1e1000000')
print(f"Flags after overflow: {getcontext().flags}")
# Clamping
print("\nClamping:")
print(f"Clamp: {getcontext().clamp}")
# Copying context
print("\nCopying context:")
ctx1 = getcontext()
ctx2 = ctx1.copy()
ctx2.prec = 10
print(f"Original precision: {ctx1.prec}")
print(f"Copy precision: {ctx2.prec}")
# ExtendedContext (for special operations)
print("\nExtendedContext:")
from decimal import ExtendedContext
with localcontext(ExtendedContext):
print(f"Extended context precision: {getcontext().prec}")
# Practical examples
print("\n" + "="*50)
print("Practical examples:")
# Financial calculation with controlled precision
print("\nFinancial calculation:")
with localcontext() as ctx:
ctx.prec = 10
ctx.rounding = ROUND_HALF_UP
price = Decimal('19.99')
tax_rate = Decimal('0.08')
quantity = 3
subtotal = price * quantity
tax = (subtotal * tax_rate).quantize(Decimal('0.01'))
total = subtotal + tax
print(f"Price: ${price}")
print(f"Tax rate: {tax_rate * 100}%")
print(f"Quantity: {quantity}")
print(f"Subtotal: ${subtotal}")
print(f"Tax: ${tax}")
print(f"Total: ${total:.2f}")
# Scientific calculation with high precision
print("\nScientific calculation:")
with localcontext() as ctx:
ctx.prec = 100
# Calculate e using series
e = Decimal('1')
factorial = Decimal('1')
for i in range(1, 50):
factorial *= i
e += Decimal('1') / factorial
print(f"e (100 digits): {e}")
# Currency conversion with rounding
print("\nCurrency conversion:")
with localcontext() as ctx:
ctx.prec = 28
ctx.rounding = ROUND_HALF_UP
usd = Decimal('100.00')
rate = Decimal('0.85')
eur = (usd * rate).quantize(Decimal('0.01'))
print(f"${usd} USD = €{eur} EUR (rate: {rate})")
ctx ← Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
6# Get current context7print("Current context:")8ctx→ Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]) = getcontext()9print(f"Precision: {ctx.prec28}")10print(f"Rounding: {ctx.roundingROUND_HALF_EVEN}")11print(f"Emin: {ctx.Emin-999999}")12print(f"Emax: {ctx.Emax999999}")13print()1415# Set precision16print("Set precision:")17getcontext().prec = 1018result→ 0.3333333333 = Decimal('1') / Decimal('3')19print(f"1/3 with prec=10: {result0.3333333333}")2021getcontext().prec = 5022result→ 0.33333333333333333333333333333333333333333333333333 = Decimal('1') / Decimal('3')23print(f"1/3 with prec=50: {result0.33333333333333333333333333333333333333333333333333}")2425getcontext().prec = 28 # Reset to default2627# Set rounding mode28print("\nSet rounding mode:")29getcontext().rounding = ROUND_HALF_UPROUND_HALF_UP30result→ 3 = Decimal('2.5').quantize(Decimal('1'))31print(f"2.5 with ROUND_HALF_UP: {result3}")3233getcontext().rounding = ROUND_DOWNROUND_DOWN34result→ 2 = Decimal('2.9').quantize(Decimal('1'))35print(f"2.9 with ROUND_DOWN: {result2}")3637from decimal import ROUND_HALF_EVEN38getcontext().rounding = ROUND_HALF_EVENROUND_HALF_EVEN # Reset to default3940# Local context (temporary changes)41print("\nLocal context:")42print(f"Global precision: {getcontext().prec}")outputCurrent context: Precision: 28 Rounding: ROUND_HALF_EVEN Emin: -999999 Emax: 999999 Set precision: 1/3 with prec=10: 0.3333333333 1/3 with prec=50: 0.33333333333333333333333333333333333333333333333333 Set rounding mode: 2.5 with ROUND_HALF_UP: 3 2.9 with ROUND_DOWN: 2 Local context: Global precision: 28ctx.prec ← 5, result ← 0.14286
44with localcontext() as ctx:45 ctx.prec→ 5 = 546 result→ 0.14286 = Decimal('1') / Decimal('7')47 print(f"Inside local context (prec=5): {result0.14286}")outputInside local context (prec=5): 0.14286result ← 0.1428571428571428571428571429, custom_ctx ← Context(prec=15, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
49result→ 0.1428571428571428571428571429 = Decimal('1') / Decimal('7')50print(f"Outside local context: {result0.1428571428571428571428571429}")5152# Create custom context53print("\nCustom context:")54custom_ctx→ Context(prec=15, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]) = Context(prec=15, rounding=ROUND_DOWNROUND_DOWN)55with localcontext(custom_ctx):outputOutside local context: 0.1428571428571428571428571429 Custom context:result ← 0.333333333333333
54custom_ctx = Context(prec=15, rounding=ROUND_DOWN)55with localcontext(custom_ctxContext(prec=15, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])):56 result→ 0.333333333333333 = Decimal('1') / Decimal('3')57 print(f"Custom context (prec=15, ROUND_DOWN): {result0.333333333333333}")outputCustom context (prec=15, ROUND_DOWN): 0.333333333333333print(" Traps:")
59# Traps (control exceptions)60print("\nTraps:")61print(f"Default traps: {getcontext().traps}")6263# Disable division by zero trap64print("\nDivision by zero:")65with localcontext() as ctx:output Traps: Default traps: {<class 'decimal.InvalidOperation'>:True, <class 'decimal.FloatOperation'>:False, <class 'decimal.DivisionByZero'>:True, <class 'decimal.Overflow'>:True, <class 'decimal.Underflow'>:False, <class 'decimal.Subnormal'>:False, <class 'decimal.Inexact'>:False, <class 'decimal.Rounded'>:False, <class 'decimal.Clamped'>:False} Division by zero:ctx.traps[InvalidOperation] ← False
64print("\nDivision by zero:")65with localcontext() as ctx:66 ctx.traps[InvalidOperation]→ False = False67 try:except:
70 print(f"Is infinite: {result.is_infinite()}")71except:72 print("Division by zero raised exception")outputDivision by zero raised exception Division by zero raised exceptionresult ← 1E+1000000, ctx1 ← Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
74# Flags (track what happened)75print("\nFlags:")76getcontext().clear_flags()77result→ 1E+1000000 = Decimal('1e1000000')78print(f"Flags after overflow: {getcontext().flags}")7980# Clamping81print("\nClamping:")82print(f"Clamp: {getcontext().clamp}")8384# Copying context85print("\nCopying context:")86ctx1→ Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]) = getcontext()87ctx2→ Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]) = ctx1Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]).copy()88ctx2.prec→ 10 = 1089print(f"Original precision: {ctx1.prec28}")90print(f"Copy precision: {ctx2.prec10}")9192# ExtendedContext (for special operations)93print("\nExtendedContext:")94from decimal import ExtendedContextoutput Flags: Flags after overflow: {<class 'decimal.InvalidOperation'>:False, <class 'decimal.FloatOperation'>:False, <class 'decimal.DivisionByZero'>:False, <class 'decimal.Overflow'>:False, <class 'decimal.Underflow'>:False, <class 'decimal.Subnormal'>:False, <class 'decimal.Inexact'>:False, <class 'decimal.Rounded'>:False, <class 'decimal.Clamped'>:False} Clamping: Clamp: 0 Copying context: Original precision: 28 Copy precision: 10 ExtendedContext:with localcontext(ExtendedContext):
94from decimal import ExtendedContext95with localcontext(ExtendedContextContext(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])):96 print(f"Extended context precision: {getcontext().prec}")outputExtended context precision: 9print(" " + "="*50)
98# Practical examples99print("\n" + "="*50)100print("Practical examples:")101102# Financial calculation with controlled precision103print("\nFinancial calculation:")104with localcontext() as ctx:output ================================================== Practical examples: Financial calculation:ctx.prec ← 10, ctx.rounding ← ROUND_HALF_UP, price ← 19.99, tax_rate ← 0.08
103print("\nFinancial calculation:")104with localcontext() as ctx:105 ctx.prec→ 10 = 10106 ctx.rounding→ ROUND_HALF_UP = ROUND_HALF_UPROUND_HALF_UP107 108 price→ 19.99 = Decimal('19.99')109 tax_rate→ 0.08 = Decimal('0.08')110 quantity→ 3 = 3111 112 subtotal→ 59.97 = price19.99 * quantity3113 tax→ 4.80 = (subtotal59.97 * tax_rate0.08).quantize(Decimal('0.01'))114 total→ 64.77 = subtotal59.97 + tax4.80115 116 print(f"Price: ${price19.99}")117 print(f"Tax rate: {tax_rate0.08 * 100}%")118 print(f"Quantity: {quantity3}")119 print(f"Subtotal: ${subtotal59.97}")120 print(f"Tax: ${tax4.80}")121 print(f"Total: ${total64.77:.2f}")outputPrice: $19.99 Tax rate: 8.00% Quantity: 3 Subtotal: $59.97 Tax: $4.80 Total: $64.77print(" Scientific calculation:")
123# Scientific calculation with high precision124print("\nScientific calculation:")125with localcontext() as ctx:output Scientific calculation:ctx.prec ← 100, e ← 1, factorial ← 1
124print("\nScientific calculation:")125with localcontext() as ctx:126 ctx.prec→ 100 = 100127 128 # Calculate e using series129 e→ 1 = Decimal('1')130 factorial→ 1 = Decimal('1')131 for i in range(1, 50):e ← 2
pass 1 of 49130factorial = Decimal('1')131for i1 in range(1, 50):132 factorial1 *= i1133 e→ 2 += Decimal('1') / factorial149 passes — pass 1 is the card above pass iefactorial1 1 1 → 2 1 2 2 2 → 2.5 1 → 2 3 3 2.5 → 2.666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667 2 → 6 4 4 2.666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667 → 2.708333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334 6 → 24 5 5 2.708333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333334 → 2.716666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667 24 → 120 6 6 2.716666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666667 → 2.718055555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556 120 → 720 7 7 2.718055555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556 → 2.718253968253968253968253968253968253968253968253968253968253968253968253968253968253968253968253969 720 → 5040 8 8 2.718253968253968253968253968253968253968253968253968253968253968253968253968253968253968253968253969 → 2.718278769841269841269841269841269841269841269841269841269841269841269841269841269841269841269841271 5040 → 40320 9 9 2.718278769841269841269841269841269841269841269841269841269841269841269841269841269841269841269841271 → 2.718281525573192239858906525573192239858906525573192239858906525573192239858906525573192239858906527 40320 → 362880 ⋯ 38 more passes ⋯ 48 48 2.718281828459045235360287471352662497757247093699959574966967545491804388058265282261751423991371715 → 2.718281828459045235360287471352662497757247093699959574966967626046565095570637924536703462971667462 258623241511168180642964355153611979969197632389120000000000 → 12413915592536072670862289047373375038521486354677760000000000 49 49 2.718281828459045235360287471352662497757247093699959574966967626046565095570637924536703462971667462 → 2.718281828459045235360287471352662497757247093699959574966967627690539803887216958052518810705959212 12413915592536072670862289047373375038521486354677760000000000 → 608281864034267560872252163321295376887552831379210240000000000 print(f"e (100 digits): {e}")
135print(f"e (100 digits): {e2.718281828459045235360287471352662497757247093699959574966967627690539803887216958052518810705959212}")outpute (100 digits): 2.718281828459045235360287471352662497757247093699959574966967627690539803887216958052518810705959212print(" Currency conversion:")
137# Currency conversion with rounding138print("\nCurrency conversion:")139with localcontext() as ctx:output Currency conversion:ctx.prec ← 28, ctx.rounding ← ROUND_HALF_UP, usd ← 100.00, rate ← 0.85
138print("\nCurrency conversion:")139with localcontext() as ctx:140 ctx.prec→ 28 = 28141 ctx.rounding→ ROUND_HALF_UP = ROUND_HALF_UPROUND_HALF_UP142 143 usd→ 100.00 = Decimal('100.00')144 rate→ 0.85 = Decimal('0.85')145 eur→ 85.00 = (usd100.00 * rate0.85).quantize(Decimal('0.01'))146 147 print(f"${usd100.00} USD = €{eur85.00} EUR (rate: {rate0.85})")output$100.00 USD = €85.00 EUR (rate: 0.85)
getcontext()
The decimal context controls precision, rounding mode, and error handling for all Decimal operations in the current thread.
Rounding Methods
Different rounding modes for different needs:
rounding.py
Replay: real traced execution (multi-file project)
# Rounding modes
from decimal import Decimal, getcontext, ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_05UP
# Rounding modes
value = Decimal('2.5')
print(f"Value: {value}")
print()
# quantize for rounding
print("Rounding 2.5:")
print(f"ROUND_CEILING (up): {value.quantize(Decimal('1'), rounding=ROUND_CEILING)}")
print(f"ROUND_FLOOR (down): {value.quantize(Decimal('1'), rounding=ROUND_FLOOR)}")
print(f"ROUND_UP (away from 0): {value.quantize(Decimal('1'), rounding=ROUND_UP)}")
print(f"ROUND_DOWN (toward 0): {value.quantize(Decimal('1'), rounding=ROUND_DOWN)}")
print(f"ROUND_HALF_UP: {value.quantize(Decimal('1'), rounding=ROUND_HALF_UP)}")
print(f"ROUND_HALF_DOWN: {value.quantize(Decimal('1'), rounding=ROUND_HALF_DOWN)}")
print(f"ROUND_HALF_EVEN (banker's): {value.quantize(Decimal('1'), rounding=ROUND_HALF_EVEN)}")
# Different values
print("\nRounding different values:")
values = [Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')]
for val in values:
print(f"{val}: HALF_UP={val.quantize(Decimal('1'), rounding=ROUND_HALF_UP)}, "
f"HALF_EVEN={val.quantize(Decimal('1'), rounding=ROUND_HALF_EVEN)}")
# Round to decimal places
print("\nRound to decimal places:")
pi = Decimal('3.14159265358979323846')
print(f"Original: {pi}")
print(f"2 places: {pi.quantize(Decimal('0.01'))}")
print(f"4 places: {pi.quantize(Decimal('0.0001'))}")
print(f"6 places: {pi.quantize(Decimal('0.000001'))}")
# Round to significant figures using context
print("\nRound to significant figures:")
getcontext().prec = 3
large = Decimal('12345.6789')
rounded = +large # Unary plus applies rounding
print(f"12345.6789 to 3 sig figs: {rounded}")
getcontext().prec = 5
rounded = +large
print(f"12345.6789 to 5 sig figs: {rounded}")
getcontext().prec = 28 # Reset
# Context rounding mode
print("\nContext rounding mode:")
getcontext().rounding = ROUND_UP
result = Decimal('10') / Decimal('3')
print(f"10/3 with ROUND_UP: {result}")
getcontext().rounding = ROUND_DOWN
result = Decimal('10') / Decimal('3')
print(f"10/3 with ROUND_DOWN: {result}")
getcontext().rounding = ROUND_HALF_EVEN # Reset
# Financial rounding
print("\nFinancial rounding (2 decimals):")
prices = [Decimal('19.995'), Decimal('19.994'), Decimal('19.996')]
for price in prices:
rounded = price.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
print(f"${price} -> ${rounded}")
# Round to nearest 5 cents
print("\nRound to nearest 5 cents:")
amounts = [Decimal('1.23'), Decimal('1.27'), Decimal('1.28')]
nickel = Decimal('0.05')
for amount in amounts:
rounded = (amount / nickel).quantize(Decimal('1'), rounding=ROUND_HALF_UP) * nickel
print(f"${amount} -> ${rounded}")
# Truncate (no rounding)
print("\nTruncate decimals:")
value = Decimal('123.456789')
truncated = value.quantize(Decimal('0.01'), rounding=ROUND_DOWN)
print(f"{value} truncated to 2 places: {truncated}")
# Round to nearest hundred
print("\nRound to nearest hundred:")
amount = Decimal('12345')
hundred = Decimal('100')
rounded = (amount / hundred).quantize(Decimal('1'), rounding=ROUND_HALF_UP) * hundred
print(f"{amount} -> {rounded}")
# Custom rounding
def round_decimal(value, places, mode=ROUND_HALF_UP):
"""Round Decimal to specified places."""
if places < 0:
# Round to tens, hundreds, etc.
factor = Decimal(10) ** abs(places)
return (value / factor).quantize(Decimal('1'), rounding=mode) * factor
else:
quantizer = Decimal(10) ** -places
return value.quantize(quantizer, rounding=mode)
print("\nCustom rounding function:")
val = Decimal('12345.6789')
print(f"Original: {val}")
print(f"2 places: {round_decimal(val, 2)}")
print(f"0 places: {round_decimal(val, 0)}")
print(f"-2 places (hundreds): {round_decimal(val, -2)}")
value ← 2.5, values ← [Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')]
5# Rounding modes6value→ 2.5 = Decimal('2.5')78print(f"Value: {value2.5}")9print()1011# quantize for rounding12print("Rounding 2.5:")13print(f"ROUND_CEILING (up): {value2.5.quantize(Decimal('1'), rounding=ROUND_CEILINGROUND_CEILING)}")14print(f"ROUND_FLOOR (down): {value2.5.quantize(Decimal('1'), rounding=ROUND_FLOORROUND_FLOOR)}")15print(f"ROUND_UP (away from 0): {value2.5.quantize(Decimal('1'), rounding=ROUND_UPROUND_UP)}")16print(f"ROUND_DOWN (toward 0): {value2.5.quantize(Decimal('1'), rounding=ROUND_DOWNROUND_DOWN)}")17print(f"ROUND_HALF_UP: {value2.5.quantize(Decimal('1'), rounding=ROUND_HALF_UPROUND_HALF_UP)}")18print(f"ROUND_HALF_DOWN: {value2.5.quantize(Decimal('1'), rounding=ROUND_HALF_DOWNROUND_HALF_DOWN)}")19print(f"ROUND_HALF_EVEN (banker's): {value2.5.quantize(Decimal('1'), rounding=ROUND_HALF_EVENROUND_HALF_EVEN)}")2021# Different values22print("\nRounding different values:")23values→ [Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')] = [Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')]24for val in values:outputValue: 2.5 Rounding 2.5: ROUND_CEILING (up): 3 ROUND_FLOOR (down): 2 ROUND_UP (away from 0): 3 ROUND_DOWN (toward 0): 2 ROUND_HALF_UP: 3 ROUND_HALF_DOWN: 2 ROUND_HALF_EVEN (banker's): 2 Rounding different values:for val in values:
pass 1 of 423values = [Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')]24for val2.4 in values[Decimal('2.4'), Decimal('2.5'), Decimal('2.6'), Decimal('-2.5')]:25 print(f"{val2.4}: HALF_UP={val.quantize(Decimal('1'), rounding=ROUND_HALF_UPROUND_HALF_UP)}, "26 f"HALF_EVEN={val2.4.quantize(Decimal('1'), rounding=ROUND_HALF_EVENROUND_HALF_EVEN)}")output2.4: HALF_UP=2, HALF_EVEN=2All 4 passes — pass 1 is the card above pass val1 2.4 2 2.5 3 2.6 4 -2.5 pi ← 3.14159265358979323846, large ← 12345.6789, rounded ← 1.23E+4
28# Round to decimal places29print("\nRound to decimal places:")30pi→ 3.14159265358979323846 = Decimal('3.14159265358979323846')31print(f"Original: {pi3.14159265358979323846}")32print(f"2 places: {pi3.14159265358979323846.quantize(Decimal('0.01'))}")33print(f"4 places: {pi3.14159265358979323846.quantize(Decimal('0.0001'))}")34print(f"6 places: {pi3.14159265358979323846.quantize(Decimal('0.000001'))}")3536# Round to significant figures using context37print("\nRound to significant figures:")38getcontext().prec = 339large→ 12345.6789 = Decimal('12345.6789')40rounded→ 1.23E+4 = +large12345.6789 # Unary plus applies rounding41print(f"12345.6789 to 3 sig figs: {rounded1.23E+4}")4243getcontext().prec = 544rounded→ 12346 = +large12345.678945print(f"12345.6789 to 5 sig figs: {rounded12346}")4647getcontext().prec = 28 # Reset4849# Context rounding mode50print("\nContext rounding mode:")51getcontext().rounding = ROUND_UPROUND_UP52result→ 3.333333333333333333333333334 = Decimal('10') / Decimal('3')53print(f"10/3 with ROUND_UP: {result3.333333333333333333333333334}")5455getcontext().rounding = ROUND_DOWNROUND_DOWN56result→ 3.333333333333333333333333333 = Decimal('10') / Decimal('3')57print(f"10/3 with ROUND_DOWN: {result3.333333333333333333333333333}")5859getcontext().rounding = ROUND_HALF_EVENROUND_HALF_EVEN # Reset6061# Financial rounding62print("\nFinancial rounding (2 decimals):")63prices→ [Decimal('19.995'), Decimal('19.994'), Decimal('19.996')] = [Decimal('19.995'), Decimal('19.994'), Decimal('19.996')]64for price in prices:output Round to decimal places: Original: 3.14159265358979323846 2 places: 3.14 4 places: 3.1416 6 places: 3.141593 Round to significant figures: 12345.6789 to 3 sig figs: 1.23E+4 12345.6789 to 5 sig figs: 12346 Context rounding mode: 10/3 with ROUND_UP: 3.333333333333333333333333334 10/3 with ROUND_DOWN: 3.333333333333333333333333333 Financial rounding (2 decimals):rounded ← 20.00
pass 1 of 363prices = [Decimal('19.995'), Decimal('19.994'), Decimal('19.996')]64for price19.995 in prices[Decimal('19.995'), Decimal('19.994'), Decimal('19.996')]:65 rounded→ 20.00 = price19.995.quantize(Decimal('0.01'), rounding=ROUND_HALF_UPROUND_HALF_UP)66 print(f"${price19.995} -> ${rounded20.00}")output$19.995 -> $20.00All 3 passes — pass 1 is the card above pass pricerounded1 19.995 20.00 2 19.994 19.99 3 19.996 20.00 amounts ← [Decimal('1.23'), Decimal('1.27'), Decimal('1.28')]
68# Round to nearest 5 cents69print("\nRound to nearest 5 cents:")70amounts→ [Decimal('1.23'), Decimal('1.27'), Decimal('1.28')] = [Decimal('1.23'), Decimal('1.27'), Decimal('1.28')]71nickel→ 0.05 = Decimal('0.05')72for amount in amounts:output Round to nearest 5 cents:rounded ← 1.25
pass 1 of 371nickel = Decimal('0.05')72for amount1.23 in amounts[Decimal('1.23'), Decimal('1.27'), Decimal('1.28')]:73 rounded→ 1.25 = (amount1.23 / nickel0.05).quantize(Decimal('1'), rounding=ROUND_HALF_UPROUND_HALF_UP) * nickel74 print(f"${amount1.23} -> ${rounded1.25}")output$1.23 -> $1.25All 3 passes — pass 1 is the card above pass amountrounded1 1.23 1.25 2 1.27 1.25 3 1.28 1.30 value ← 123.456789, truncated ← 123.45, amount ← 12345, hundred ← 100
76# Truncate (no rounding)77print("\nTruncate decimals:")78value→ 123.456789 = Decimal('123.456789')79truncated→ 123.45 = value123.456789.quantize(Decimal('0.01'), rounding=ROUND_DOWNROUND_DOWN)80print(f"{value123.456789} truncated to 2 places: {truncated123.45}")8182# Round to nearest hundred83print("\nRound to nearest hundred:")84amount→ 12345 = Decimal('12345')85hundred→ 100 = Decimal('100')86rounded→ 12300 = (amount12345 / hundred100).quantize(Decimal('1'), rounding=ROUND_HALF_UPROUND_HALF_UP) * hundred87print(f"{amount12345} -> {rounded12300}")8889# Custom rounding90def round_decimal(value, places, mode=ROUND_HALF_UP):91 """Round Decimal to specified places."""92 if places < 0:93 # Round to tens, hundreds, etc.94 factor = Decimal(10) ** abs(places)95 return (value / factor).quantize(Decimal('1'), rounding=mode) * factor96 else:97 quantizer = Decimal(10) ** -places98 return value.quantize(quantizer, rounding=mode)99100print("\nCustom rounding function:")101val→ 12345.6789 = Decimal('12345.6789')102print(f"Original: {val12345.6789}")103print(f"2 places: {round_decimal(val12345.6789, 2)}")104print(f"0 places: {round_decimal(val, 0)}")output Truncate decimals: 123.456789 truncated to 2 places: 123.45 Round to nearest hundred: 12345 -> 12300 Custom rounding function: Original: 12345.6789def round_decimal(value, places, mode=ROUND_HALF_UP):
pass 1 of 389# Custom rounding90def round_decimal(value12345.6789, places2, modeROUND_HALF_UP=ROUND_HALF_UPROUND_HALF_UP):91 """Round Decimal to specified places."""92 if places < 0:All 3 passes — pass 1 is the card above pass placesquantizerfactor1 2 0.01 — 2 0 1 — 3 -2 — 100 quantizer ← 0.01
pass 1 of 294 factor = Decimal(10) ** abs(places)95 return (value / factor).quantize(Decimal('1'), rounding=mode) * factor96else:97 quantizer→ 0.01 = Decimal(10) ** -places298 return value12345.6789.quantize(quantizer0.01, rounding=modeROUND_HALF_UP)print(f"2 places: {round_decimal(val, 2)}")
102print(f"Original: {val}")103print(f"2 places: {round_decimal(val12345.6789, 2)}")104print(f"0 places: {round_decimal(val12345.6789, 0)}")105print(f"-2 places (hundreds): {round_decimal(val, -2)}")output2 places: 12345.68quantizer ← 1
pass 2 of 294 factor = Decimal(10) ** abs(places)95 return (value / factor).quantize(Decimal('1'), rounding=mode) * factor96else:97 quantizer→ 1 = Decimal(10) ** -places098 return value12345.6789.quantize(quantizer1, rounding=modeROUND_HALF_UP)print(f"0 places: {round_decimal(val, 0)}")
103print(f"2 places: {round_decimal(val, 2)}")104print(f"0 places: {round_decimal(val12345.6789, 0)}")105print(f"-2 places (hundreds): {round_decimal(val12345.6789, -2)}")output0 places: 12346factor ← 100
91"""Round Decimal to specified places."""92if places-2 < 0:93 # Round to tens, hundreds, etc.94 factor→ 100 = Decimal(10) ** abs(places-2)95 return (value12345.6789 / factor100).quantize(Decimal('1'), rounding=modeROUND_HALF_UP) * factor96else:print(f"-2 places (hundreds): {round_decimal(val, -2)}")
104print(f"0 places: {round_decimal(val, 0)}")105print(f"-2 places (hundreds): {round_decimal(val12345.6789, -2)}")output-2 places (hundreds): 12300
Comparison Operations
Comparing Decimal values:
comparison.py
Replay: real traced execution (multi-file project)
# Comparison operations
from decimal import Decimal
# Comparison
a = Decimal('10.5')
b = Decimal('20.3')
c = Decimal('10.5')
print(f"a = {a}")
print(f"b = {b}")
print(f"c = {c}")
print()
# Equality
print("Equality:")
print(f"a == b: {a == b}")
print(f"a == c: {a == c}")
print(f"a != b: {a != b}")
# Ordering
print("\nOrdering:")
print(f"a < b: {a < b}")
print(f"a <= b: {a <= b}")
print(f"a > b: {a > b}")
print(f"a >= b: {a >= b}")
# compare method
print("\ncompare method:")
print(f"a.compare(b): {a.compare(b)}") # -1, 0, or 1
print(f"b.compare(a): {b.compare(a)}")
print(f"a.compare(c): {a.compare(c)}")
# compare_signal (raises on NaN)
print("\ncompare_signal:")
print(f"a.compare_signal(b): {a.compare_signal(b)}")
# max and min
print("\nmax and min:")
print(f"max(a, b): {max(a, b)}")
print(f"min(a, b): {min(a, b)}")
# Decimal max/min methods
print("\nDecimal max/min methods:")
print(f"a.max(b): {a.max(b)}")
print(f"a.min(b): {a.min(b)}")
# Find max/min in list
print("\nFind max/min in list:")
numbers = [Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')]
print(f"Numbers: {numbers}")
print(f"Max: {max(numbers)}")
print(f"Min: {min(numbers)}")
# Sort
print("\nSort:")
sorted_nums = sorted(numbers)
print(f"Sorted: {sorted_nums}")
# Check if in range
print("\nCheck if in range:")
value = Decimal('15.5')
lower = Decimal('10')
upper = Decimal('20')
in_range = lower <= value <= upper
print(f"{value} in [{lower}, {upper}]: {in_range}")
# Zero checks
print("\nZero checks:")
zero = Decimal('0')
pos = Decimal('5')
neg = Decimal('-5')
print(f"{zero} == 0: {zero == 0}")
print(f"{pos} > 0: {pos > 0}")
print(f"{neg} < 0: {neg < 0}")
# is_zero method
print("\nis_zero method:")
print(f"{zero}.is_zero(): {zero.is_zero()}")
print(f"{pos}.is_zero(): {pos.is_zero()}")
# Sign checks
print("\nSign checks:")
print(f"{pos}.is_signed(): {pos.is_signed()}")
print(f"{neg}.is_signed(): {neg.is_signed()}")
print(f"{zero}.is_signed(): {zero.is_signed()}")
# is_finite, is_infinite, is_nan
print("\nSpecial value checks:")
finite = Decimal('42.5')
infinity = Decimal('Infinity')
nan = Decimal('NaN')
print(f"{finite}.is_finite(): {finite.is_finite()}")
print(f"{infinity}.is_infinite(): {infinity.is_infinite()}")
print(f"{nan}.is_nan(): {nan.is_nan()}")
# is_normal, is_subnormal
print("\nis_normal:")
normal = Decimal('1.5')
tiny = Decimal('1e-1000')
print(f"{normal}.is_normal(): {normal.is_normal()}")
print(f"{tiny}.is_normal(): {tiny.is_normal()}")
# compare_total (considers exponent)
print("\ncompare_total (considers exponent):")
d1 = Decimal('1.0')
d2 = Decimal('1.00')
print(f"d1 = {d1}, d2 = {d2}")
print(f"d1 == d2: {d1 == d2}") # True (value equal)
print(f"d1.compare_total(d2): {d1.compare_total(d2)}") # -1 (exponents differ)
# Tolerance comparison (for floats converted to Decimal)
print("\nTolerance comparison:")
def approx_equal(a, b, tolerance=Decimal('0.0001')):
"""Check if two Decimals are approximately equal."""
return abs(a - b) <= tolerance
val1 = Decimal('3.14159')
val2 = Decimal('3.14160')
print(f"approx_equal({val1}, {val2}): {approx_equal(val1, val2)}")
print(f"approx_equal({val1}, {val2}, 0.00001): {approx_equal(val1, val2, Decimal('0.00001'))}")
a ← 10.5, b ← 20.3, c ← 10.5, numbers ← [Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')]
5# Comparison6a→ 10.5 = Decimal('10.5')7b→ 20.3 = Decimal('20.3')8c→ 10.5 = Decimal('10.5')910print(f"a = {a10.5}")11print(f"b = {b20.3}")12print(f"c = {c10.5}")13print()1415# Equality16print("Equality:")17print(f"a == b: {a10.5 == b20.3}")18print(f"a == c: {a10.5 == c10.5}")19print(f"a != b: {a10.5 != b20.3}")2021# Ordering22print("\nOrdering:")23print(f"a < b: {a10.5 < b20.3}")24print(f"a <= b: {a10.5 <= b20.3}")25print(f"a > b: {a10.5 > b20.3}")26print(f"a >= b: {a10.5 >= b20.3}")2728# compare method29print("\ncompare method:")30print(f"a.compare(b): {a10.5.compare(b20.3)}") # -1, 0, or 131print(f"b.compare(a): {b20.3.compare(a10.5)}")32print(f"a.compare(c): {a10.5.compare(c10.5)}")3334# compare_signal (raises on NaN)35print("\ncompare_signal:")36print(f"a.compare_signal(b): {a10.5.compare_signal(b20.3)}")3738# max and min39print("\nmax and min:")40print(f"max(a, b): {max(a10.5, b20.3)}")41print(f"min(a, b): {min(a10.5, b20.3)}")4243# Decimal max/min methods44print("\nDecimal max/min methods:")45print(f"a.max(b): {a10.5.max(b20.3)}")46print(f"a.min(b): {a10.5.min(b20.3)}")4748# Find max/min in list49print("\nFind max/min in list:")50numbers→ [Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')] = [Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')]51print(f"Numbers: {numbers[Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')]}")52print(f"Max: {max(numbers[Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')])}")53print(f"Min: {min(numbers[Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')])}")5455# Sort56print("\nSort:")57sorted_nums→ [Decimal('12.5'), Decimal('23.7'), Decimal('45.2'), Decimal('89.1')] = sorted(numbers[Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')])58print(f"Sorted: {sorted_nums[Decimal('12.5'), Decimal('23.7'), Decimal('45.2'), Decimal('89.1')]}")5960# Check if in range61print("\nCheck if in range:")62value→ 15.5 = Decimal('15.5')63lower→ 10 = Decimal('10')64upper→ 20 = Decimal('20')65in_range→ True = lower10 <= value15.5 <= upper2066print(f"{value15.5} in [{lower10}, {upper20}]: {in_rangeTrue}")6768# Zero checks69print("\nZero checks:")70zero→ 0 = Decimal('0')71pos→ 5 = Decimal('5')72neg→ -5 = Decimal('-5')7374print(f"{zero0} == 0: {zero == 0}")75print(f"{pos5} > 0: {pos > 0}")76print(f"{neg-5} < 0: {neg < 0}")7778# is_zero method79print("\nis_zero method:")80print(f"{zero0}.is_zero(): {zero.is_zero()}")81print(f"{pos5}.is_zero(): {pos.is_zero()}")8283# Sign checks84print("\nSign checks:")85print(f"{pos5}.is_signed(): {pos.is_signed()}")86print(f"{neg-5}.is_signed(): {neg.is_signed()}")87print(f"{zero0}.is_signed(): {zero.is_signed()}")8889# is_finite, is_infinite, is_nan90print("\nSpecial value checks:")91finite→ 42.5 = Decimal('42.5')92infinity→ Infinity = Decimal('Infinity')93nan→ NaN = Decimal('NaN')9495print(f"{finite42.5}.is_finite(): {finite.is_finite()}")96print(f"{infinityInfinity}.is_infinite(): {infinity.is_infinite()}")97print(f"{nanNaN}.is_nan(): {nan.is_nan()}")9899# is_normal, is_subnormal100print("\nis_normal:")101normal→ 1.5 = Decimal('1.5')102tiny→ 1E-1000 = Decimal('1e-1000')103print(f"{normal1.5}.is_normal(): {normal.is_normal()}")104print(f"{tiny1E-1000}.is_normal(): {tiny.is_normal()}")105106# compare_total (considers exponent)107print("\ncompare_total (considers exponent):")108d1→ 1.0 = Decimal('1.0')109d2→ 1.00 = Decimal('1.00')110print(f"d1 = {d11.0}, d2 = {d21.00}")111print(f"d1 == d2: {d11.0 == d21.00}") # True (value equal)112print(f"d1.compare_total(d2): {d11.0.compare_total(d21.00)}") # -1 (exponents differ)113114# Tolerance comparison (for floats converted to Decimal)115print("\nTolerance comparison:")116def approx_equal(a, b, tolerance=Decimal('0.0001')):117 """Check if two Decimals are approximately equal."""118 return abs(a - b) <= tolerance119120val1→ 3.14159 = Decimal('3.14159')121val2→ 3.14160 = Decimal('3.14160')122print(f"approx_equal({val13.14159}, {val23.14160}): {approx_equal(val1, val2)}")123print(f"approx_equal({val1}, {val2}, 0.00001): {approx_equal(val1, val2, Decimal('0.00001'))}")outputa = 10.5 b = 20.3 c = 10.5 Equality: a == b: False a == c: True a != b: True Ordering: a < b: True a <= b: True a > b: False a >= b: False compare method: a.compare(b): -1 b.compare(a): 1 a.compare(c): 0 compare_signal: a.compare_signal(b): -1 max and min: max(a, b): 20.3 min(a, b): 10.5 Decimal max/min methods: a.max(b): 20.3 a.min(b): 10.5 Find max/min in list: Numbers: [Decimal('12.5'), Decimal('45.2'), Decimal('23.7'), Decimal('89.1')] Max: 89.1 Min: 12.5 Sort: Sorted: [Decimal('12.5'), Decimal('23.7'), Decimal('45.2'), Decimal('89.1')] Check if in range: 15.5 in [10, 20]: True Zero checks: 0 == 0: True 5 > 0: True -5 < 0: True is_zero method: 0.is_zero(): True 5.is_zero(): False Sign checks: 5.is_signed(): False -5.is_signed(): True 0.is_signed(): False Special value checks: 42.5.is_finite(): True Infinity.is_infinite(): True NaN.is_nan(): True is_normal: 1.5.is_normal(): True 1E-1000.is_normal(): True compare_total (considers exponent): d1 = 1.0, d2 = 1.00 d1 == d2: True d1.compare_total(d2): 1 Tolerance comparison:def approx_equal(a, b, tolerance=Decimal('0.0001')):
pass 1 of 2115print("\nTolerance comparison:")116def approx_equal(a3.14159, b3.14160, tolerance0.0001=Decimal('0.0001')):117 """Check if two Decimals are approximately equal."""118 return abs(a3.14159 - b3.14160) <= tolerance0.0001print(f"approx_equal({val1}, {val2}): {approx_equal(val1, val2)}")
121val2 = Decimal('3.14160')122print(f"approx_equal({val13.14159}, {val23.14160}): {approx_equal(val1, val2)}")123print(f"approx_equal({val13.14159}, {val23.14160}, 0.00001): {approx_equal(val1, val2, Decimal('0.00001'))}")outputapprox_equal(3.14159, 3.14160): Truedef approx_equal(a, b, tolerance=Decimal('0.0001')):
pass 2 of 2115print("\nTolerance comparison:")116def approx_equal(a3.14159, b3.14160, tolerance0.00001=Decimal('0.0001')):117 """Check if two Decimals are approximately equal."""118 return abs(a3.14159 - b3.14160) <= tolerance0.00001print(f"approx_equal({val1}, {val2}, 0.00001): {approx_equal(val1, val…
122print(f"approx_equal({val1}, {val2}): {approx_equal(val1, val2)}")123print(f"approx_equal({val13.14159}, {val23.14160}, 0.00001): {approx_equal(val1, val2, Decimal('0.00001'))}")outputapprox_equal(3.14159, 3.14160, 0.00001): True
Exercise: practical.py
Calculate compound interest and format currency values with proper rounding