decimal
Exact decimal numbers for money and accounting, with none of the rounding error of floating point.
import decimal
In f64, 0.1 + 0.2 is not exactly 0.3. For science and graphics that tiny error does not matter; for money it does, because a lost cent in the accounts is not acceptable. The decimal package keeps a number as a large whole number and a "scale", the count of digits after the point, so 10.05 is 1005 with scale 2 and no error can creep in.
Addition, subtraction and multiplication are always exact. Division may not terminate, as one third does not, so you say how many decimal places you want and how to round. Rounding offers seven methods; accounting usually wants HalfEven.
Types
Rounding
enum Rounding| Name | Type | Description |
|---|---|---|
Down | | Towards zero: the extra digits are thrown away. |
Up | | Away from zero. |
Floor | | Downwards, towards negative infinity. |
Ceil | | Upwards, towards positive infinity. |
HalfUp | | To the nearest, with a half going away from zero. This is the rounding taught at school. |
HalfDown | | To the nearest, with a half going towards zero. |
HalfEven | | To the nearest, with a half going to the even number, known as banker's rounding. Over many additions it keeps the rounding error at zero on average. |
import decimal
func main:
x := decimal.FromScaled(-25, 1)
println decimal.ToStr(decimal.Round(x, 0)), decimal.ToStr(decimal.RoundHalfUp(x, 0)), decimal.ToStr(decimal.Truncate(x, 0))
each mode in [decimal.Rounding.Down, decimal.Rounding.Up, decimal.Rounding.Floor, decimal.Rounding.Ceil, decimal.Rounding.HalfUp, decimal.Rounding.HalfDown, decimal.Rounding.HalfEven]:
print decimal.ToStr(decimal.Rescale(x, 0, mode)), ""
end
println ""
println decimal.ToStr(decimal.Trim(decimal.FromScaled(12500, 4)))
endDec
struct Dec| Name | Type | Description |
|---|---|---|
unscaled | bigint.Int | The whole number without the point; for 10.05 it is 1005. |
scale | int = 0 | The number of digits after the point. |
import decimal
import bigint
func main:
mut a := decimal.FromScaled(1005, 2)
defer a.free()
println a.to_str(), a.is_zero(), a.sign()
b := a.clone()
println decimal.ToStr(b), decimal.Scale(b), bigint.ToStr(decimal.Unscaled(b))
println decimal.ToStr(decimal.Zero()), decimal.ToStr(decimal.FromInt(42))
println decimal.ToStr(decimal.New(bigint.FromInt(31415), 4))
println decimal.ToStr(decimal.FromFloat(0.1, 3))
println decimal.IsZero(decimal.Zero()), decimal.IsNegative(decimal.FromInt(-1)), decimal.Sign(a)
mut c := decimal.Clone(a)
decimal.Free(c)
endfree
func free()The example for this item is shown with the ones above: decimal-Dec.salam
is_zero
func is_zero(): boolThe example for this item is shown with the ones above: decimal-Dec.salam
sign
func sign(): intThe example for this item is shown with the ones above: decimal-Dec.salam
clone
func clone(): DecThe example for this item is shown with the ones above: decimal-Dec.salam
to_str
func to_str(): strThe example for this item is shown with the ones above: decimal-Dec.salam
Functions
Split
func Split(total: Dec, n: int): Vector<Dec>n equal shares whose total is exactly the amount; the odd remainder goes to the first shares.import decimal
func main:
total := decimal.FromScaled(10000, 2)
mut shares := decimal.Split(total, 3)
defer decimal.FreeAll(shares)
each s in shares:
print decimal.ToStr(s), ""
end
println ""
println decimal.ToStr(decimal.Sum(shares))
mut ratios := Vector {} as Vector<i64>
defer ratios.free()
ratios.push(1 as i64)
ratios.push(2 as i64)
mut parts := decimal.Allocate(total, ratios)
defer decimal.FreeAll(parts)
each p in parts:
print decimal.ToStr(p), ""
end
println ""
endAllocate
func Allocate(total: Dec, ratios: Vector<i64>): Vector<Dec>The example for this item is shown with the ones above: decimal-Split.salam
FreeAll
func FreeAll(v &: Vector<Dec>)The example for this item is shown with the ones above: decimal-Split.salam
Rescale
func Rescale(d: Dec, scale: int, mode: Rounding): DecThe example for this item is shown with the ones above: decimal-Round.salam
Round
func Round(d: Dec, scale: int): DecThe example for this item is shown with the ones above: decimal-Round.salam
RoundHalfUp
func RoundHalfUp(d: Dec, scale: int): DecThe example for this item is shown with the ones above: decimal-Round.salam
Truncate
func Truncate(d: Dec, scale: int): DecThe example for this item is shown with the ones above: decimal-Round.salam
Trim
func Trim(d: Dec): DecThe example for this item is shown with the ones above: decimal-Round.salam
Neg
func Neg(d: Dec): Decimport decimal
func main:
a := decimal.FromScaled(10, 1)
b := decimal.FromScaled(20, 1)
println decimal.ToStr(decimal.Add(a, b)), decimal.ToStr(decimal.Sub(a, b)), decimal.ToStr(decimal.Mul(a, b))
println decimal.ToStr(decimal.Div(a, decimal.FromInt(3), 4, decimal.Rounding.HalfEven))
println decimal.ToStr(decimal.DivRound(a, decimal.FromInt(3), 2))
println decimal.ToStr(decimal.Pow(b, 3)), decimal.ToStr(decimal.Neg(a)), decimal.ToStr(decimal.Abs(decimal.Neg(a)))
println decimal.ToStr(decimal.MulInt(a, 3)), decimal.ToStr(decimal.AddInt(a, 1)), decimal.ToStr(decimal.SubInt(a, 1))
println decimal.ToStr(decimal.DivInt(decimal.FromInt(10), 4, 2, decimal.Rounding.Floor))
println decimal.ToStr(decimal.Percent(decimal.FromInt(250000), decimal.FromInt(9), 0))
endAbs
func Abs(d: Dec): DecThe example for this item is shown with the ones above: decimal-Add.salam
Add
func Add(a: Dec, b: Dec): DecThe example for this item is shown with the ones above: decimal-Add.salam
Sub
func Sub(a: Dec, b: Dec): DecThe example for this item is shown with the ones above: decimal-Add.salam
Mul
func Mul(a: Dec, b: Dec): DecThe example for this item is shown with the ones above: decimal-Add.salam
Div
func Div(a: Dec, b: Dec, scale: int, mode: Rounding): DecThe example for this item is shown with the ones above: decimal-Add.salam
DivRound
func DivRound(a: Dec, b: Dec, scale: int): DecThe example for this item is shown with the ones above: decimal-Add.salam
Pow
func Pow(d: Dec, n: int): Decn.The example for this item is shown with the ones above: decimal-Add.salam
MulInt
func MulInt(d: Dec, v: i64): DecThe example for this item is shown with the ones above: decimal-Add.salam
AddInt
func AddInt(d: Dec, v: i64): DecThe example for this item is shown with the ones above: decimal-Add.salam
SubInt
func SubInt(d: Dec, v: i64): DecThe example for this item is shown with the ones above: decimal-Add.salam
DivInt
func DivInt(d: Dec, v: i64, scale: int, mode: Rounding): DecThe example for this item is shown with the ones above: decimal-Add.salam
Percent
func Percent(d: Dec, pct: Dec, scale: int): Decpct per cent of the number, to the given number of decimal places; a 9 per cent tax, for instance.The example for this item is shown with the ones above: decimal-Add.salam
Sum
func Sum(items: Vector<Dec>): DecThe example for this item is shown with the ones above: decimal-Split.salam
ToStr
func ToStr(d: Dec): strimport decimal
func main:
mut ok := false
d := decimal.Parse("1234567.891", ok)
println ok, decimal.ToStr(d)
println decimal.ToStrFixed(d, 1), decimal.FormatGrouped(d, 2, ",", ".")
println decimal.ToStr(decimal.ParseOr("not a number"))
mut fits := false
println decimal.ToInt(decimal.FromInt(42), fits), fits, decimal.ToFloat(d)
endToStrFixed
func ToStrFixed(d: Dec, scale: int): strscale decimal places.The example for this item is shown with the ones above: decimal-Parse.salam
FormatGrouped
func FormatGrouped(d: Dec, scale: int, group: str, point: str): strThe example for this item is shown with the ones above: decimal-Parse.salam
Parse
func Parse(s: str, ok &: bool): Decok turns false.The example for this item is shown with the ones above: decimal-Parse.salam
ParseOr
func ParseOr(s: str): DecThe example for this item is shown with the ones above: decimal-Parse.salam
ToInt
func ToInt(d: Dec, ok &: bool): i64ok turns false.The example for this item is shown with the ones above: decimal-Parse.salam
ToFloat
func ToFloat(d: Dec): f64The example for this item is shown with the ones above: decimal-Parse.salam
Zero
func Zero(): DecThe example for this item is shown with the ones above: decimal-Dec.salam
FromInt
func FromInt(v: i64): DecThe example for this item is shown with the ones above: decimal-Dec.salam
FromScaled
func FromScaled(unscaled: i64, scale: int): DecFromScaled(1005, 2) is 10.05. It suits amounts stored in minor units such as cents.The example for this item is shown with the ones above: decimal-Dec.salam
New
func New(unscaled: bigint.Int, scale: int): DecThe example for this item is shown with the ones above: decimal-Dec.salam
Clone
func Clone(d: Dec): DecThe example for this item is shown with the ones above: decimal-Dec.salam
Free
func Free(d &: Dec)The example for this item is shown with the ones above: decimal-Dec.salam
FromFloat
func FromFloat(f: f64, scale: int): Decf64 with the number of decimal places you ask for. The f64's own error is rounded away, so 0.1 to three places is exactly 0.100.The example for this item is shown with the ones above: decimal-Dec.salam
IsZero
func IsZero(d: Dec): boolThe example for this item is shown with the ones above: decimal-Dec.salam
Sign
func Sign(d: Dec): intThe example for this item is shown with the ones above: decimal-Dec.salam
IsNegative
func IsNegative(d: Dec): boolThe example for this item is shown with the ones above: decimal-Dec.salam
Scale
func Scale(d: Dec): intThe example for this item is shown with the ones above: decimal-Dec.salam
Unscaled
func Unscaled(d: Dec): bigint.IntThe example for this item is shown with the ones above: decimal-Dec.salam
Cmp
func Cmp(a: Dec, b: Dec): intimport decimal
func main:
a := decimal.FromScaled(150, 2)
b := decimal.FromScaled(15, 1)
println decimal.Cmp(a, b), decimal.Equals(a, b)
println decimal.Less(a, decimal.FromInt(2)), decimal.Greater(a, decimal.FromInt(2))
println decimal.ToStr(decimal.Min(a, decimal.FromInt(1))), decimal.ToStr(decimal.Max(a, decimal.FromInt(1)))
endEquals
func Equals(a: Dec, b: Dec): boolThe example for this item is shown with the ones above: decimal-Cmp.salam
Less
func Less(a: Dec, b: Dec): boolThe example for this item is shown with the ones above: decimal-Cmp.salam
Greater
func Greater(a: Dec, b: Dec): boolThe example for this item is shown with the ones above: decimal-Cmp.salam
Min
func Min(a: Dec, b: Dec): DecThe example for this item is shown with the ones above: decimal-Cmp.salam
Max
func Max(a: Dec, b: Dec): DecThe example for this item is shown with the ones above: decimal-Cmp.salam