Fixed Point
Fixed is Blorp's fixed-point decimal type for values that need an explicit decimal scale.
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)
-- F.to_string(price) == "19.99"
-- F.to_string(tax_rate) == "0.0825"
-- F.to_string(whole_dollars) == "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)
-- price_scale == 2
-- custom_precision == 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
-- F.to_string(subtotal) == "59.97"
-- F.to_string(tax) == "4.95"
-- F.to_string(total) == "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)
-- F.to_string(rounded) == "20.00"
-- whole == 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
-- same_value == True
-- ordered == True
FixedPoint Bounds
Fixed is the concrete type. Use T: FixedPoint only when a helper should work over any fixed-point type in the family.
import:
fixed as F: round_to
pure func cents[T:FixedPoint](value: T) -> T:
round_to(value, 2)
func main(args: List[String]) -> Void:
rounded: Fixed = cents(F.fixed(19.999, 3))
-- F.to_string(rounded) == "20.00"
Conversions
Use to_string for decimal text. Convert to Float only when handing a value to APIs that require floats.
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)
as_float: Float = F.to_float(value)
-- as_text == "12.25"
-- as_int == 12
-- as_float == 12.25
Example
import:
fixed as F
pure func money(value: Float) -> Fixed:
F.fixed(value, 2)
pure func rate(value: Float) -> Fixed:
F.fixed(value, 4)
pure func line_total(unit_price: Fixed, quantity: Int) -> Fixed:
unit_price * F.from_int(quantity, 0)
pure 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: ${subtotal}") -- prints: subtotal: 59.97
print("tax: ${tax}") -- prints: tax: 4.95
print("total: ${total}") -- prints: total: 64.92
print("scale: ${scale}") -- prints: scale: 2
Try it
blorp run examples/docs/core-data/fixed/fixed.brp