module

FixedDecimal::Internal

Low-level arithmetic shared by Fixed and UFixed.

Everything here works on unsigned magnitudes (UInt128) plus a separate sign, with fraction_bits giving the position of the binary point. All rounding is round-half-to-even unless stated otherwise.

:nodoc:

Constants

LOW_64 = 18446744073709551615_u128
MAX_EXPONENT = 1000000

Exponents are saturated to this magnitude while parsing.

MAX_FRACTION_LEADING_ZEROS = 45

A decimal fraction with this many leading zeros is below 2**-129, so it rounds to zero for every supported number of fraction bits.

MAX_INTEGER_DIGITS = 40

Beyond this many decimal digits an integer part cannot fit in 128 bits.

Instance methods

add_scaled_integer(negative : Bool, magnitude : UInt128, integer_negative : Bool, integer : UInt128, fraction_bits : Int32) : Tuple(Bool, UInt128 | Nil)

The signed sum of two magnitudes, where the right-hand one is the integer integer scaled by 2**fraction_bits and so may need up to 256 bits. Returns {negative, magnitude}, with nil for a magnitude that does not fit in 128 bits.

Source
big_magnitude(value : BigInt) : UInt128 | Nil

The value as a UInt128, or nil if it does not fit.

Source
compare(left_negative : Bool, left : UInt128, left_bits : Int32, right_negative : Bool, right : UInt128, right_bits : Int32) : Int32

Three-way comparison of two signed values, each given as a sign, a magnitude and a number of fraction bits.

Source
compare_float(negative : Bool, magnitude : UInt128, fraction_bits : Int32, other : Float) : Int32 | Nil

Compares a fixed-point value with a float exactly; nil for NaN.

Source
compare_magnitudes(left : UInt128, left_bits : Int32, right : UInt128, right_bits : Int32) : Int32

Compares left / 2**left_bits with right / 2**right_bits exactly.

Source
decimal_fraction_to_bits(digits : Array(UInt8), fraction_bits : Int32) : Tuple(UInt128, Bool, Bool)

Converts the decimal fraction 0.d1d2d3... to fraction_bits binary digits, returning {bits, guard, sticky} for rounding.

Source
decimal_to_magnitude(integer : UInt128, fraction_digits : Array(UInt8), fraction_bits : Int32) : UInt128 | Nil

The magnitude nearest to integer + 0.fraction_digits; nil on overflow.

Source
decompose(value : Float64) : Tuple(Bool, UInt64, Int32)

Splits a finite float into {negative, mantissa, exponent} such that its value is exactly mantissa * 2**exponent.

Source
decompose(value : Float32) : Tuple(Bool, UInt64, Int32)

Splits a finite float into {negative, mantissa, exponent} such that its value is exactly mantissa * 2**exponent.

Source
div_shift(dividend : UInt128, divisor : UInt128, fraction_bits : Int32) : UInt128 | Nil

dividend * 2**fraction_bits / divisor, rounded half-to-even; nil on overflow. fraction_bits may be up to 256. Raises DivisionByZeroError when divisor is zero.

Source
fits_shifted?(magnitude : UInt128, count : Int32) : Bool

True when magnitude shifted left by count bits still fits in 128 bits.

Source
fraction_digits(fraction : UInt128, fraction_bits : Int32) : Array(UInt8)

The exact decimal digits of fraction / 2**fraction_bits (which is below one), without trailing zeros. There are at most fraction_bits.

Source
int_sign_magnitude(value : Int) : Tuple(Bool, UInt128)

The magnitude of an integer, as {negative, magnitude}.

Source
mask(count : Int32) : UInt128

The low count bits set, for count in 0..128.

Source
mul_shift(left : UInt128, right : UInt128, fraction_bits : Int32) : UInt128 | Nil

left * right / 2**fraction_bits, rounded half-to-even; nil on overflow.

Source
mul_wide(left : UInt128, right : UInt128) : Tuple(UInt128, UInt128)

Full 256-bit product of two 128-bit values, as {high, low}.

Source
parse_decimal(input : String, whitespace : Bool = true) : ParsedDecimal | Nil

Parses [+-]digits[.digits][e[+-]digits], where either run of mantissa digits may be empty (but not both) and single underscores may separate digits. Returns nil if the syntax is invalid.

Source
rescale(magnitude : UInt128, from_bits : Int32, to_bits : Int32) : UInt128 | Nil

Rescales magnitude from from_bits to to_bits fraction bits, rounding half-to-even; nil on overflow.

Source
round_digits(integer : UInt128, digits : Array(UInt8), count : Int32) : Tuple(UInt128, Array(UInt8))

Rounds integer.digits to exactly count fraction digits, half-to-even, returning the new integer part and digits.

Source
round_half_even(value : UInt128, guard : Bool, sticky : Bool) : UInt128 | Nil

Adds one to value when the discarded bits call for it under round-half-to-even. Returns nil if that overflows.

Source
scale_float(mantissa : UInt64, exponent : Int32, fraction_bits : Int32) : UInt128 | Nil

mantissa * 2**(exponent + fraction_bits) rounded half-to-even; nil on overflow.

Source
shift_right_round(high : UInt128, low : UInt128, count : Int32) : UInt128 | Nil

The 256-bit value high:low shifted right by count (0..128) bits, rounded half-to-even. Returns nil if the result needs more than 128 bits.

Source
shortest_digits(magnitude : UInt128, fraction_bits : Int32) : Tuple(UInt128, Array(UInt8))

The shortest decimal expansion of magnitude / 2**fraction_bits that parses back to exactly magnitude, as {integer, fraction_digits}.

A candidate parses back to magnitude when its distance from the exact value is below half a unit in the last place, or equal to it when magnitude is even, since ties round to even. For each length, the nearest candidate is the exact expansion rounded to that length, and its distance is either the dropped tail or the tail's complement.

Source
to_float32(negative : Bool, magnitude : UInt128, fraction_bits : Int32) : Float32

Converts magnitude / 2**fraction_bits to the nearest Float32, rounding half-to-even (including into the subnormal range). Returns infinity when the value is out of range.

Source
to_float64(negative : Bool, magnitude : UInt128, fraction_bits : Int32) : Float64

Converts magnitude / 2**fraction_bits to the nearest Float64, rounding half-to-even (including into the subnormal range). Returns infinity when the value is out of range.

Source
write_decimal(io : IO, magnitude : UInt128, fraction_bits : Int32, precision : Int32 | Nil, alternate : Bool = false) : Nil

Writes magnitude / 2**fraction_bits in decimal. With precision, exactly that many fraction digits (rounded half-to-even); without it, the shortest round-tripping form, which always has at least one fraction digit unless fraction_bits is zero.

Source
write_formatted(io : IO, negative : Bool, magnitude : UInt128, fraction_bits : Int32, *, width : Int32 | Nil, precision : Int32 | Nil, padding : Char, left_justify : Bool = false, plus_sign : Bool = false, space_sign : Bool = false, alternate : Bool = false) : Nil

Writes a fully formatted, padded number; see Fixed#format.

Source
write_spec(io : IO, negative : Bool, magnitude : UInt128, fraction_bits : Int32, spec : String) : Nil

Parses a sprintf-style spec such as "%+08.3f" and writes the value.

Source

Nested types