123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- package ftoa
- import (
- "math"
- "math/big"
- )
- const (
- exp_11 = 0x3ff00000
- frac_mask1 = 0xfffff
- bletch = 0x10
- quick_max = 14
- int_max = 14
- )
- var (
- tens = [...]float64{
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
- 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
- 1e20, 1e21, 1e22,
- }
- bigtens = [...]float64{1e16, 1e32, 1e64, 1e128, 1e256}
- big5 = big.NewInt(5)
- big10 = big.NewInt(10)
- p05 = []*big.Int{big5, big.NewInt(25), big.NewInt(125)}
- pow5Cache [7]*big.Int
- dtoaModes = []int{
- ModeStandard: 0,
- ModeStandardExponential: 0,
- ModeFixed: 3,
- ModeExponential: 2,
- ModePrecision: 2,
- }
- )
- /*
- d must be > 0 and must not be Inf
- mode:
- 0 ==> shortest string that yields d when read in
- and rounded to nearest.
- 1 ==> like 0, but with Steele & White stopping rule;
- e.g. with IEEE P754 arithmetic , mode 0 gives
- 1e23 whereas mode 1 gives 9.999999999999999e22.
- 2 ==> max(1,ndigits) significant digits. This gives a
- return value similar to that of ecvt, except
- that trailing zeros are suppressed.
- 3 ==> through ndigits past the decimal point. This
- gives a return value similar to that from fcvt,
- except that trailing zeros are suppressed, and
- ndigits can be negative.
- 4,5 ==> similar to 2 and 3, respectively, but (in
- round-nearest mode) with the tests of mode 0 to
- possibly return a shorter string that rounds to d.
- With IEEE arithmetic and compilation with
- -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
- as modes 2 and 3 when FLT_ROUNDS != 1.
- 6-9 ==> Debugging modes similar to mode - 4: don't try
- fast floating-point estimate (if applicable).
- Values of mode other than 0-9 are treated as mode 0.
- */
- func ftoa(d float64, mode int, biasUp bool, ndigits int, buf []byte) ([]byte, int) {
- startPos := len(buf)
- dblBits := make([]byte, 0, 8)
- be, bbits, dblBits := d2b(d, dblBits)
- dBits := math.Float64bits(d)
- word0 := uint32(dBits >> 32)
- word1 := uint32(dBits)
- i := int((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
- var d2 float64
- var denorm bool
- if i != 0 {
- d2 = setWord0(d, (word0&frac_mask1)|exp_11)
- i -= bias
- denorm = false
- } else {
- /* d is denormalized */
- i = bbits + be + (bias + (p - 1) - 1)
- var x uint64
- if i > 32 {
- x = uint64(word0)<<(64-i) | uint64(word1)>>(i-32)
- } else {
- x = uint64(word1) << (32 - i)
- }
- d2 = setWord0(float64(x), uint32((x>>32)-31*exp_mask))
- i -= (bias + (p - 1) - 1) + 1
- denorm = true
- }
- /* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */
- ds := (d2-1.5)*0.289529654602168 + 0.1760912590558 + float64(i)*0.301029995663981
- k := int(ds)
- if ds < 0.0 && ds != float64(k) {
- k-- /* want k = floor(ds) */
- }
- k_check := true
- if k >= 0 && k < len(tens) {
- if d < tens[k] {
- k--
- }
- k_check = false
- }
- /* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
- If k_check is zero, we're guaranteed that k = floor(log10(d)). */
- j := bbits - i - 1
- var b2, s2, b5, s5 int
- /* At this point d = b/2^j, where b is an odd integer. */
- if j >= 0 {
- b2 = 0
- s2 = j
- } else {
- b2 = -j
- s2 = 0
- }
- if k >= 0 {
- b5 = 0
- s5 = k
- s2 += k
- } else {
- b2 -= k
- b5 = -k
- s5 = 0
- }
- /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
- b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
- if mode < 0 || mode > 9 {
- mode = 0
- }
- try_quick := true
- if mode > 5 {
- mode -= 4
- try_quick = false
- }
- leftright := true
- var ilim, ilim1 int
- switch mode {
- case 0, 1:
- ilim, ilim1 = -1, -1
- ndigits = 0
- case 2:
- leftright = false
- fallthrough
- case 4:
- if ndigits <= 0 {
- ndigits = 1
- }
- ilim, ilim1 = ndigits, ndigits
- case 3:
- leftright = false
- fallthrough
- case 5:
- i = ndigits + k + 1
- ilim = i
- ilim1 = i - 1
- }
- /* ilim is the maximum number of significant digits we want, based on k and ndigits. */
- /* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
- when it turns out that k was computed too high by one. */
- fast_failed := false
- if ilim >= 0 && ilim <= quick_max && try_quick {
- /* Try to get by with floating-point arithmetic. */
- i = 0
- d2 = d
- k0 := k
- ilim0 := ilim
- ieps := 2 /* conservative */
- /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
- if k > 0 {
- ds = tens[k&0xf]
- j = k >> 4
- if (j & bletch) != 0 {
- /* prevent overflows */
- j &= bletch - 1
- d /= bigtens[len(bigtens)-1]
- ieps++
- }
- for ; j != 0; i++ {
- if (j & 1) != 0 {
- ieps++
- ds *= bigtens[i]
- }
- j >>= 1
- }
- d /= ds
- } else if j1 := -k; j1 != 0 {
- d *= tens[j1&0xf]
- for j = j1 >> 4; j != 0; i++ {
- if (j & 1) != 0 {
- ieps++
- d *= bigtens[i]
- }
- j >>= 1
- }
- }
- /* Check that k was computed correctly. */
- if k_check && d < 1.0 && ilim > 0 {
- if ilim1 <= 0 {
- fast_failed = true
- } else {
- ilim = ilim1
- k--
- d *= 10.
- ieps++
- }
- }
- /* eps bounds the cumulative error. */
- eps := float64(ieps)*d + 7.0
- eps = setWord0(eps, _word0(eps)-(p-1)*exp_msk1)
- if ilim == 0 {
- d -= 5.0
- if d > eps {
- buf = append(buf, '1')
- k++
- return buf, k + 1
- }
- if d < -eps {
- buf = append(buf, '0')
- return buf, 1
- }
- fast_failed = true
- }
- if !fast_failed {
- fast_failed = true
- if leftright {
- /* Use Steele & White method of only
- * generating digits needed.
- */
- eps = 0.5/tens[ilim-1] - eps
- for i = 0; ; {
- l := int64(d)
- d -= float64(l)
- buf = append(buf, byte('0'+l))
- if d < eps {
- return buf, k + 1
- }
- if 1.0-d < eps {
- buf, k = bumpUp(buf, k)
- return buf, k + 1
- }
- i++
- if i >= ilim {
- break
- }
- eps *= 10.0
- d *= 10.0
- }
- } else {
- /* Generate ilim digits, then fix them up. */
- eps *= tens[ilim-1]
- for i = 1; ; i++ {
- l := int64(d)
- d -= float64(l)
- buf = append(buf, byte('0'+l))
- if i == ilim {
- if d > 0.5+eps {
- buf, k = bumpUp(buf, k)
- return buf, k + 1
- } else if d < 0.5-eps {
- buf = stripTrailingZeroes(buf, startPos)
- return buf, k + 1
- }
- break
- }
- d *= 10.0
- }
- }
- }
- if fast_failed {
- buf = buf[:startPos]
- d = d2
- k = k0
- ilim = ilim0
- }
- }
- /* Do we have a "small" integer? */
- if be >= 0 && k <= int_max {
- /* Yes. */
- ds = tens[k]
- if ndigits < 0 && ilim <= 0 {
- if ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds) {
- buf = buf[:startPos]
- buf = append(buf, '0')
- return buf, 1
- }
- buf = append(buf, '1')
- k++
- return buf, k + 1
- }
- for i = 1; ; i++ {
- l := int64(d / ds)
- d -= float64(l) * ds
- buf = append(buf, byte('0'+l))
- if i == ilim {
- d += d
- if (d > ds) || (d == ds && (((l & 1) != 0) || biasUp)) {
- buf, k = bumpUp(buf, k)
- }
- break
- }
- d *= 10.0
- if d == 0 {
- break
- }
- }
- return buf, k + 1
- }
- m2 := b2
- m5 := b5
- var mhi, mlo *big.Int
- if leftright {
- if mode < 2 {
- if denorm {
- i = be + (bias + (p - 1) - 1 + 1)
- } else {
- i = 1 + p - bbits
- }
- /* i is 1 plus the number of trailing zero bits in d's significand. Thus,
- (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
- } else {
- j = ilim - 1
- if m5 >= j {
- m5 -= j
- } else {
- j -= m5
- s5 += j
- b5 += j
- m5 = 0
- }
- i = ilim
- if i < 0 {
- m2 -= i
- i = 0
- }
- /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
- }
- b2 += i
- s2 += i
- mhi = big.NewInt(1)
- /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
- input (when mode < 2) significant digit, divided by 10^k. */
- }
- /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in
- b2, m2, and s2 without changing the equalities. */
- if m2 > 0 && s2 > 0 {
- if m2 < s2 {
- i = m2
- } else {
- i = s2
- }
- b2 -= i
- m2 -= i
- s2 -= i
- }
- b := new(big.Int).SetBytes(dblBits)
- /* Fold b5 into b and m5 into mhi. */
- if b5 > 0 {
- if leftright {
- if m5 > 0 {
- pow5mult(mhi, m5)
- b.Mul(mhi, b)
- }
- j = b5 - m5
- if j != 0 {
- pow5mult(b, j)
- }
- } else {
- pow5mult(b, b5)
- }
- }
- /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
- (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */
- S := big.NewInt(1)
- if s5 > 0 {
- pow5mult(S, s5)
- }
- /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
- (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */
- /* Check for special case that d is a normalized power of 2. */
- spec_case := false
- if mode < 2 {
- if (_word1(d) == 0) && ((_word0(d) & bndry_mask) == 0) &&
- ((_word0(d) & (exp_mask & (exp_mask << 1))) != 0) {
- /* The special case. Here we want to be within a quarter of the last input
- significant digit instead of one half of it when the decimal output string's value is less than d. */
- b2 += log2P
- s2 += log2P
- spec_case = true
- }
- }
- /* Arrange for convenient computation of quotients:
- * shift left if necessary so divisor has 4 leading 0 bits.
- *
- * Perhaps we should just compute leading 28 bits of S once
- * and for all and pass them and a shift to quorem, so it
- * can do shifts and ors to compute the numerator for q.
- */
- var zz int
- if s5 != 0 {
- S_bytes := S.Bytes()
- var S_hiWord uint32
- for idx := 0; idx < 4; idx++ {
- S_hiWord = S_hiWord << 8
- if idx < len(S_bytes) {
- S_hiWord |= uint32(S_bytes[idx])
- }
- }
- zz = 32 - hi0bits(S_hiWord)
- } else {
- zz = 1
- }
- i = (zz + s2) & 0x1f
- if i != 0 {
- i = 32 - i
- }
- /* i is the number of leading zero bits in the most significant word of S*2^s2. */
- if i > 4 {
- i -= 4
- b2 += i
- m2 += i
- s2 += i
- } else if i < 4 {
- i += 28
- b2 += i
- m2 += i
- s2 += i
- }
- /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
- if b2 > 0 {
- b = b.Lsh(b, uint(b2))
- }
- if s2 > 0 {
- S.Lsh(S, uint(s2))
- }
- /* Now we have d/10^k = b/S and
- (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
- if k_check {
- if b.Cmp(S) < 0 {
- k--
- b.Mul(b, big10) /* we botched the k estimate */
- if leftright {
- mhi.Mul(mhi, big10)
- }
- ilim = ilim1
- }
- }
- /* At this point 1 <= d/10^k = b/S < 10. */
- if ilim <= 0 && mode > 2 {
- /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
- Output either zero or the minimum nonzero output depending on which is closer to d. */
- if ilim >= 0 {
- i = b.Cmp(S.Mul(S, big5))
- }
- if ilim < 0 || i < 0 || i == 0 && !biasUp {
- /* Always emit at least one digit. If the number appears to be zero
- using the current mode, then emit one '0' digit and set decpt to 1. */
- buf = buf[:startPos]
- buf = append(buf, '0')
- return buf, 1
- }
- buf = append(buf, '1')
- k++
- return buf, k + 1
- }
- var dig byte
- if leftright {
- if m2 > 0 {
- mhi.Lsh(mhi, uint(m2))
- }
- /* Compute mlo -- check for special case
- * that d is a normalized power of 2.
- */
- mlo = mhi
- if spec_case {
- mhi = mlo
- mhi = new(big.Int).Lsh(mhi, log2P)
- }
- /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
- /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */
- var z, delta big.Int
- for i = 1; ; i++ {
- z.DivMod(b, S, b)
- dig = byte(z.Int64() + '0')
- /* Do we yet have the shortest decimal string
- * that will round to d?
- */
- j = b.Cmp(mlo)
- /* j is b/S compared with mlo/S. */
- delta.Sub(S, mhi)
- var j1 int
- if delta.Sign() <= 0 {
- j1 = 1
- } else {
- j1 = b.Cmp(&delta)
- }
- /* j1 is b/S compared with 1 - mhi/S. */
- if (j1 == 0) && (mode == 0) && ((_word1(d) & 1) == 0) {
- if dig == '9' {
- var flag bool
- buf = append(buf, '9')
- if buf, flag = roundOff(buf, startPos); flag {
- k++
- buf = append(buf, '1')
- }
- return buf, k + 1
- }
- if j > 0 {
- dig++
- }
- buf = append(buf, dig)
- return buf, k + 1
- }
- if (j < 0) || ((j == 0) && (mode == 0) && ((_word1(d) & 1) == 0)) {
- if j1 > 0 {
- /* Either dig or dig+1 would work here as the least significant decimal digit.
- Use whichever would produce a decimal value closer to d. */
- b.Lsh(b, 1)
- j1 = b.Cmp(S)
- if (j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)) {
- dig++
- if dig == '9' {
- buf = append(buf, '9')
- buf, flag := roundOff(buf, startPos)
- if flag {
- k++
- buf = append(buf, '1')
- }
- return buf, k + 1
- }
- }
- }
- buf = append(buf, dig)
- return buf, k + 1
- }
- if j1 > 0 {
- if dig == '9' { /* possible if i == 1 */
- buf = append(buf, '9')
- buf, flag := roundOff(buf, startPos)
- if flag {
- k++
- buf = append(buf, '1')
- }
- return buf, k + 1
- }
- buf = append(buf, dig+1)
- return buf, k + 1
- }
- buf = append(buf, dig)
- if i == ilim {
- break
- }
- b.Mul(b, big10)
- if mlo == mhi {
- mhi.Mul(mhi, big10)
- } else {
- mlo.Mul(mlo, big10)
- mhi.Mul(mhi, big10)
- }
- }
- } else {
- var z big.Int
- for i = 1; ; i++ {
- z.DivMod(b, S, b)
- dig = byte(z.Int64() + '0')
- buf = append(buf, dig)
- if i >= ilim {
- break
- }
- b.Mul(b, big10)
- }
- }
- /* Round off last digit */
- b.Lsh(b, 1)
- j = b.Cmp(S)
- if (j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp)) {
- var flag bool
- buf, flag = roundOff(buf, startPos)
- if flag {
- k++
- buf = append(buf, '1')
- return buf, k + 1
- }
- } else {
- buf = stripTrailingZeroes(buf, startPos)
- }
- return buf, k + 1
- }
- func bumpUp(buf []byte, k int) ([]byte, int) {
- var lastCh byte
- stop := 0
- if len(buf) > 0 && buf[0] == '-' {
- stop = 1
- }
- for {
- lastCh = buf[len(buf)-1]
- buf = buf[:len(buf)-1]
- if lastCh != '9' {
- break
- }
- if len(buf) == stop {
- k++
- lastCh = '0'
- break
- }
- }
- buf = append(buf, lastCh+1)
- return buf, k
- }
- func setWord0(d float64, w uint32) float64 {
- dBits := math.Float64bits(d)
- return math.Float64frombits(uint64(w)<<32 | dBits&0xffffffff)
- }
- func _word0(d float64) uint32 {
- dBits := math.Float64bits(d)
- return uint32(dBits >> 32)
- }
- func _word1(d float64) uint32 {
- dBits := math.Float64bits(d)
- return uint32(dBits)
- }
- func stripTrailingZeroes(buf []byte, startPos int) []byte {
- bl := len(buf) - 1
- for bl >= startPos && buf[bl] == '0' {
- bl--
- }
- return buf[:bl+1]
- }
- /* Set b = b * 5^k. k must be nonnegative. */
- func pow5mult(b *big.Int, k int) *big.Int {
- if k < (1 << (len(pow5Cache) + 2)) {
- i := k & 3
- if i != 0 {
- b.Mul(b, p05[i-1])
- }
- k >>= 2
- i = 0
- for {
- if k&1 != 0 {
- b.Mul(b, pow5Cache[i])
- }
- k >>= 1
- if k == 0 {
- break
- }
- i++
- }
- return b
- }
- return b.Mul(b, new(big.Int).Exp(big5, big.NewInt(int64(k)), nil))
- }
- func roundOff(buf []byte, startPos int) ([]byte, bool) {
- i := len(buf)
- for i != startPos {
- i--
- if buf[i] != '9' {
- buf[i]++
- return buf[:i+1], false
- }
- }
- return buf[:startPos], true
- }
- func init() {
- p := big.NewInt(625)
- pow5Cache[0] = p
- for i := 1; i < len(pow5Cache); i++ {
- p = new(big.Int).Mul(p, p)
- pow5Cache[i] = p
- }
- }
|