Recipe Collection
This cookbook contains ready-to-use code patterns for common financial and decimal arithmetic scenarios. Each recipe is complete and can be adapted to your needs.
Recipe: Invoice Calculator
Calculate invoice totals with line items, discounts, and tax.
class
INVOICE_CALCULATOR
feature -- Access
subtotal: SIMPLE_DECIMAL
-- Running subtotal
attribute
create Result.make_zero
end
feature -- Operations
add_line_item (unit_price_str: STRING; quantity: INTEGER)
-- Add a line item to the invoice
local
unit_price, qty, line_total: SIMPLE_DECIMAL
do
create unit_price.make (unit_price_str)
create qty.make_from_integer (quantity)
line_total := unit_price * qty
subtotal := subtotal + line_total
end
apply_discount (percent_str: STRING)
-- Apply percentage discount to subtotal
local
discount_rate: SIMPLE_DECIMAL
do
create discount_rate.make (percent_str)
subtotal := subtotal.subtract_percent (discount_rate)
end
calculate_total (tax_rate_str: STRING): STRING
-- Calculate final total with tax, return formatted
local
tax_rate, tax, total: SIMPLE_DECIMAL
do
create tax_rate.make (tax_rate_str)
tax := (subtotal * tax_rate.from_percentage).round_cents
total := subtotal + tax
Result := total.to_currency_string
end
end
-- Usage:
local
calc: INVOICE_CALCULATOR
do
create calc
calc.add_line_item ("29.99", 3) -- 3 items @ $29.99
calc.add_line_item ("149.95", 1) -- 1 item @ $149.95
calc.apply_discount ("10") -- 10% off
print (calc.calculate_total ("8.25")) -- Add 8.25% tax
-- Output: "$227.84"
end
Recipe: Restaurant Tip Calculator
Calculate tip and split the bill among multiple people.
class
TIP_CALCULATOR
feature -- Calculation
calculate_split (bill_str: STRING; tip_percent_str: STRING;
num_people: INTEGER): TUPLE [
tip: STRING;
total: STRING;
per_person: ARRAYED_LIST [STRING]]
-- Calculate tip, total, and split per person
local
bill, tip_rate, tip, total: SIMPLE_DECIMAL
splits: ARRAYED_LIST [SIMPLE_DECIMAL]
amounts: ARRAYED_LIST [STRING]
do
create bill.make (bill_str)
create tip_rate.make (tip_percent_str)
-- Calculate tip and total
tip := (bill * tip_rate.from_percentage).round_cents
total := bill + tip
-- Split among people
splits := total.split (num_people)
-- Convert to strings
create amounts.make (num_people)
across splits as s loop
amounts.extend (s.to_currency_string)
end
Result := [tip.to_currency_string, total.to_currency_string, amounts]
end
end
-- Usage:
local
calc: TIP_CALCULATOR
result: TUPLE [tip, total: STRING; per_person: ARRAYED_LIST [STRING]]
do
create calc
result := calc.calculate_split ("127.50", "20", 4)
print ("Tip: " + result.tip) -- Tip: $25.50
print ("Total: " + result.total) -- Total: $153.00
print ("Per person: ") -- Per person:
across result.per_person as p loop
print (p) -- $38.25 each (4 people)
end
end
Recipe: Compound Interest Calculator
Calculate compound interest with monthly compounding.
class
INTEREST_CALCULATOR
feature -- Calculation
compound_interest (principal_str: STRING;
annual_rate_str: STRING;
years: INTEGER): STRING
-- Calculate compound interest (monthly compounding)
-- Formula: A = P(1 + r/n)^(nt)
-- P = principal, r = rate, n = 12 (monthly), t = years
local
principal, rate, monthly_rate: SIMPLE_DECIMAL
base, factor, final_amount: SIMPLE_DECIMAL
one, twelve: SIMPLE_DECIMAL
total_periods: INTEGER
i: INTEGER
do
create principal.make (principal_str)
create rate.make (annual_rate_str)
create one.make_one
create twelve.make_from_integer (12)
-- Monthly rate = annual rate / 12
monthly_rate := rate.from_percentage / twelve
-- Base = 1 + monthly_rate
base := one + monthly_rate
-- Calculate (1 + r/n)^(nt) iteratively
total_periods := years * 12
create factor.make_one
from i := 1 until i > total_periods loop
factor := factor * base
i := i + 1
end
-- Final = principal * factor
final_amount := (principal * factor).round_cents
Result := final_amount.to_currency_string
end
interest_earned (principal_str, annual_rate_str: STRING;
years: INTEGER): STRING
-- Calculate just the interest portion
local
principal, final_amount, interest: SIMPLE_DECIMAL
do
create principal.make (principal_str)
create final_amount.make (compound_interest (principal_str,
annual_rate_str, years))
interest := final_amount - principal
Result := interest.to_currency_string
end
end
-- Usage: $10,000 at 5% for 10 years
local
calc: INTEREST_CALCULATOR
do
create calc
print (calc.compound_interest ("10000", "5", 10))
-- Output: "$16,470.09"
print (calc.interest_earned ("10000", "5", 10))
-- Output: "$6,470.09"
end
Recipe: Currency Converter
Convert between currencies with precise exchange rates.
class
CURRENCY_CONVERTER
feature -- Access
rates: HASH_TABLE [SIMPLE_DECIMAL, STRING]
-- Exchange rates relative to USD
attribute
create Result.make (10)
end
feature -- Setup
set_rate (currency: STRING; rate_str: STRING)
-- Set exchange rate (how many of currency = 1 USD)
local
rate: SIMPLE_DECIMAL
do
create rate.make (rate_str)
rates.force (rate, currency.as_upper)
end
feature -- Conversion
convert (amount_str: STRING; from_currency, to_currency: STRING): STRING
-- Convert amount from one currency to another
require
valid_from: rates.has (from_currency.as_upper) or
from_currency.as_upper.is_equal ("USD")
valid_to: rates.has (to_currency.as_upper) or
to_currency.as_upper.is_equal ("USD")
local
amount, usd_amount, result_amount: SIMPLE_DECIMAL
from_rate, to_rate: SIMPLE_DECIMAL
one: SIMPLE_DECIMAL
do
create amount.make (amount_str)
create one.make_one
-- Get rates (USD = 1.0)
if from_currency.as_upper.is_equal ("USD") then
from_rate := one
else
from_rate := rates [from_currency.as_upper]
end
if to_currency.as_upper.is_equal ("USD") then
to_rate := one
else
to_rate := rates [to_currency.as_upper]
end
-- Convert: from -> USD -> to
usd_amount := amount / from_rate
result_amount := (usd_amount * to_rate).round_cents
Result := result_amount.to_string
end
end
-- Usage:
local
conv: CURRENCY_CONVERTER
do
create conv
conv.set_rate ("EUR", "0.92") -- 1 USD = 0.92 EUR
conv.set_rate ("GBP", "0.79") -- 1 USD = 0.79 GBP
conv.set_rate ("JPY", "149.50") -- 1 USD = 149.50 JPY
print (conv.convert ("100", "USD", "EUR")) -- "92.00"
print (conv.convert ("100", "EUR", "USD")) -- "108.70"
print (conv.convert ("100", "EUR", "JPY")) -- "16249.46"
end
Recipe: Payroll Calculator
Calculate gross pay, deductions, and net pay.
class
PAYROLL_CALCULATOR
feature -- Calculation
calculate_paycheck (
hourly_rate_str: STRING;
regular_hours, overtime_hours: INTEGER;
federal_tax_rate_str, state_tax_rate_str: STRING;
insurance_deduction_str: STRING
): TUPLE [gross, federal_tax, state_tax, insurance, net: STRING]
-- Calculate complete paycheck breakdown
local
hourly_rate, regular_pay, overtime_pay, gross_pay: SIMPLE_DECIMAL
federal_rate, state_rate, federal_tax, state_tax: SIMPLE_DECIMAL
insurance, total_deductions, net_pay: SIMPLE_DECIMAL
overtime_multiplier: SIMPLE_DECIMAL
do
create hourly_rate.make (hourly_rate_str)
create overtime_multiplier.make ("1.5")
-- Calculate gross pay
regular_pay := hourly_rate *
create {SIMPLE_DECIMAL}.make_from_integer (regular_hours)
overtime_pay := (hourly_rate * overtime_multiplier) *
create {SIMPLE_DECIMAL}.make_from_integer (overtime_hours)
gross_pay := regular_pay + overtime_pay
-- Calculate taxes
create federal_rate.make (federal_tax_rate_str)
create state_rate.make (state_tax_rate_str)
federal_tax := (gross_pay * federal_rate.from_percentage).round_cents
state_tax := (gross_pay * state_rate.from_percentage).round_cents
-- Insurance deduction
create insurance.make (insurance_deduction_str)
-- Calculate net
total_deductions := federal_tax + state_tax + insurance
net_pay := gross_pay - total_deductions
Result := [
gross_pay.to_currency_string,
federal_tax.to_currency_string,
state_tax.to_currency_string,
insurance.to_currency_string,
net_pay.to_currency_string
]
end
end
-- Usage: $25/hour, 40 regular + 10 overtime
local
payroll: PAYROLL_CALCULATOR
check: TUPLE [gross, federal_tax, state_tax, insurance, net: STRING]
do
create payroll
check := payroll.calculate_paycheck (
"25.00", -- hourly rate
40, 10, -- regular hours, overtime hours
"22", -- 22% federal tax
"5", -- 5% state tax
"125.00" -- insurance per period
)
print ("Gross: " + check.gross) -- Gross: $1,375.00
print ("Federal Tax: " + check.federal_tax) -- Federal Tax: $302.50
print ("State Tax: " + check.state_tax) -- State Tax: $68.75
print ("Insurance: " + check.insurance) -- Insurance: $125.00
print ("Net Pay: " + check.net) -- Net Pay: $878.75
end
Recipe: Shopping Cart with Discounts
A shopping cart that supports different discount types.
class
SHOPPING_CART
feature -- Access
items: ARRAYED_LIST [TUPLE [name: STRING; price: SIMPLE_DECIMAL; qty: INTEGER]]
attribute
create Result.make (10)
end
discount_code: detachable STRING
feature -- Modification
add_item (name, price_str: STRING; quantity: INTEGER)
local
price: SIMPLE_DECIMAL
do
create price.make (price_str)
items.extend ([name, price, quantity])
end
apply_code (code: STRING)
do
discount_code := code.as_upper
end
feature -- Calculation
subtotal: SIMPLE_DECIMAL
local
item_total: SIMPLE_DECIMAL
do
create Result.make_zero
across items as item loop
item_total := item.price *
create {SIMPLE_DECIMAL}.make_from_integer (item.qty)
Result := Result + item_total
end
end
discount_amount: SIMPLE_DECIMAL
local
sub: SIMPLE_DECIMAL
discount_rate, flat_discount: SIMPLE_DECIMAL
do
create Result.make_zero
sub := subtotal
if attached discount_code as code then
if code.is_equal ("SAVE10") then
-- 10% off
create discount_rate.make ("10")
Result := (sub * discount_rate.from_percentage).round_cents
elseif code.is_equal ("SAVE20") then
-- 20% off
create discount_rate.make ("20")
Result := (sub * discount_rate.from_percentage).round_cents
elseif code.is_equal ("FLAT25") then
-- $25 off if subtotal >= $100
create flat_discount.make ("25.00")
if sub >= create {SIMPLE_DECIMAL}.make ("100") then
Result := flat_discount
end
end
end
end
total: SIMPLE_DECIMAL
do
Result := (subtotal - discount_amount).round_cents
end
print_receipt
do
print ("=== RECEIPT ===%N")
across items as item loop
print (item.name + " x" + item.qty.out +
": " + (item.price *
create {SIMPLE_DECIMAL}.make_from_integer (item.qty)
).to_currency_string + "%N")
end
print ("Subtotal: " + subtotal.to_currency_string + "%N")
if not discount_amount.is_zero then
print ("Discount: -" + discount_amount.to_currency_string + "%N")
end
print ("TOTAL: " + total.to_currency_string + "%N")
end
end
-- Usage:
local
cart: SHOPPING_CART
do
create cart
cart.add_item ("Widget", "29.99", 2)
cart.add_item ("Gadget", "49.99", 1)
cart.apply_code ("SAVE10")
cart.print_receipt
-- === RECEIPT ===
-- Widget x2: $59.98
-- Gadget x1: $49.99
-- Subtotal: $109.97
-- Discount: -$11.00
-- TOTAL: $98.97
end
Recipe: Loan Payment Calculator
Calculate monthly payments and amortization schedule.
class
LOAN_CALCULATOR
feature -- Calculation
monthly_payment (principal_str, annual_rate_str: STRING;
term_months: INTEGER): STRING
-- Calculate monthly payment using standard formula:
-- M = P * (r(1+r)^n) / ((1+r)^n - 1)
-- P = principal, r = monthly rate, n = number of payments
local
principal, annual_rate, monthly_rate: SIMPLE_DECIMAL
one, twelve: SIMPLE_DECIMAL
one_plus_r, one_plus_r_n: SIMPLE_DECIMAL
numerator, denominator, payment: SIMPLE_DECIMAL
i: INTEGER
do
create principal.make (principal_str)
create annual_rate.make (annual_rate_str)
create one.make_one
create twelve.make_from_integer (12)
-- Monthly rate = annual rate / 12 / 100
monthly_rate := annual_rate / twelve /
create {SIMPLE_DECIMAL}.make_from_integer (100)
-- (1 + r)
one_plus_r := one + monthly_rate
-- (1 + r)^n
create one_plus_r_n.make_one
from i := 1 until i > term_months loop
one_plus_r_n := one_plus_r_n * one_plus_r
i := i + 1
end
-- numerator = r * (1+r)^n
numerator := monthly_rate * one_plus_r_n
-- denominator = (1+r)^n - 1
denominator := one_plus_r_n - one
-- payment = P * numerator / denominator
payment := (principal * numerator / denominator).round_cents
Result := payment.to_currency_string
end
total_cost (principal_str, annual_rate_str: STRING;
term_months: INTEGER): STRING
-- Total amount paid over loan lifetime
local
payment, total: SIMPLE_DECIMAL
do
create payment.make (monthly_payment (principal_str, annual_rate_str,
term_months))
total := payment * create {SIMPLE_DECIMAL}.make_from_integer (term_months)
Result := total.to_currency_string
end
total_interest (principal_str, annual_rate_str: STRING;
term_months: INTEGER): STRING
-- Total interest paid
local
principal, total, interest: SIMPLE_DECIMAL
do
create principal.make (principal_str)
create total.make (total_cost (principal_str, annual_rate_str, term_months))
interest := total - principal
Result := interest.to_currency_string
end
end
-- Usage: $250,000 mortgage at 6.5% for 30 years
local
loan: LOAN_CALCULATOR
do
create loan
print ("Monthly payment: " +
loan.monthly_payment ("250000", "6.5", 360))
-- Monthly payment: $1,580.17
print ("Total cost: " +
loan.total_cost ("250000", "6.5", 360))
-- Total cost: $568,861.20
print ("Total interest: " +
loan.total_interest ("250000", "6.5", 360))
-- Total interest: $318,861.20
end
Recipe: Price Formatting Patterns
Common patterns for displaying prices and numbers.
class
PRICE_FORMATTER
feature -- Formatting
format_price (amount_str: STRING): STRING
-- Standard price: "$1,234.56"
local
amount: SIMPLE_DECIMAL
do
create amount.make (amount_str)
Result := amount.to_currency_string
end
format_price_no_cents (amount_str: STRING): STRING
-- Round price: "$1,235"
local
amount: SIMPLE_DECIMAL
do
create amount.make (amount_str)
Result := "$" + amount.round (0).to_string
end
format_with_symbol (amount_str, symbol: STRING): STRING
-- Custom symbol: "EUR 1,234.56"
local
amount: SIMPLE_DECIMAL
formatted: STRING
do
create amount.make (amount_str)
formatted := amount.to_currency_string
-- Replace $ with custom symbol
formatted.replace_substring_all ("$", symbol + " ")
Result := formatted
end
format_percentage (decimal_str: STRING; places: INTEGER): STRING
-- Format as percentage: "8.25%"
local
amount: SIMPLE_DECIMAL
do
create amount.make (decimal_str)
Result := amount.as_percentage.round (places).to_string + "%%"
end
format_accounting (amount_str: STRING): STRING
-- Accounting format: negative in parens "(1,234.56)"
local
amount: SIMPLE_DECIMAL
do
create amount.make (amount_str)
if amount.is_negative then
Result := "(" + amount.absolute.to_currency_string + ")"
else
Result := amount.to_currency_string
end
end
end
-- Usage:
local
fmt: PRICE_FORMATTER
do
create fmt
print (fmt.format_price ("1234.56")) -- $1,234.56
print (fmt.format_price_no_cents ("1234.56")) -- $1235
print (fmt.format_with_symbol ("1234.56", "EUR")) -- EUR 1,234.56
print (fmt.format_percentage ("0.0825", 2)) -- 8.25%
print (fmt.format_accounting ("-1234.56")) -- ($1,234.56)
end
Recipe: Input Validation
Safely parse and validate user-entered amounts.
class
AMOUNT_VALIDATOR
feature -- Validation
is_valid_amount (input: STRING): BOOLEAN
-- Check if input can be parsed as a valid decimal
local
test: SIMPLE_DECIMAL
retried: BOOLEAN
do
if not retried then
if input /= Void and then not input.is_empty then
create test.make (input)
Result := not test.is_nan
end
end
rescue
retried := True
Result := False
retry
end
parsed_amount (input: STRING): detachable SIMPLE_DECIMAL
-- Parse input, return Void if invalid
local
retried: BOOLEAN
do
if not retried and is_valid_amount (input) then
create Result.make (input)
end
rescue
retried := True
retry
end
validated_currency (input: STRING;
min_str, max_str: STRING): detachable SIMPLE_DECIMAL
-- Parse and validate within range, return Void if invalid
local
amount, min_val, max_val: SIMPLE_DECIMAL
do
if attached parsed_amount (input) as amt then
create min_val.make (min_str)
create max_val.make (max_str)
if amt >= min_val and amt <= max_val then
Result := amt
end
end
end
end
-- Usage:
local
validator: AMOUNT_VALIDATOR
user_input: STRING
do
create validator
user_input := "$1,234.56"
if validator.is_valid_amount (user_input) then
print ("Valid amount")
end
if attached validator.validated_currency (user_input, "0", "10000") as amt then
print ("Amount in range: " + amt.to_currency_string)
else
print ("Amount out of range or invalid")
end
end