Money & Precision¶
The Money class is the foundation of MoneyWarp, providing high-precision financial calculations while maintaining intuitive 2-decimal display for "real money" amounts.
Why Precision Matters¶
Financial calculations require precision. Floating-point arithmetic can introduce errors:
# The classic floating-point problem
print(0.1 + 0.2) # 0.30000000000000004 😱
# With MoneyWarp
from money_warp import Money
money1 = Money("0.1")
money2 = Money("0.2")
result = money1 + money2
print(result) # 0.30 ✅
Creating Money Objects¶
Multiple ways to create Money objects:
from money_warp import Money
from decimal import Decimal
# From strings (recommended for precision)
price = Money("99.99")
salary = Money("75000.00")
# From integers
count = Money(100) # $100.00
# From Decimal (maintains precision)
precise = Money(Decimal("123.456789"))
# From floats (converted to string internally)
approx = Money(99.99) # Converted to avoid float precision issues
print(f"Price: {price}")
print(f"Salary: {salary}")
print(f"Count: {count}")
print(f"Precise: {precise}")
print(f"Approx: {approx}")
Output:
Precision vs Display¶
MoneyWarp maintains full precision internally but displays 2 decimals:
# High precision calculation
money = Money("100.123456789")
print(f"Internal (raw): {money.raw_amount}") # Full precision
print(f"Display (real): {money.real_amount}") # 2 decimals
print(f"String: {money}") # 2 decimals
Output:
Arithmetic Operations¶
All arithmetic maintains precision internally:
base = Money("100.00")
# Basic operations
addition = base + Money("25.50")
subtraction = base - Money("15.75")
multiplication = base * 1.08 # 8% increase
division = base / 4
print(f"Addition: {addition}")
print(f"Subtraction: {subtraction}")
print(f"Multiplication: {multiplication}")
print(f"Division: {division}")
# Complex calculations
compound = Money("1000.00") * (1.05 ** 10) # 5% for 10 years
print(f"Compound growth: {compound}")
# Chain operations
result = Money("500.00") * 1.08 / 12 * 365.25 / 100
print(f"Complex chain: {result}")
print(f"Internal precision: {result.raw_amount}")
Output:
Addition: 125.50
Subtraction: 84.25
Multiplication: 108.00
Division: 25.00
Compound growth: 1,628.89
Complex chain: 164.25
Internal precision: 164.2500000000000000000000000
Comparison Operations¶
Comparisons use the 2-decimal "real money" representation. You can compare Money against another Money or directly against a Decimal:
from decimal import Decimal
money1 = Money("100.001") # Rounds to 100.00
money2 = Money("100.009") # Rounds to 100.01
print(f"Money1: {money1}") # 100.00
print(f"Money2: {money2}") # 100.01
# Money vs Money
print(f"Equal? {money1 == money2}") # False
print(f"Money1 < Money2? {money1 < money2}") # True
print(f"Money1 <= 100.00? {money1 <= Money('100.00')}") # True
# Money vs Decimal -- no need to extract .real_amount
print(f"Equals Decimal? {money1 == Decimal('100.00')}") # True
print(f"Greater than? {money2 > Decimal('100.00')}") # True
Working with Cents¶
Avoid decimal issues by working with cents:
# Create from cents
price_in_cents = Money.from_cents(9999) # $99.99
print(f"From cents: {price_in_cents}")
# Get cents value
money = Money("123.45")
cents = money.cents
print(f"As cents: {cents}") # 12345
# Useful for APIs that work in cents
api_amount = Money.from_cents(2500) # $25.00 from API
print(f"API amount: {api_amount}")
Zero and Utility Methods¶
Convenient methods for common operations:
# Zero money
zero = Money.zero()
print(f"Zero: {zero}")
# Check if zero
balance = Money("0.00")
print(f"Is zero? {balance.is_zero()}")
# Check sign
positive = Money("100.00")
negative = Money("-50.00")
print(f"Positive? {positive.is_positive()}")
print(f"Negative? {negative.is_negative()}")
# Absolute value
debt = Money("-1500.00")
print(f"Debt: {debt}")
print(f"Absolute: {abs(debt)}")
Output:
Real-World Example: Tax Calculations¶
def calculate_tax_breakdown(gross_salary, tax_rate, deductions):
"""Calculate detailed tax breakdown with high precision."""
gross = Money(gross_salary)
rate = tax_rate
deduct = Money(deductions)
# Calculate taxable income
taxable = gross - deduct
# Calculate taxes (maintains precision)
federal_tax = taxable * rate
state_tax = taxable * 0.05 # 5% state tax
total_tax = federal_tax + state_tax
# Net income
net_income = gross - total_tax
return {
'gross': gross,
'deductions': deduct,
'taxable': taxable,
'federal_tax': federal_tax,
'state_tax': state_tax,
'total_tax': total_tax,
'net_income': net_income,
'effective_rate': (total_tax / gross) * 100
}
# Calculate for $75,000 salary
breakdown = calculate_tax_breakdown("75000.00", 0.22, "12550.00")
print("Tax Breakdown:")
print(f"Gross Salary: {breakdown['gross']}")
print(f"Standard Deduction: {breakdown['deductions']}")
print(f"Taxable Income: {breakdown['taxable']}")
print(f"Federal Tax (22%): {breakdown['federal_tax']}")
print(f"State Tax (5%): {breakdown['state_tax']}")
print(f"Total Tax: {breakdown['total_tax']}")
print(f"Net Income: {breakdown['net_income']}")
print(f"Effective Rate: {breakdown['effective_rate']:.2f}%")
Output:
Tax Breakdown:
Gross Salary: 75,000.00
Standard Deduction: 12,550.00
Taxable Income: 62,450.00
Federal Tax (22%): 13,739.00
State Tax (5%): 3,122.50
Total Tax: 16,861.50
Net Income: 58,138.50
Effective Rate: 22.48%
Performance Considerations¶
While Money uses Decimal for precision, it's optimized for financial calculations:
import time
from money_warp import Money
# Benchmark Money operations
start = time.time()
total = Money.zero()
for i in range(10000):
total += Money("1.23")
end = time.time()
print(f"10,000 additions: {end - start:.4f} seconds")
print(f"Final total: {total}")
# Memory efficiency
money = Money("123456789.123456789")
print(f"Memory efficient: {money}") # Only stores one Decimal
Best Practices¶
- Use strings for input:
Money("99.99")notMoney(99.99) - Leverage precision: Internal calculations maintain full precision
- Display consistency: All output shows 2 decimals automatically
- Comparison safety: Comparisons use "real money" (2 decimal) values -- works with both
MoneyandDecimal - Zero handling: Use
Money.zero()and.is_zero()for clarity
Common Patterns¶
# Running totals
total = Money.zero()
transactions = [Money("100.00"), Money("-25.50"), Money("75.25")]
for transaction in transactions:
total += transaction
print(f"Final balance: {total}")
# Percentage calculations
principal = Money("10000.00")
interest_rate = 0.05
interest = principal * interest_rate
print(f"Interest: {interest}")
# Splitting amounts
bill = Money("127.50")
people = 3
per_person = bill / people
print(f"Per person: {per_person}")
# Rounding behavior (automatic)
precise_calc = Money("100.00") / 3 * 3
print(f"Rounded result: {precise_calc}") # Shows 100.00
print(f"Internal: {precise_calc.raw_amount}") # Shows full precision
The Money class ensures your financial calculations are both precise and intuitive! 💰