Source file src/internal/strconv/ftoa.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Binary to decimal floating point conversion.
     6  // Algorithm:
     7  //   1) store mantissa in multiprecision decimal
     8  //   2) shift decimal by exponent
     9  //   3) read digits out & format
    10  
    11  package strconv
    12  
    13  import (
    14  	"math/bits"
    15  	"unsafe"
    16  )
    17  
    18  const (
    19  	lowerhex = "0123456789abcdef"
    20  	upperhex = "0123456789ABCDEF"
    21  )
    22  
    23  const (
    24  	float32MantBits = 23
    25  	float32ExpBits  = 8
    26  	float32Bias     = -127
    27  	float32MinExp   = -189
    28  
    29  	float64MantBits = 52
    30  	float64ExpBits  = 11
    31  	float64Bias     = -1023
    32  	float64MinExp   = -1085
    33  )
    34  
    35  // FormatFloat converts the floating-point number f to a string,
    36  // according to the format fmt and precision prec. It rounds the
    37  // result assuming that the original was obtained from a floating-point
    38  // value of bitSize bits (32 for float32, 64 for float64).
    39  //
    40  // The format fmt is one of
    41  //   - 'b' (-ddddp±ddd, a binary exponent),
    42  //   - 'e' (-d.dddde±dd, a decimal exponent),
    43  //   - 'E' (-d.ddddE±dd, a decimal exponent),
    44  //   - 'f' (-ddd.dddd, no exponent),
    45  //   - 'g' ('e' for large exponents, 'f' otherwise),
    46  //   - 'G' ('E' for large exponents, 'f' otherwise),
    47  //   - 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or
    48  //   - 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).
    49  //
    50  // The precision prec controls the number of digits (excluding the exponent)
    51  // printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats.
    52  // For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point.
    53  // For 'g' and 'G' it is the maximum number of significant digits (trailing
    54  // zeros are removed).
    55  // The special precision -1 uses the smallest number of digits
    56  // necessary such that ParseFloat will return f exactly.
    57  // The exponent is written as a decimal integer;
    58  // for all formats other than 'b', it will be at least two digits.
    59  func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
    60  	if bitSize == 32 {
    61  		return string(ftoa32(make([]byte, 0, max(prec+4, 24)), float32(f), fmt, prec))
    62  	}
    63  	if bitSize == 64 {
    64  		return string(ftoa64(make([]byte, 0, max(prec+4, 24)), f, fmt, prec))
    65  	}
    66  	panic("strconv: illegal FormatFloat bitSize")
    67  }
    68  
    69  // AppendFloat appends the string form of the floating-point number f,
    70  // as generated by [FormatFloat], to dst and returns the extended buffer.
    71  func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
    72  	if bitSize == 32 {
    73  		return ftoa32(dst, float32(f), fmt, prec)
    74  	}
    75  	if bitSize == 64 {
    76  		return ftoa64(dst, f, fmt, prec)
    77  	}
    78  	panic("strconv: illegal AppendFloat bitSize")
    79  }
    80  
    81  // TODO(rsc): This should be ftoa[F float32 | float64](dst []byte, val F, ...),
    82  // but due to some bad interaction between inlining, escape analysis, and generic functions,
    83  // the result appears to escape dst to the heap with -l=4, which breaks
    84  // TestAbstractOriginSanity. See go.dev/issue/79547.
    85  // For now we make two manual specializations ftoa32 and ftoa64 instead.
    86  
    87  func ftoa32(dst []byte, val float32, fmt byte, prec int) []byte {
    88  	type F = float32
    89  	var b uint64
    90  	var expBits, mantBits, bias int // parameterized constants
    91  	switch 8 * unsafe.Sizeof(val) {
    92  	case 32:
    93  		b = uint64(float32bits(float32(val)))
    94  		expBits = float32ExpBits
    95  		mantBits = float32MantBits
    96  		bias = float32Bias
    97  	case 64:
    98  		b = float64bits(float64(val))
    99  		expBits = float64ExpBits
   100  		mantBits = float64MantBits
   101  		bias = float64Bias
   102  	}
   103  
   104  	neg := b>>(expBits+mantBits) != 0
   105  	exp := int(b>>mantBits) & (1<<expBits - 1)
   106  	mant := b & (1<<mantBits - 1)
   107  	if exp == 1<<expBits-1 {
   108  		if mant != 0 {
   109  			return append(dst, "NaN"...)
   110  		}
   111  		if neg {
   112  			return append(dst, "-Inf"...)
   113  		}
   114  		return append(dst, "+Inf"...)
   115  	}
   116  	if exp == 0 {
   117  		exp++
   118  	} else {
   119  		mant |= 1 << mantBits
   120  	}
   121  	exp += bias
   122  
   123  	// Pick off easy binary, hex formats.
   124  	if fmt == 'b' {
   125  		return fmtB(dst, neg, mant, exp-mantBits)
   126  	}
   127  	if fmt == 'x' || fmt == 'X' {
   128  		return fmtX(dst, prec, fmt, neg, mant, exp, mantBits)
   129  	}
   130  
   131  	// Pick off zero.
   132  	if mant == 0 {
   133  		return fmtEFG(dst, neg, nil, 0, 0, prec, fmt, prec < 0)
   134  	}
   135  
   136  	// Negative precision means "only as much as needed to be exact."
   137  	if prec < 0 {
   138  		// Use fast unrounded scaling.
   139  		var buf [32]byte
   140  		s := 64 - bits.Len64(mant)
   141  		m := mant << s
   142  		e := exp - s
   143  		d, p := shortFloat[F](m, e-mantBits)
   144  		dp, nd := setDigits(buf[:], d, p, numDigits(d))
   145  		// Precision for shortest representation mode.
   146  		switch fmt {
   147  		case 'e', 'E':
   148  			prec = max(nd-1, 0)
   149  		case 'f':
   150  			prec = max(nd-dp, 0)
   151  		case 'g', 'G':
   152  			prec = nd
   153  		}
   154  		return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, true)
   155  	}
   156  
   157  	if optimize {
   158  		// Fixed number of digits.
   159  		digits := prec
   160  		switch fmt {
   161  		case 'f':
   162  			// %f precision specifies digits after the decimal point.
   163  			// Estimate an upper bound on the total number of digits needed.
   164  			// ftoaFixed will shorten as needed according to prec.
   165  			if exp >= 0 {
   166  				digits = 1 + log10Pow2(1+exp) + prec
   167  			} else {
   168  				digits = 1 + prec - log10Pow2(-exp)
   169  			}
   170  		case 'e', 'E':
   171  			digits++
   172  		case 'g', 'G':
   173  			if prec == 0 {
   174  				prec = 1
   175  			}
   176  			digits = prec
   177  		default:
   178  			// Invalid mode.
   179  			digits = 1
   180  		}
   181  		if digits <= 18 {
   182  			// digits <= 0 happens for %f on very small numbers
   183  			// and means that we're guaranteed to print all zeros.
   184  			var buf [24]byte
   185  			var dp, nd int
   186  			if digits > 0 {
   187  				s := 64 - bits.Len64(mant)
   188  				m := mant << s
   189  				e := exp - s
   190  				d, p := fixedWidthFloat(m, e-mantBits, digits, prec, fmt)
   191  				if d != 0 {
   192  					dp, nd = setDigits(buf[:], d, p, numDigits(d))
   193  				}
   194  			}
   195  			return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, false)
   196  		}
   197  	}
   198  
   199  	// Slow bignum case. Only for non-shortest results.
   200  	d := new(decimal)
   201  	d.Assign(mant)
   202  	d.Shift(exp - mantBits)
   203  	switch fmt {
   204  	case 'e', 'E':
   205  		d.Round(prec + 1)
   206  	case 'f':
   207  		d.Round(d.dp + prec)
   208  	case 'g', 'G':
   209  		if prec == 0 {
   210  			prec = 1
   211  		}
   212  		d.Round(prec)
   213  	}
   214  	return fmtEFG(dst, neg, d.d[:], d.dp, d.nd, prec, fmt, false)
   215  }
   216  
   217  func ftoa64(dst []byte, val float64, fmt byte, prec int) []byte {
   218  	type F = float64
   219  	var b uint64
   220  	var expBits, mantBits, bias int // parameterized constants
   221  	switch 8 * unsafe.Sizeof(val) {
   222  	case 32:
   223  		b = uint64(float32bits(float32(val)))
   224  		expBits = float32ExpBits
   225  		mantBits = float32MantBits
   226  		bias = float32Bias
   227  	case 64:
   228  		b = float64bits(float64(val))
   229  		expBits = float64ExpBits
   230  		mantBits = float64MantBits
   231  		bias = float64Bias
   232  	}
   233  
   234  	neg := b>>(expBits+mantBits) != 0
   235  	exp := int(b>>mantBits) & (1<<expBits - 1)
   236  	mant := b & (1<<mantBits - 1)
   237  	if exp == 1<<expBits-1 {
   238  		if mant != 0 {
   239  			return append(dst, "NaN"...)
   240  		}
   241  		if neg {
   242  			return append(dst, "-Inf"...)
   243  		}
   244  		return append(dst, "+Inf"...)
   245  	}
   246  	if exp == 0 {
   247  		exp++
   248  	} else {
   249  		mant |= 1 << mantBits
   250  	}
   251  	exp += bias
   252  
   253  	// Pick off easy binary, hex formats.
   254  	if fmt == 'b' {
   255  		return fmtB(dst, neg, mant, exp-mantBits)
   256  	}
   257  	if fmt == 'x' || fmt == 'X' {
   258  		return fmtX(dst, prec, fmt, neg, mant, exp, mantBits)
   259  	}
   260  
   261  	// Pick off zero.
   262  	if mant == 0 {
   263  		return fmtEFG(dst, neg, nil, 0, 0, prec, fmt, prec < 0)
   264  	}
   265  
   266  	// Negative precision means "only as much as needed to be exact."
   267  	if prec < 0 {
   268  		// Use fast unrounded scaling.
   269  		var buf [32]byte
   270  		s := 64 - bits.Len64(mant)
   271  		m := mant << s
   272  		e := exp - s
   273  		d, p := shortFloat[F](m, e-mantBits)
   274  		dp, nd := setDigits(buf[:], d, p, numDigits(d))
   275  		// Precision for shortest representation mode.
   276  		switch fmt {
   277  		case 'e', 'E':
   278  			prec = max(nd-1, 0)
   279  		case 'f':
   280  			prec = max(nd-dp, 0)
   281  		case 'g', 'G':
   282  			prec = nd
   283  		}
   284  		return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, true)
   285  	}
   286  
   287  	if optimize {
   288  		// Fixed number of digits.
   289  		digits := prec
   290  		switch fmt {
   291  		case 'f':
   292  			// %f precision specifies digits after the decimal point.
   293  			// Estimate an upper bound on the total number of digits needed.
   294  			// ftoaFixed will shorten as needed according to prec.
   295  			if exp >= 0 {
   296  				digits = 1 + log10Pow2(1+exp) + prec
   297  			} else {
   298  				digits = 1 + prec - log10Pow2(-exp)
   299  			}
   300  		case 'e', 'E':
   301  			digits++
   302  		case 'g', 'G':
   303  			if prec == 0 {
   304  				prec = 1
   305  			}
   306  			digits = prec
   307  		default:
   308  			// Invalid mode.
   309  			digits = 1
   310  		}
   311  		if digits <= 18 {
   312  			// digits <= 0 happens for %f on very small numbers
   313  			// and means that we're guaranteed to print all zeros.
   314  			var buf [24]byte
   315  			var dp, nd int
   316  			if digits > 0 {
   317  				s := 64 - bits.Len64(mant)
   318  				m := mant << s
   319  				e := exp - s
   320  				d, p := fixedWidthFloat(m, e-mantBits, digits, prec, fmt)
   321  				if d != 0 {
   322  					dp, nd = setDigits(buf[:], d, p, numDigits(d))
   323  				}
   324  			}
   325  			return fmtEFG(dst, neg, buf[:], dp, nd, prec, fmt, false)
   326  		}
   327  	}
   328  
   329  	// Slow bignum case. Only for non-shortest results.
   330  	d := new(decimal)
   331  	d.Assign(mant)
   332  	d.Shift(exp - mantBits)
   333  	switch fmt {
   334  	case 'e', 'E':
   335  		d.Round(prec + 1)
   336  	case 'f':
   337  		d.Round(d.dp + prec)
   338  	case 'g', 'G':
   339  		if prec == 0 {
   340  			prec = 1
   341  		}
   342  		d.Round(prec)
   343  	}
   344  	return fmtEFG(dst, neg, d.d[:], d.dp, d.nd, prec, fmt, false)
   345  }
   346  
   347  func fmtEFG(dst []byte, neg bool, s []byte, dp, nd, prec int, fmt byte, shortest bool) []byte {
   348  	if fmt == 'g' || fmt == 'G' {
   349  		// trailing fractional zeros in 'e' form will be trimmed.
   350  		eprec := prec
   351  		if eprec > nd && nd >= dp {
   352  			eprec = nd
   353  		}
   354  		// %e is used if the exponent from the conversion
   355  		// is less than -4 or greater than or equal to the precision.
   356  		// if precision was the shortest possible, use precision 6 for this decision.
   357  		if shortest {
   358  			eprec = 6
   359  		}
   360  		exp := dp - 1
   361  		if exp < -4 || exp >= eprec {
   362  			if prec > nd {
   363  				prec = nd
   364  			}
   365  			prec--
   366  			fmt = fmt + 'e' - 'g'
   367  		} else {
   368  			if prec > dp {
   369  				prec = nd
   370  			}
   371  			prec = max(prec-dp, 0)
   372  			fmt = 'f'
   373  		}
   374  	}
   375  
   376  	switch fmt {
   377  	case 'e', 'E': // %e: -d.ddddde±dd
   378  		// sign
   379  		if neg {
   380  			dst = append(dst, '-')
   381  		}
   382  
   383  		// first digit
   384  		ch := byte('0')
   385  		if nd != 0 {
   386  			ch = s[0]
   387  		}
   388  		dst = append(dst, ch)
   389  
   390  		// .moredigits
   391  		if prec > 0 {
   392  			dst = append(dst, '.')
   393  			i := 1
   394  			m := min(nd, prec+1)
   395  			if i < m {
   396  				dst = append(dst, s[i:m]...)
   397  				i = m
   398  			}
   399  			for range prec + 1 - i {
   400  				dst = append(dst, '0')
   401  			}
   402  		}
   403  
   404  		// e±
   405  		dst = append(dst, fmt)
   406  		exp := dp - 1
   407  		if nd == 0 { // special case: 0 has exponent 0
   408  			exp = 0
   409  		}
   410  		if exp < 0 {
   411  			ch = '-'
   412  			exp = -exp
   413  		} else {
   414  			ch = '+'
   415  		}
   416  		dst = append(dst, ch)
   417  
   418  		// dd or ddd
   419  		switch {
   420  		case exp < 10:
   421  			dst = append(dst, '0', byte(exp)+'0')
   422  		case exp < 100:
   423  			dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
   424  		default:
   425  			dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
   426  		}
   427  		return dst
   428  
   429  	case 'f': // %f: -ddddddd.ddddd
   430  		// sign
   431  		if neg {
   432  			dst = append(dst, '-')
   433  		}
   434  
   435  		// integer, padded with zeros as needed.
   436  		if dp > 0 {
   437  			m := min(nd, dp)
   438  			for _, c := range s[:m] {
   439  				dst = append(dst, c)
   440  			}
   441  			for range dp - m {
   442  				dst = append(dst, '0')
   443  			}
   444  		} else {
   445  			dst = append(dst, '0')
   446  		}
   447  
   448  		// fraction
   449  		if prec > 0 {
   450  			dst = append(dst, '.')
   451  			lz := min(prec, max(0, -dp)) // leading zeros
   452  			off := dp + lz
   453  			m := min(prec-lz, max(0, nd-off)) // middle digits
   454  			tz := max(0, prec-lz-m)           // trailing zeros
   455  			for range lz {
   456  				dst = append(dst, '0')
   457  			}
   458  			for i := range m {
   459  				dst = append(dst, s[off+i])
   460  			}
   461  			for range tz {
   462  				dst = append(dst, '0')
   463  			}
   464  		}
   465  		return dst
   466  	}
   467  
   468  	// unknown format
   469  	return append(dst, '%', fmt)
   470  }
   471  
   472  // %b: -ddddddddp±ddd
   473  func fmtB(dst []byte, neg bool, mant uint64, exp int) []byte {
   474  	if neg {
   475  		dst = append(dst, '-')
   476  	}
   477  	dst = AppendUint(dst, mant, 10)
   478  	dst = append(dst, 'p')
   479  	if exp >= 0 {
   480  		dst = append(dst, '+')
   481  	}
   482  	dst = AppendInt(dst, int64(exp), 10)
   483  	return dst
   484  }
   485  
   486  // %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit)
   487  func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp, mantBits int) []byte {
   488  	if mant == 0 {
   489  		exp = 0
   490  	}
   491  
   492  	// Shift digits so leading 1 (if any) is at bit 1<<60.
   493  	// TODO: Is this the right way to handle subnormals?
   494  	mant <<= 60 - mantBits
   495  	for mant != 0 && mant&(1<<60) == 0 {
   496  		mant <<= 1
   497  		exp--
   498  	}
   499  
   500  	// Round if requested.
   501  	if prec >= 0 && prec < 15 {
   502  		shift := uint(prec * 4)
   503  		extra := (mant << shift) & (1<<60 - 1)
   504  		mant >>= 60 - shift
   505  		if extra|(mant&1) > 1<<59 {
   506  			mant++
   507  		}
   508  		mant <<= 60 - shift
   509  		if mant&(1<<61) != 0 {
   510  			// Wrapped around.
   511  			mant >>= 1
   512  			exp++
   513  		}
   514  	}
   515  
   516  	hex := lowerhex
   517  	if fmt == 'X' {
   518  		hex = upperhex
   519  	}
   520  
   521  	// sign, 0x, leading digit
   522  	if neg {
   523  		dst = append(dst, '-')
   524  	}
   525  	dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
   526  
   527  	// .fraction
   528  	mant <<= 4 // remove leading 0 or 1
   529  	if prec < 0 && mant != 0 {
   530  		dst = append(dst, '.')
   531  		for mant != 0 {
   532  			dst = append(dst, hex[(mant>>60)&15])
   533  			mant <<= 4
   534  		}
   535  	} else if prec > 0 {
   536  		dst = append(dst, '.')
   537  		for i := 0; i < prec; i++ {
   538  			dst = append(dst, hex[(mant>>60)&15])
   539  			mant <<= 4
   540  		}
   541  	}
   542  
   543  	// p±
   544  	ch := byte('P')
   545  	if fmt == lower(fmt) {
   546  		ch = 'p'
   547  	}
   548  	dst = append(dst, ch)
   549  	if exp < 0 {
   550  		ch = '-'
   551  		exp = -exp
   552  	} else {
   553  		ch = '+'
   554  	}
   555  	dst = append(dst, ch)
   556  
   557  	// dd or ddd or dddd
   558  	switch {
   559  	case exp < 100:
   560  		dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
   561  	case exp < 1000:
   562  		dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   563  	default:
   564  		dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   565  	}
   566  
   567  	return dst
   568  }
   569  

View as plain text