Early preview: syntax, standard library APIs, and tooling may change.

Core DataFixed Point

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

fixed-point.brp
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

terminal
blorp run examples/docs/core-data/fixed/fixed-point.brp