module Float::Printer::Grisu3

Extended Modules

Defined in:

float/printer/grisu3.cr

Instance Method Summary

Instance Method Detail

def digit_gen(low : DiyFP, w : DiyFP, high : DiyFP, buffer_p) : Tuple(Bool, Int32, Int32) #

Generates the digits of input number w. w is a floating-point number (DiyFp), consisting of a significand and an exponent. Its exponent is bounded by kMinimalTargetExponent and kMaximalTargetExponent.

  Hence -60 <= w.e() <= -32.

Returns false if it fails, in which case the generated digits in the buffer should not be used. Preconditions:

  • low, w and high are correct up to 1 ulp (unit in the last place). That is, their error must be less than a unit of their last digits.
  • low.e() == w.e() == high.e()
  • low < w < high, and taking into account their error: low~ <= high~
  • kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent Postconditions: returns false if procedure fails. otherwise:
    • buffer is not null-terminated, but len contains the number of digits.
    • buffer contains the shortest possible decimal digit-sequence
      such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
      correct values of low and high (without their error).
    * if more than one decimal representation gives the minimal number of
      decimal digits then the one closest to W (where W is the correct value
      of w) is chosen.

    Remark: this procedure takes into account the imprecision of its input numbers. If the precision is not enough to guarantee all the postconditions then false is returned. This usually happens rarely (~0.5%).

    Say, for the sake of example, that w.e() == -48, and w.f() == 0x1234567890abcdef w's value can be computed by w.f() * 2^w.e() We can obtain w's integral digits by simply shifting w.f() by -w.e(). -> w's integral part is 0x1234 w's fractional part is therefore 0x567890abcdef. Printing w's integral part is easy (simply print 0x1234 in decimal). In order to print its fraction we repeatedly multiply the fraction by 10 and get each digit. Example the first digit after the point would be computed by (0x567890abcdef * 10) >> 48. -> 3 The whole thing becomes slightly more complicated because we want to stop once we have enough digits. That is, once the digits inside the buffer represent 'w' we can stop. Everything inside the interval low - high represents w. However we have to pay attention to low, high and w's imprecision.


View source
def grisu3(v : Float64 | Float32, buffer_p) : Tuple(Bool, Int32, Int32) #

Provides a decimal representation of v.

Returns a Tuple of {status, decimal_exponent, length} status will be true if it succeeds, otherwise the result cannot be trusted. There will be length digits inside the buffer (not null-terminated). If the function returns satatus as true true then

   v == (buffer * 10^decimal_exponent).to_f

The digits in the buffer are the shortest representation possible: no

  1. 09999999999999999 instead of 0.1. The shorter representation will even be chosen even if the longer one would be closer to v. The last digit will be closest to the actual v. That is, even if several digits might correctly yield v when read again, the closest will be computed.

View source
def round_weed(buffer_p, length, distance_too_high_w, unsafe_interval, rest, ten_kappa, unit) #

Adjusts the last digit of the generated number, and screens out generated solutions that may be inaccurate. A solution may be inaccurate if it is outside the safe interval, or if we cannot prove that it is closer to the input than a neighboring representation of the same length.

Input: * buffer pointer containing the digits of too_high / 10^kappa

   * the buffer

Output: returns true if the buffer is guaranteed to contain the closest representable number to the input. Modifies the generated digits in the buffer to approach (round towards) w.


View source