Source File
dtoa.go
Belonging Package
github.com/dop251/goja/ftoa/internal/fast
package fastimport ()const (kMinimalTargetExponent = -60kMaximalTargetExponent = -32kTen4 = 10000kTen5 = 100000kTen6 = 1000000kTen7 = 10000000kTen8 = 100000000kTen9 = 1000000000)type Mode intconst (ModeShortest Mode = iotaModePrecision)// 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 containing the digits of too_high / 10^kappa// - distance_too_high_w == (too_high - w).f() * unit// - unsafe_interval == (too_high - too_low).f() * unit// - rest = (too_high - buffer * 10^kappa).f() * unit// - ten_kappa = 10^kappa * unit// - unit = the common multiplier//// 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.func roundWeed( []byte, , , , , uint64) bool {:= -:= +// Let w_low = too_high - big_distance, and// w_high = too_high - small_distance.// Note: w_low < w < w_high//// The real w (* unit) must lie somewhere inside the interval// ]w_low; w_high[ (often written as "(w_low; w_high)")// Basically the buffer currently contains a number in the unsafe interval// ]too_low; too_high[ with too_low < w < too_high//// too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// ^v 1 unit ^ ^ ^ ^// boundary_high --------------------- . . . .// ^v 1 unit . . . .// - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .// . . ^ . .// . big_distance . . .// . . . . rest// small_distance . . . .// v . . . .// w_high - - - - - - - - - - - - - - - - - - . . . .// ^v 1 unit . . . .// w ---------------------------------------- . . . .// ^v 1 unit v . . .// w_low - - - - - - - - - - - - - - - - - - - - - . . .// . . v// buffer --------------------------------------------------+-------+--------// . .// safe_interval .// v .// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .// ^v 1 unit .// boundary_low ------------------------- unsafe_interval// ^v 1 unit v// too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -////// Note that the value of buffer could lie anywhere inside the range too_low// to too_high.//// boundary_low, boundary_high and w are approximations of the real boundaries// and v (the input number). They are guaranteed to be precise up to one unit.// In fact the error is guaranteed to be strictly less than one unit.//// Anything that lies outside the unsafe interval is guaranteed not to round// to v when read again.// Anything that lies inside the safe interval is guaranteed to round to v// when read again.// If the number inside the buffer lies inside the unsafe interval but not// inside the safe interval then we simply do not know and bail out (returning// false).//// Similarly we have to take into account the imprecision of 'w' when finding// the closest representation of 'w'. If we have two potential// representations, and one is closer to both w_low and w_high, then we know// it is closer to the actual value v.//// By generating the digits of too_high we got the largest (closest to// too_high) buffer that is still in the unsafe interval. In the case where// w_high < buffer < too_high we try to decrement the buffer.// This way the buffer approaches (rounds towards) w.// There are 3 conditions that stop the decrementation process:// 1) the buffer is already below w_high// 2) decrementing the buffer would make it leave the unsafe interval// 3) decrementing the buffer would yield a number below w_high and farther// away than the current number. In other words:// (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high// Instead of using the buffer directly we use its distance to too_high.// Conceptually rest ~= too_high - buffer// We need to do the following tests in this order to avoid over- and// underflows._DCHECK( <= )for < && // Negated condition 1- >= && // Negated condition 2(+ < || // buffer{-1} > w_high- >= +-) {[len()-1]--+=}// We have approached w+ as much as possible. We now test if approaching w-// would require changing the buffer. If yes, then we have two possible// representations close to w, but we cannot decide which one is closer.if < && - >= &&(+ < ||- > +-) {return false}// Weeding test.// The safe interval is [too_low + 2 ulp; too_high - 2 ulp]// Since too_low = too_high - unsafe_interval this is equivalent to// [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]// Conceptually we have: rest ~= too_high - bufferreturn (2* <= ) && ( <= -4*)}// Rounds the buffer upwards if the result is closer to v by possibly adding// 1 to the buffer. If the precision of the calculation is not sufficient to// round correctly, return false.// The rounding might shift the whole buffer in which case the kappa is// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.//// If 2*rest > ten_kappa then the buffer needs to be round up.// rest can have an error of +/- 1 unit. This function accounts for the// imprecision and returns false, if the rounding direction cannot be// unambiguously determined.//// Precondition: rest < ten_kappa.func roundWeedCounted( []byte, , , uint64, *int) bool {_DCHECK( < )// The following tests are done in a specific order to avoid overflows. They// will work correctly with any uint64 values of rest < ten_kappa and unit.//// If the unit is too big, then we don't know which way to round. For example// a unit of 50 means that the real number lies within rest +/- 50. If// 10^kappa == 40 then there is no way to tell which way to round.if >= {return false}// Even if unit is just half the size of 10^kappa we are already completely// lost. (And after the previous test we know that the expression will not// over/underflow.)if - <= {return false}// If 2 * (rest + unit) <= 10^kappa we can safely round down.if (- > ) && (-2* >= 2*) {return true}// If 2 * (rest - unit) >= 10^kappa, then we can safely round up.if ( > ) && (-(-) <= ( - )) {// Increment the last digit recursively until we find a non '9' digit.[len()-1]++for := len() - 1; > 0; -- {if [] != '0'+10 {break}[] = '0'[-1]++}// If the first digit is now '0'+ 10 we had a buffer with all '9's. With the// exception of the first digit all digits are now '0'. Simply switch the// first digit to '1' and adjust the kappa. Example: "99" becomes "10" and// the power (the kappa) is increased.if [0] == '0'+10 {[0] = '1'* += 1}return true}return false}// Returns the biggest power of ten that is less than or equal than the given// number. We furthermore receive the maximum number of bits 'number' has.// If number_bits == 0 then 0^-1 is returned// The number of bits must be <= 32.// Precondition: number < (1 << (number_bits + 1)).func biggestPowerTen( uint32, int) ( uint32, int) {switch {case 32, 31, 30:if kTen9 <= {= kTen9= 9break}fallthroughcase 29, 28, 27:if kTen8 <= {= kTen8= 8break}fallthroughcase 26, 25, 24:if kTen7 <= {= kTen7= 7break}fallthroughcase 23, 22, 21, 20:if kTen6 <= {= kTen6= 6break}fallthroughcase 19, 18, 17:if kTen5 <= {= kTen5= 5break}fallthroughcase 16, 15, 14:if kTen4 <= {= kTen4= 4break}fallthroughcase 13, 12, 11, 10:if 1000 <= {= 1000= 3break}fallthroughcase 9, 8, 7:if 100 <= {= 100= 2break}fallthroughcase 6, 5, 4:if 10 <= {= 10= 1break}fallthroughcase 3, 2, 1:if 1 <= {= 1= 0break}fallthroughcase 0:= 0= -1}return}// 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.func digitGen(, , diyfp, []byte) ( int, []byte, bool) {_DCHECK(.e == .e && .e == .e)_DCHECK(.f+1 <= .f-1)_DCHECK(kMinimalTargetExponent <= .e && .e <= kMaximalTargetExponent)// low, w and high are imprecise, but by less than one ulp (unit in the last// place).// If we remove (resp. add) 1 ulp from low (resp. high) we are certain that// the new numbers are outside of the interval we want the final// representation to lie in.// Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield// numbers that are certain to lie in the interval. We will use this fact// later on.// We will now start by generating the digits within the uncertain// interval. Later we will weed out representations that lie outside the safe// interval and thus _might_ lie outside the correct interval.:= uint64(1):= diyfp{f: .f - , e: .e}:= diyfp{f: .f + , e: .e}// too_low and too_high are guaranteed to lie outside the interval we want the// generated number in.:= .minus()// We now cut the input number into two parts: the integral digits and the// fractionals. We will not write any decimal separator though, but adapt// kappa instead.// Reminder: we are currently computing the digits (stored inside the buffer)// such that: too_low < buffer * 10^kappa < too_high// We use too_high for the digit_generation and stop as soon as possible.// If we stop early we effectively round down.:= diyfp{f: 1 << -.e, e: .e}// Division by one is a shift.:= uint32(.f >> -.e)// Modulo by one is an and.:= .f & (.f - 1), := biggestPowerTen(, diyFpKSignificandSize-(-.e))= + 1=for > 0 {:= int( / )= append(, byte('0'+))%=--// Note that kappa now equals the exponent of the divisor and that the// invariant thus holds again.:= uint64()<<-.e +// Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e)// Reminder: unsafe_interval.e == one.eif < .f {// Rounding down (by not emitting the remaining digits) yields a number// that lies within the unsafe interval.= roundWeed(, .minus().f,.f, ,uint64()<<-.e, )return}/= 10}// The integrals have been generated. We are at the point of the decimal// separator. In the following loop we simply multiply the remaining digits by// 10 and divide by one. We just need to pay attention to multiply associated// data (like the interval or 'unit'), too.// Note that the multiplication by 10 does not overflow, because w.e >= -60// and thus one.e >= -60._DCHECK(.e >= -60)_DCHECK( < .f)_DCHECK(0xFFFFFFFFFFFFFFFF/10 >= .f)for {*= 10*= 10.f *= 10// Integer division by one.:= byte( >> -.e)= append(, '0'+)&= .f - 1 // Modulo by one.--if < .f {= roundWeed(, .minus().f*, .f, , .f, )return}}}// Generates (at most) requested_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:// - w is correct up to 1 ulp (unit in the last place). That// is, its error must be strictly less than a unit of its last digit.// - kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent//// Postconditions: returns false if procedure fails.//// otherwise:// * buffer is not null-terminated, but length contains the number of// digits.// * the representation in buffer is the most precise representation of// requested_digits digits.// * buffer contains at most requested_digits digits of w. If there are less// than requested_digits digits then some trailing '0's have been removed.// * kappa is such that// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.//// 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, but the failure-rate// increases with higher requested_digits.func digitGenCounted( diyfp, int, []byte) ( int, []byte, bool) {_DCHECK(kMinimalTargetExponent <= .e && .e <= kMaximalTargetExponent)// w is assumed to have an error less than 1 unit. Whenever w is scaled we// also scale its error.:= uint64(1)// We cut the input number into two parts: the integral digits and the// fractional digits. We don't emit any decimal separator, but adapt kappa// instead. Example: instead of writing "1.2" we put "12" into the buffer and// increase kappa by 1.:= diyfp{f: 1 << -.e, e: .e}// Division by one is a shift.:= uint32(.f >> -.e)// Modulo by one is an and.:= .f & (.f - 1), := biggestPowerTen(, diyFpKSignificandSize-(-.e))= + 1=// Loop invariant: buffer = w / 10^kappa (integer division)// The invariant holds for the first iteration: kappa has been initialized// with the divisor exponent + 1. And the divisor is the biggest power of ten// that is smaller than 'integrals'.for > 0 {:= byte( / )= append(, '0'+)--%=--// Note that kappa now equals the exponent of the divisor and that the// invariant thus holds again.if == 0 {break}/= 10}if == 0 {:= uint64()<<-.e += roundWeedCounted(, , uint64()<<-.e, , &)return}// The integrals have been generated. We are at the point of the decimal// separator. In the following loop we simply multiply the remaining digits by// 10 and divide by one. We just need to pay attention to multiply associated// data (the 'unit'), too.// Note that the multiplication by 10 does not overflow, because w.e >= -60// and thus one.e >= -60._DCHECK(.e >= -60)_DCHECK( < .f)_DCHECK(0xFFFFFFFFFFFFFFFF/10 >= .f)for > 0 && > {*= 10*= 10// Integer division by one.:= byte( >> -.e)= append(, '0'+)--&= .f - 1 // Modulo by one.--}if != 0 {= false} else {= roundWeedCounted(, , .f, , &)}return}// Provides a decimal representation of v.// Returns 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 true then//// v == (double) (buffer * 10^decimal_exponent).//// The digits in the buffer are the shortest representation possible: no// 0.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.func grisu3( float64, []byte) ( []byte, int, bool) {:= double():= .toNormalizedDiyfp()// boundary_minus and boundary_plus are the boundaries between v and its// closest floating-point neighbors. Any number strictly between// boundary_minus and boundary_plus will round to v when convert to a double.// Grisu3 will never output representations that lie exactly on a boundary., := .normalizedBoundaries():= kMinimalTargetExponent - (.e + diyFpKSignificandSize):= kMaximalTargetExponent - (.e + diyFpKSignificandSize), := getCachedPowerForBinaryExponentRange(, )_DCHECK((kMinimalTargetExponent <=.e+.e+diyFpKSignificandSize) &&(kMaximalTargetExponent >= .e+.e+diyFpKSignificandSize))// Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a// 64 bit significand and ten_mk is thus only precise up to 64 bits.// The DiyFp::Times procedure rounds its result, and ten_mk is approximated// too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now// off by a small amount.// In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.// In other words: let f = scaled_w.f() and e = scaled_w.e(), then// (f-1) * 2^e < w*10^k < (f+1) * 2^e:= .times()_DCHECK(.e ==.e+.e+diyFpKSignificandSize)// In theory it would be possible to avoid some recomputations by computing// the difference between w and boundary_minus/plus (a power of 2) and to// compute scaled_boundary_minus/plus by subtracting/adding from// scaled_w. However the code becomes much less readable and the speed// enhancements are not terrific.:= .times():= .times()// DigitGen will generate the digits of scaled_w. Therefore we have// v == (double) (scaled_w * 10^-mk).// Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an// integer than it will be updated. For instance if scaled_w == 1.23 then// the buffer will be filled with "123" und the decimal_exponent will be// decreased by 2.var int, , = digitGen(, , , )= - +return}// The "counted" version of grisu3 (see above) only generates requested_digits// number of digits. This version does not generate the shortest representation,// and with enough requested digits 0.1 will at some point print as 0.9999999...// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and// therefore the rounding strategy for halfway cases is irrelevant.func grisu3Counted( float64, int, []byte) ( []byte, int, bool) {:= double().toNormalizedDiyfp():= kMinimalTargetExponent - (.e + diyFpKSignificandSize):= kMaximalTargetExponent - (.e + diyFpKSignificandSize), := getCachedPowerForBinaryExponentRange(, )_DCHECK((kMinimalTargetExponent <=.e+.e+diyFpKSignificandSize) &&(kMaximalTargetExponent >= .e+.e+diyFpKSignificandSize))// Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a// 64 bit significand and ten_mk is thus only precise up to 64 bits.// The DiyFp::Times procedure rounds its result, and ten_mk is approximated// too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now// off by a small amount.// In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.// In other words: let f = scaled_w.f() and e = scaled_w.e(), then// (f-1) * 2^e < w*10^k < (f+1) * 2^e:= .times()// We now have (double) (scaled_w * 10^-mk).// DigitGen will generate the first requested_digits digits of scaled_w and// return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It// will not always be exactly the same since DigitGenCounted only produces a// limited number of digits.)var int, , = digitGenCounted(, , )= - +return}// v must be > 0 and must not be Inf or NaNfunc ( float64, Mode, int, []byte) ( []byte, int, bool) {defer func() {if := recover(); != nil {if == dcheckFailure {panic(fmt.Errorf("DCHECK assertion failed while formatting %s in mode %d", strconv.FormatFloat(, 'e', 50, 64), ))}panic()}}()var int:= len()switch {case ModeShortest:, , = grisu3(, )case ModePrecision:, , = grisu3Counted(, , )}if {= len() - +} else {= [:]}return}
![]() |
The pages are generated with Golds v0.8.2. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |