to String() - > string- Module
- std.
decimal - Receiver
- Decimal
- Minimum arity
- 0
- Maximum arity
- 0
Declaration and parameters
LinkAvailability
Included by default: Pending
Import std.decimal in language mode 5.21.
The current compiler selects std/decimal.tpz for this language mode. Availability in other released editions and inclusion in each installed distribution are Pending.
Source evidence
- compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
b48527d0a174· 1131 - compiler/crates/topaz_resolve/src/stdlib.rs at
b48527d0a174· 62 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
b48527d0a174· 1131 - compiler/crates/topaz_self_frontend/topaz/checker/builtin_signatures.tpz at
b48527d0a174· 484 - compiler/crates/topaz_self_frontend/topaz/checker/members_capabilities.tpz at
b48527d0a174· 1296 - compiler/crates/topaz_value/src/value/members.rs at
b48527d0a174· 300
Receiver
Decimal
Parameter constraints
A Decimal represents a signed integer coefficient multiplied by ten raised to the negative scale. The coefficient has arbitrary precision. The scale is an integer from 0 through 4294967295 inclusive.
Decimal has no fixed significant digit limit or ambient precision context. Increasing the coefficient beyond the int range does not cause numeric overflow. Decimal values are finite and have no infinity or NaN.
Every Decimal is canonical. Remove trailing coefficient zeros while its scale is positive. Zero has coefficient zero and scale zero. A negative zero spelling produces the same value as zero.
Decimal.scale returns the canonical scale as int. It counts fractional decimal places after normalization. It does not retain input padding or a requested display precision.
Decimal.toString returns exact ASCII decimal text without an exponent or locale rules. A negative nonzero value starts with a minus sign. The integer part has at least one digit and no redundant leading zeros.
A positive scale produces a decimal point followed by exactly that many fractional digits. There are no trailing fractional zeros. Scale zero omits the decimal point, and zero is written as 0.
Exact addition and subtraction align the operand scales before combining their coefficients. Exact multiplication multiplies their coefficients and adds their scales without rounding.
Normalize the exact product before enforcing the scale limit. Raise TPZ4004 when its canonical scale exceeds 4294967295. An intermediate scale sum must not reject a product whose canonical scale fits.
Parsing the output of Decimal.toString recovers the same Decimal. A request for more fractional places through round or div does not append stored zeros.
Decimal values are immutable. Receiver and positional argument expressions evaluate once in source order. An earlier fault prevents later evaluation. The decimal operations themselves do not perform external effects.
Related rule: Preserve exact decimal values and canonical scaleDecimal equality compares exact numeric values. Values parsed from 1.2, 1.20 and 1.200 are equal. Redundant scale in an input spelling is not part of value identity.
The equality operators == and != return complementary results. Zero and every accepted signed or padded zero spelling compare equal.
The ordering operators <, <=, > and >= use exact numeric order. They align decimal places without first rounding either operand or converting either operand to float.
Every pair of Decimal values is comparable. Equality agrees with ordering, and exactly one of less than, equal to or greater than holds.
Comparison leaves both operands and their canonical scales unchanged. Call round explicitly when comparison after rounding is the intended operation.
Related rule: Compare exact decimal values independently of input scaleResult
The declared result type is string.
Effects
Failures
Result and effects
LinkUse ASCII digits, a minus sign for negative nonzero values and a decimal point when the canonical scale is positive. Omit exponents, redundant zeros and a negative sign on zero.
Why
LinkOne numeric serialization supports exact round trips while display padding remains an explicit formatting choice.
Resolved contracts
LinkRelated entries
LinkPreserve exact decimal values and canonical scale
LinkPreserve exact decimal values and canonical scale
A Decimal represents a signed integer coefficient multiplied by ten raised to the negative scale. The coefficient has arbitrary precision. The scale is an integer from 0 through 4294967295 inclusive.
Decimal has no fixed significant digit limit or ambient precision context. Increasing the coefficient beyond the int range does not cause numeric overflow. Decimal values are finite and have no infinity or NaN.
Every Decimal is canonical. Remove trailing coefficient zeros while its scale is positive. Zero has coefficient zero and scale zero. A negative zero spelling produces the same value as zero.
Decimal.scale returns the canonical scale as int. It counts fractional decimal places after normalization. It does not retain input padding or a requested display precision.
Decimal.toString returns exact ASCII decimal text without an exponent or locale rules. A negative nonzero value starts with a minus sign. The integer part has at least one digit and no redundant leading zeros.
A positive scale produces a decimal point followed by exactly that many fractional digits. There are no trailing fractional zeros. Scale zero omits the decimal point, and zero is written as 0.
Exact addition and subtraction align the operand scales before combining their coefficients. Exact multiplication multiplies their coefficients and adds their scales without rounding.
Normalize the exact product before enforcing the scale limit. Raise TPZ4004 when its canonical scale exceeds 4294967295. An intermediate scale sum must not reject a product whose canonical scale fits.
Parsing the output of Decimal.toString recovers the same Decimal. A request for more fractional places through round or div does not append stored zeros.
Decimal values are immutable. Receiver and positional argument expressions evaluate once in source order. An earlier fault prevents later evaluation. The decimal operations themselves do not perform external effects.
Why
Exact coefficients preserve decimal quantities without a hidden precision setting. Canonical scale makes equality and text exchange independent of input padding. Display padding has a separate formatting intent and is not stored as numeric value state. Scale bounds apply to the value that the operation returns. A temporary representation has no distinct numeric intent and must not make an otherwise representable product fail.
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 71 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/builtins/bigint_decimal.rs at
693a4cb69c39· 184 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 212 - compiler/crates/topaz_value/src/value/operators.rs at
693a4cb69c39· 227 -
topaz.stdlib.contract.decimal-valuesatworking-tree - topaz.decision.decimal-values.1 at
topaz.decisi
Normalize signs and redundant decimal zeros
Linkimport std.decimal { Decimal }import std.testimport std.iofunction read(text: string) -> Decimal {let parsed: Option<Decimal> = Decimal.parse(text)let value: Decimal = test.assertSome(parsed)return value}for text in (["0", "-0.000", "+00012.3400", ".0050", "100.000"]) {let value: Decimal = read(text)io.writeLine("{value.toString()} {value.scale()}")let reparsed: Option<Decimal> = Decimal.parse(value.toString())let recovered: Decimal = test.assertSome(reparsed)test.assertEq(recovered, value)}
0 0 0 0 12.34 2 0.005 3 100 0
Expected result
Expected result
Execution completes. Exit code 0.
0 00 012.34 20.005 3100 0
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 71 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/builtins/bigint_decimal.rs at
693a4cb69c39· 184 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 212 - compiler/crates/topaz_value/src/value/operators.rs at
693a4cb69c39· 227 -
topaz.stdlib.contract.decimal-valuesatworking-tree - topaz.decision.decimal-values.1 at
topaz.decisi
Keep every digit beyond machine integer precision
Linkimport std.decimal { Decimal }import std.testimport std.iofunction read(text: string) -> Decimal {let parsed: Option<Decimal> = Decimal.parse(text)let value: Decimal = test.assertSome(parsed)return value}let left: Decimal = read("1000000000000000000000000000000.25")let right: Decimal = read("0.75")let sum: Decimal = left + rightlet difference: Decimal = left - rightlet product: Decimal = left * rightio.writeLine(sum.toString())io.writeLine(difference.toString())io.writeLine(product.toString())io.writeLine(left.toString())
1000000000000000000000000000001 999999999999999999999999999999.5 750000000000000000000000000000.1875 1000000000000000000000000000000.25
Expected result
Expected result
Execution completes. Exit code 0.
1000000000000000000000000000001999999999999999999999999999999.5750000000000000000000000000000.18751000000000000000000000000000000.25
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 71 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/builtins/bigint_decimal.rs at
693a4cb69c39· 184 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 212 - compiler/crates/topaz_value/src/value/operators.rs at
693a4cb69c39· 227 -
topaz.stdlib.contract.decimal-valuesatworking-tree - topaz.decision.decimal-values.1 at
topaz.decisi
Normalize a product before checking its final scale
Linkimport std.decimal { Decimal }import std.testimport std.iolet parsedPlace: Option<Decimal> = Decimal.parse("0.1")let mut place: Decimal = test.assertSome(parsedPlace)let mut smallest: Decimal = (1).toDecimal()let mut step: int = 0while (step < 32) {smallest = smallest * placeif (step < 31) {place = place * place}step = step + 1}let doubled: Decimal = smallest * (2).toDecimal()let parsedHalf: Option<Decimal> = Decimal.parse("0.5")let half: Decimal = test.assertSome(parsedHalf)let recovered: Decimal = doubled * halflet equal = recovered == smallestio.writeLine("{recovered.scale()} {equal}")
4294967295 true
Expected result
Expected result
Execution completes. Exit code 0.
4294967295 true
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 71 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/builtins/bigint_decimal.rs at
693a4cb69c39· 184 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 212 - compiler/crates/topaz_value/src/value/operators.rs at
693a4cb69c39· 227 -
topaz.stdlib.contract.decimal-valuesatworking-tree - topaz.decision.decimal-values.1 at
topaz.decisi
Compare exact decimal values independently of input scale
LinkCompare exact decimal values independently of input scale
Decimal equality compares exact numeric values. Values parsed from 1.2, 1.20 and 1.200 are equal. Redundant scale in an input spelling is not part of value identity.
The equality operators == and != return complementary results. Zero and every accepted signed or padded zero spelling compare equal.
The ordering operators <, <=, > and >= use exact numeric order. They align decimal places without first rounding either operand or converting either operand to float.
Every pair of Decimal values is comparable. Equality agrees with ordering, and exactly one of less than, equal to or greater than holds.
Comparison leaves both operands and their canonical scales unchanged. Call round explicitly when comparison after rounding is the intended operation.
Why
Numeric comparison answers whether quantities are equal or ordered. Retaining textual padding as a second value identity would mix formatting intent into arithmetic. Exact comparison also preserves distinctions beyond binary floating point precision.
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 222 -
topaz.stdlib.contract.decimal-comparisonatworking-tree - topaz.decision.decimal-comparison.1 at
topaz.decisi
Treat values with different input padding as equal
Linkimport std.decimal { Decimal }import std.testimport std.iofunction read(text: string) -> Decimal {let parsed: Option<Decimal> = Decimal.parse(text)let value: Decimal = test.assertSome(parsed)return value}let left: Decimal = read("1.20")let right: Decimal = read("1.2000")let equal = left == rightlet unequal = left != rightlet less = left < rightlet lessOrEqual = left <= rightlet greater = left > rightlet greaterOrEqual = left >= rightio.writeLine("{equal} {unequal} {less} {lessOrEqual} {greater} {greaterOrEqual}")io.writeLine("{left.scale()} {right.scale()}")
true false false true false true 1 1
Expected result
Expected result
Execution completes. Exit code 0.
true false false true false true1 1
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 222 -
topaz.stdlib.contract.decimal-comparisonatworking-tree - topaz.decision.decimal-comparison.1 at
topaz.decisi
Order neighboring large values and signed zero exactly
Linkimport std.decimal { Decimal }import std.testimport std.iofunction read(text: string) -> Decimal {let parsed: Option<Decimal> = Decimal.parse(text)let value: Decimal = test.assertSome(parsed)return value}let lower: Decimal = read("9007199254740992")let higher: Decimal = read("9007199254740993")let increasing = lower < higherlet decreasing = higher > lowerlet distinct = lower != higherlet negativeOrder = -higher < -lowerio.writeLine("{increasing} {decreasing} {distinct} {negativeOrder}")let negativeZero: Decimal = read("-0.000")let zero: Decimal = (0).toDecimal()let sameZero = negativeZero == zeroio.writeLine("{sameZero}")
true true true true true
Expected result
Expected result
Execution completes. Exit code 0.
true true true truetrue
Source evidence
- compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 3 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 194 - compiler/crates/topaz_value/src/value/decimal.rs at
693a4cb69c39· 222 -
topaz.stdlib.contract.decimal-comparisonatworking-tree - topaz.decision.decimal-comparison.1 at
topaz.decisi