Fixed Point
Fixed is Blorp's fixed-point decimal type for values that need an explicit decimal scale. It is unrelated to the fixed aggregate modifier.
Creating Fixed Values
Import fixed as F, then create decimal values with a scale.
import:
fixed as F
func main(args: List[String]) -> Void:
price: Fixed = F.fixed(19.99, 2)
tax_rate: Fixed = F.fixed(0.0825, 4)
whole_dollars: Fixed = F.from_int(42, 2)
print(F.to_string(price)) -- prints: 19.99
print(F.to_string(tax_rate)) -- prints: 0.0825
print(F.to_string(whole_dollars)) -- prints: 42.00
Scale and Precision
scale is the number of decimal places. fixed uses default precision; with_precision sets it explicitly.
import:
fixed as F
func main(args: List[String]) -> Void:
price: Fixed = F.fixed(19.99, 2)
custom: Fixed = F.with_precision(1.2345, 4, 6)
price_scale: Int = F.get_scale(price)
custom_precision: Int = F.get_precision(custom)
print(price_scale) -- prints: 2
print(custom_precision) -- prints: 6
Arithmetic
+ and - normalize scale, * adds scales, and / uses extra precision. Round when the domain expects a specific scale.
import:
fixed as F
func main(args: List[String]) -> Void:
price: Fixed = F.fixed(19.99, 2)
quantity: Fixed = F.from_int(3, 0)
subtotal: Fixed = price * quantity
tax: Fixed = F.round_to(subtotal * F.fixed(0.0825, 4), 2)
total: Fixed = subtotal + tax
print(F.to_string(subtotal)) -- prints: 59.97
print(F.to_string(tax)) -- prints: 4.95
print(F.to_string(total)) -- prints: 64.92
Rounding
round_to returns a new Fixed at the requested scale. to_int truncates toward zero.
import:
fixed as F
func main(args: List[String]) -> Void:
raw: Fixed = F.fixed(19.999, 3)
rounded: Fixed = F.round_to(raw, 2)
whole: Int = F.to_int(rounded)
print(F.to_string(rounded)) -- prints: 20.00
print(whole) -- prints: 20
Comparisons
Comparisons normalize scale, so the same decimal value compares equal even when stored with different scales.
import:
fixed as F
func main(args: List[String]) -> Void:
one_decimal: Fixed = F.fixed(10.0, 1)
two_decimals: Fixed = F.fixed(10.0, 2)
smaller: Fixed = F.fixed(9.99, 2)
same_value: Bool = one_decimal == two_decimals
ordered: Bool = smaller < one_decimal
print(same_value) -- prints: True
print(ordered) -- prints: True
Named Rounding Helpers
Give domain-specific rounding a name so callers consistently apply the same decimal scale.
import:
fixed as F
pure func cents(value: Fixed) -> Fixed:
F.round_to(value, 2)
func main(args: List[String]) -> Void:
rounded: Fixed = cents(F.fixed(19.999, 3))
print(F.to_string(rounded)) -- prints: 20.00
Conversions
Use to_string for decimal text and to_int for truncation toward zero.
import:
fixed as F
func main(args: List[String]) -> Void:
value: Fixed = F.fixed(12.25, 2)
as_text: String = F.to_string(value)
as_int: Int = F.to_int(value)
print(as_text) -- prints: 12.25
print(as_int) -- prints: 12
Example
import:
fixed as F
func money(value: Float) -> Fixed:
F.fixed(value, 2)
func rate(value: Float) -> Fixed:
F.fixed(value, 4)
func line_total(unit_price: Fixed, quantity: Int) -> Fixed:
unit_price * F.from_int(quantity, 0)
func tax_for(subtotal: Fixed, tax_rate: Fixed) -> Fixed:
F.round_to(subtotal * tax_rate, 2)
func main(args: List[String]) -> Void:
price: Fixed = money(19.99)
quantity: Int = 3
subtotal: Fixed = line_total(price, quantity)
tax: Fixed = tax_for(subtotal, rate(0.0825))
total: Fixed = subtotal + tax
scale: Int = F.get_scale(total)
print("subtotal: ${F.to_string(subtotal)}") -- prints: subtotal: 59.97
print("tax: ${F.to_string(tax)}") -- prints: tax: 4.95
print("total: ${F.to_string(total)}") -- prints: total: 64.92
print("scale: ${scale}") -- prints: scale: 2
Try it
blorp run examples/docs/core-data/fixed/fixed-point.brp