Skip to content

Decimal

A Decimal is an exact decimal number: an integer significand of up to 512 bits, about 154 digits, and a scale, the number of digits after the point, from 0 to 154. A number written with a decimal point is a Decimal, so arithmetic on it loses nothing to binary rounding:

0.1 + 0.2 == 0.3
true

The scale is kept for display. A sum or a difference has the larger scale of its operands, and a product the sum of their scales. Equality and order are by value, so 1.50 == 1.5 is true:

[1.50, 1.50 + 1.25, 1.50 * 1.5]
[1.50, 2.75, 2.250]

A literal keeps every digit it is written with, however many there are:

123456789012345678901234567890.123456789 + 0.000000001
123456789012345678901234567890.123456790

Division and rounding

/ is exact where the quotient terminates, and otherwise rounded half to even to 100 significant digits. Division by zero is an evaluation error, as it is for an Int. round(x, places) rounds half to even to places digits after the point, and round(x) to a whole number:

[10 / 4.0, round(2 / 3.0, 4), round(2.345, 2), round(2.355, 2), round(2.5)]
[2.5, 0.6667, 2.34, 2.36, 2]

Int, Float and Decimal

An Int beside a Decimal widens to one of scale 0, in arithmetic and in a comparison:

[12.50 * 3, 7 - 0.25]
[37.50, 6.75]

A Float does not mix with a Decimal: a binary float carries no exact decimal value, so the program says which conversion it means. decimal(x) reads an Int, or a Float by its shortest digits, as a Decimal; float(d) gives the nearest Float and int(d) the integer part:

1.5 + 2.0f
type error: a Decimal and a Float do not mix: write `decimal(x)` to read the Float as a Decimal, or `float(d)` to read the Decimal as a Float
 --> <expression>:1:7
  |
1 | 1.5 + 2.0f
  |       ^^^^
[decimal(0.1f) + 1.5, "12.50".to_decimal().unwrap_or(0.0)]
[1.6, 12.50]

JSON, YAML and CSV carry a Decimal without loss: a number read as a Decimal field keeps the digits it is written with, and a Decimal is written as a number with its digits and scale.