Skip to content
Topaz6.0 · Before release
Download

Search documentation

Specification 6.0 · Not released · Tested product 5.21.3

Use arrow keys to choose a result. Press Enter to open.

Type an API name, diagnostic number, rule, or project topic.

    Library · std.decimal

    Decimal.scale

    Read the canonical number of fractional decimal places.

    scale() -> int
    Receiver
    Decimal
    Minimum arity
    0
    Maximum arity
    0

    Declaration and parameters

    Link

    Availability

    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

    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.

    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.

    Result

    The declared result type is int.

    Effects

    Failures

    Result and effects

    Link

    Return an int from 0 through 4294967295. Trailing coefficient zeros have already been removed, and every zero value has scale zero.

    Why

    Link

    Canonical scale observes numeric value state without preserving input padding.

    Resolved contracts

    Link

    Related entries

    Link

    std.decimal

    Preserve exact decimal values and canonical scale

    Link
    Ruletopaz.stdlib.contract.decimal-values.rule

    Preserve 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

    Normalize signs and redundant decimal zeros

    Link
    main.tpzNormalize signs and redundant decimal zerosOpen in Playground
    1. import std.decimal { Decimal }
    2. import std.test
    3. import std.io
    4. function read(text: string) -> Decimal {
    5. let parsed: Option<Decimal> = Decimal.parse(text)
    6. let value: Decimal = test.assertSome(parsed)
    7. return value
    8. }
    9. for text in (["0", "-0.000", "+00012.3400", ".0050", "100.000"]) {
    10. let value: Decimal = read(text)
    11. io.writeLine("{value.toString()} {value.scale()}")
    12. let reparsed: Option<Decimal> = Decimal.parse(value.toString())
    13. let recovered: Decimal = test.assertSome(reparsed)
    14. test.assertEq(recovered, value)
    15. }
    Expected outputexit 0
    0 0
    0 0
    12.34 2
    0.005 3
    100 0
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 0 0
    2. 0 0
    3. 12.34 2
    4. 0.005 3
    5. 100 0
    Source evidence

    Keep every digit beyond machine integer precision

    Link
    main.tpzKeep every digit beyond machine integer precisionOpen in Playground
    1. import std.decimal { Decimal }
    2. import std.test
    3. import std.io
    4. function read(text: string) -> Decimal {
    5. let parsed: Option<Decimal> = Decimal.parse(text)
    6. let value: Decimal = test.assertSome(parsed)
    7. return value
    8. }
    9. let left: Decimal = read("1000000000000000000000000000000.25")
    10. let right: Decimal = read("0.75")
    11. let sum: Decimal = left + right
    12. let difference: Decimal = left - right
    13. let product: Decimal = left * right
    14. io.writeLine(sum.toString())
    15. io.writeLine(difference.toString())
    16. io.writeLine(product.toString())
    17. io.writeLine(left.toString())
    Expected outputexit 0
    1000000000000000000000000000001
    999999999999999999999999999999.5
    750000000000000000000000000000.1875
    1000000000000000000000000000000.25
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 1000000000000000000000000000001
    2. 999999999999999999999999999999.5
    3. 750000000000000000000000000000.1875
    4. 1000000000000000000000000000000.25
    Source evidence

    Normalize a product before checking its final scale

    Link
    main.tpzNormalize a product before checking its final scaleOpen in Playground
    1. import std.decimal { Decimal }
    2. import std.test
    3. import std.io
    4. let parsedPlace: Option<Decimal> = Decimal.parse("0.1")
    5. let mut place: Decimal = test.assertSome(parsedPlace)
    6. let mut smallest: Decimal = (1).toDecimal()
    7. let mut step: int = 0
    8. while (step < 32) {
    9. smallest = smallest * place
    10. if (step < 31) {
    11. place = place * place
    12. }
    13. step = step + 1
    14. }
    15. let doubled: Decimal = smallest * (2).toDecimal()
    16. let parsedHalf: Option<Decimal> = Decimal.parse("0.5")
    17. let half: Decimal = test.assertSome(parsedHalf)
    18. let recovered: Decimal = doubled * half
    19. let equal = recovered == smallest
    20. io.writeLine("{recovered.scale()} {equal}")
    Expected outputexit 0
    4294967295 true
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. 4294967295 true
    Source evidence

    Compare exact decimal values independently of input scale

    Link
    Ruletopaz.stdlib.contract.decimal-comparison.rule

    Compare 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

    Treat values with different input padding as equal

    Link
    main.tpzTreat values with different input padding as equalOpen in Playground
    1. import std.decimal { Decimal }
    2. import std.test
    3. import std.io
    4. function read(text: string) -> Decimal {
    5. let parsed: Option<Decimal> = Decimal.parse(text)
    6. let value: Decimal = test.assertSome(parsed)
    7. return value
    8. }
    9. let left: Decimal = read("1.20")
    10. let right: Decimal = read("1.2000")
    11. let equal = left == right
    12. let unequal = left != right
    13. let less = left < right
    14. let lessOrEqual = left <= right
    15. let greater = left > right
    16. let greaterOrEqual = left >= right
    17. io.writeLine("{equal} {unequal} {less} {lessOrEqual} {greater} {greaterOrEqual}")
    18. io.writeLine("{left.scale()} {right.scale()}")
    Expected outputexit 0
    true false false true false true
    1 1
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. true false false true false true
    2. 1 1
    Source evidence

    Order neighboring large values and signed zero exactly

    Link
    main.tpzOrder neighboring large values and signed zero exactlyOpen in Playground
    1. import std.decimal { Decimal }
    2. import std.test
    3. import std.io
    4. function read(text: string) -> Decimal {
    5. let parsed: Option<Decimal> = Decimal.parse(text)
    6. let value: Decimal = test.assertSome(parsed)
    7. return value
    8. }
    9. let lower: Decimal = read("9007199254740992")
    10. let higher: Decimal = read("9007199254740993")
    11. let increasing = lower < higher
    12. let decreasing = higher > lower
    13. let distinct = lower != higher
    14. let negativeOrder = -higher < -lower
    15. io.writeLine("{increasing} {decreasing} {distinct} {negativeOrder}")
    16. let negativeZero: Decimal = read("-0.000")
    17. let zero: Decimal = (0).toDecimal()
    18. let sameZero = negativeZero == zero
    19. io.writeLine("{sameZero}")
    Expected outputexit 0
    true true true true
    true
    
    $ topaz run main.tpz · target product 5.21.3
    Expected result

    Expected result

    Execution completes. Exit code 0.

    Expected stdout
    1. true true true true
    2. true
    Source evidence

    Menu

    Download