The Go Programming Language

Source file src/pkg/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 "math"
    14	
    15	// TODO: move elsewhere?
    16	type floatInfo struct {
    17		mantbits uint
    18		expbits  uint
    19		bias     int
    20	}
    21	
    22	var float32info = floatInfo{23, 8, -127}
    23	var float64info = floatInfo{52, 11, -1023}
    24	
    25	// Ftoa32 converts the 32-bit floating-point number f to a string,
    26	// according to the format fmt and precision prec.
    27	//
    28	// The format fmt is one of
    29	// 'b' (-ddddp±ddd, a binary exponent),
    30	// 'e' (-d.dddde±dd, a decimal exponent),
    31	// 'E' (-d.ddddE±dd, a decimal exponent),
    32	// 'f' (-ddd.dddd, no exponent),
    33	// 'g' ('e' for large exponents, 'f' otherwise), or
    34	// 'G' ('E' for large exponents, 'f' otherwise).
    35	//
    36	// The precision prec controls the number of digits
    37	// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
    38	// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
    39	// For 'g' and 'G' it is the total number of digits.
    40	// The special precision -1 uses the smallest number of digits
    41	// necessary such that Atof32 will return f exactly.
    42	//
    43	// Ftoa32(f) is not the same as Ftoa64(float32(f)),
    44	// because correct rounding and the number of digits
    45	// needed to identify f depend on the precision of the representation.
    46	func Ftoa32(f float32, fmt byte, prec int) string {
    47		return genericFtoa(uint64(math.Float32bits(f)), fmt, prec, &float32info)
    48	}
    49	
    50	// Ftoa64 is like Ftoa32 but converts a 64-bit floating-point number.
    51	func Ftoa64(f float64, fmt byte, prec int) string {
    52		return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
    53	}
    54	
    55	// FtoaN converts the 64-bit floating-point number f to a string,
    56	// according to the format fmt and precision prec, but it rounds the
    57	// result assuming that it was obtained from a floating-point value
    58	// of n bits (32 or 64).
    59	func FtoaN(f float64, fmt byte, prec int, n int) string {
    60		if n == 32 {
    61			return Ftoa32(float32(f), fmt, prec)
    62		}
    63		return Ftoa64(f, fmt, prec)
    64	}
    65	
    66	func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
    67		neg := bits>>(flt.expbits+flt.mantbits) != 0
    68		exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
    69		mant := bits & (uint64(1)<<flt.mantbits - 1)
    70	
    71		switch exp {
    72		case 1<<flt.expbits - 1:
    73			// Inf, NaN
    74			if mant != 0 {
    75				return "NaN"
    76			}
    77			if neg {
    78				return "-Inf"
    79			}
    80			return "+Inf"
    81	
    82		case 0:
    83			// denormalized
    84			exp++
    85	
    86		default:
    87			// add implicit top bit
    88			mant |= uint64(1) << flt.mantbits
    89		}
    90		exp += flt.bias
    91	
    92		// Pick off easy binary format.
    93		if fmt == 'b' {
    94			return fmtB(neg, mant, exp, flt)
    95		}
    96	
    97		// Create exact decimal representation.
    98		// The shift is exp - flt.mantbits because mant is a 1-bit integer
    99		// followed by a flt.mantbits fraction, and we are treating it as
   100		// a 1+flt.mantbits-bit integer.
   101		d := newDecimal(mant).Shift(exp - int(flt.mantbits))
   102	
   103		// Round appropriately.
   104		// Negative precision means "only as much as needed to be exact."
   105		shortest := false
   106		if prec < 0 {
   107			shortest = true
   108			roundShortest(d, mant, exp, flt)
   109			switch fmt {
   110			case 'e', 'E':
   111				prec = d.nd - 1
   112			case 'f':
   113				prec = max(d.nd-d.dp, 0)
   114			case 'g', 'G':
   115				prec = d.nd
   116			}
   117		} else {
   118			switch fmt {
   119			case 'e', 'E':
   120				d.Round(prec + 1)
   121			case 'f':
   122				d.Round(d.dp + prec)
   123			case 'g', 'G':
   124				if prec == 0 {
   125					prec = 1
   126				}
   127				d.Round(prec)
   128			}
   129		}
   130	
   131		switch fmt {
   132		case 'e', 'E':
   133			return fmtE(neg, d, prec, fmt)
   134		case 'f':
   135			return fmtF(neg, d, prec)
   136		case 'g', 'G':
   137			// trailing fractional zeros in 'e' form will be trimmed.
   138			eprec := prec
   139			if eprec > d.nd && d.nd >= d.dp {
   140				eprec = d.nd
   141			}
   142			// %e is used if the exponent from the conversion
   143			// is less than -4 or greater than or equal to the precision.
   144			// if precision was the shortest possible, use precision 6 for this decision.
   145			if shortest {
   146				eprec = 6
   147			}
   148			exp := d.dp - 1
   149			if exp < -4 || exp >= eprec {
   150				if prec > d.nd {
   151					prec = d.nd
   152				}
   153				return fmtE(neg, d, prec-1, fmt+'e'-'g')
   154			}
   155			if prec > d.dp {
   156				prec = d.nd
   157			}
   158			return fmtF(neg, d, max(prec-d.dp, 0))
   159		}
   160	
   161		return "%" + string(fmt)
   162	}
   163	
   164	// Round d (= mant * 2^exp) to the shortest number of digits
   165	// that will let the original floating point value be precisely
   166	// reconstructed.  Size is original floating point size (64 or 32).
   167	func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
   168		// If mantissa is zero, the number is zero; stop now.
   169		if mant == 0 {
   170			d.nd = 0
   171			return
   172		}
   173	
   174		// TODO(rsc): Unless exp == minexp, if the number of digits in d
   175		// is less than 17, it seems likely that it would be
   176		// the shortest possible number already.  So maybe we can
   177		// bail out without doing the extra multiprecision math here.
   178	
   179		// Compute upper and lower such that any decimal number
   180		// between upper and lower (possibly inclusive)
   181		// will round to the original floating point number.
   182	
   183		// d = mant << (exp - mantbits)
   184		// Next highest floating point number is mant+1 << exp-mantbits.
   185		// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
   186		upper := newDecimal(mant*2 + 1).Shift(exp - int(flt.mantbits) - 1)
   187	
   188		// d = mant << (exp - mantbits)
   189		// Next lowest floating point number is mant-1 << exp-mantbits,
   190		// unless mant-1 drops the significant bit and exp is not the minimum exp,
   191		// in which case the next lowest is mant*2-1 << exp-mantbits-1.
   192		// Either way, call it mantlo << explo-mantbits.
   193		// Our lower bound is halfway inbetween, mantlo*2+1 << explo-mantbits-1.
   194		minexp := flt.bias + 1 // minimum possible exponent
   195		var mantlo uint64
   196		var explo int
   197		if mant > 1<<flt.mantbits || exp == minexp {
   198			mantlo = mant - 1
   199			explo = exp
   200		} else {
   201			mantlo = mant*2 - 1
   202			explo = exp - 1
   203		}
   204		lower := newDecimal(mantlo*2 + 1).Shift(explo - int(flt.mantbits) - 1)
   205	
   206		// The upper and lower bounds are possible outputs only if
   207		// the original mantissa is even, so that IEEE round-to-even
   208		// would round to the original mantissa and not the neighbors.
   209		inclusive := mant%2 == 0
   210	
   211		// Now we can figure out the minimum number of digits required.
   212		// Walk along until d has distinguished itself from upper and lower.
   213		for i := 0; i < d.nd; i++ {
   214			var l, m, u byte // lower, middle, upper digits
   215			if i < lower.nd {
   216				l = lower.d[i]
   217			} else {
   218				l = '0'
   219			}
   220			m = d.d[i]
   221			if i < upper.nd {
   222				u = upper.d[i]
   223			} else {
   224				u = '0'
   225			}
   226	
   227			// Okay to round down (truncate) if lower has a different digit
   228			// or if lower is inclusive and is exactly the result of rounding down.
   229			okdown := l != m || (inclusive && l == m && i+1 == lower.nd)
   230	
   231			// Okay to round up if upper has a different digit and
   232			// either upper is inclusive or upper is bigger than the result of rounding up.
   233			okup := m != u && (inclusive || i+1 < upper.nd)
   234	
   235			// If it's okay to do either, then round to the nearest one.
   236			// If it's okay to do only one, do it.
   237			switch {
   238			case okdown && okup:
   239				d.Round(i + 1)
   240				return
   241			case okdown:
   242				d.RoundDown(i + 1)
   243				return
   244			case okup:
   245				d.RoundUp(i + 1)
   246				return
   247			}
   248		}
   249	}
   250	
   251	// %e: -d.ddddde±dd
   252	func fmtE(neg bool, d *decimal, prec int, fmt byte) string {
   253		buf := make([]byte, 3+max(prec, 0)+30) // "-0." + prec digits + exp
   254		w := 0                                 // write index
   255	
   256		// sign
   257		if neg {
   258			buf[w] = '-'
   259			w++
   260		}
   261	
   262		// first digit
   263		if d.nd == 0 {
   264			buf[w] = '0'
   265		} else {
   266			buf[w] = d.d[0]
   267		}
   268		w++
   269	
   270		// .moredigits
   271		if prec > 0 {
   272			buf[w] = '.'
   273			w++
   274			for i := 0; i < prec; i++ {
   275				if 1+i < d.nd {
   276					buf[w] = d.d[1+i]
   277				} else {
   278					buf[w] = '0'
   279				}
   280				w++
   281			}
   282		}
   283	
   284		// e±
   285		buf[w] = fmt
   286		w++
   287		exp := d.dp - 1
   288		if d.nd == 0 { // special case: 0 has exponent 0
   289			exp = 0
   290		}
   291		if exp < 0 {
   292			buf[w] = '-'
   293			exp = -exp
   294		} else {
   295			buf[w] = '+'
   296		}
   297		w++
   298	
   299		// dddd
   300		// count digits
   301		n := 0
   302		for e := exp; e > 0; e /= 10 {
   303			n++
   304		}
   305		// leading zeros
   306		for i := n; i < 2; i++ {
   307			buf[w] = '0'
   308			w++
   309		}
   310		// digits
   311		w += n
   312		n = 0
   313		for e := exp; e > 0; e /= 10 {
   314			n++
   315			buf[w-n] = byte(e%10 + '0')
   316		}
   317	
   318		return string(buf[0:w])
   319	}
   320	
   321	// %f: -ddddddd.ddddd
   322	func fmtF(neg bool, d *decimal, prec int) string {
   323		buf := make([]byte, 1+max(d.dp, 1)+1+max(prec, 0))
   324		w := 0
   325	
   326		// sign
   327		if neg {
   328			buf[w] = '-'
   329			w++
   330		}
   331	
   332		// integer, padded with zeros as needed.
   333		if d.dp > 0 {
   334			var i int
   335			for i = 0; i < d.dp && i < d.nd; i++ {
   336				buf[w] = d.d[i]
   337				w++
   338			}
   339			for ; i < d.dp; i++ {
   340				buf[w] = '0'
   341				w++
   342			}
   343		} else {
   344			buf[w] = '0'
   345			w++
   346		}
   347	
   348		// fraction
   349		if prec > 0 {
   350			buf[w] = '.'
   351			w++
   352			for i := 0; i < prec; i++ {
   353				if d.dp+i < 0 || d.dp+i >= d.nd {
   354					buf[w] = '0'
   355				} else {
   356					buf[w] = d.d[d.dp+i]
   357				}
   358				w++
   359			}
   360		}
   361	
   362		return string(buf[0:w])
   363	}
   364	
   365	// %b: -ddddddddp+ddd
   366	func fmtB(neg bool, mant uint64, exp int, flt *floatInfo) string {
   367		var buf [50]byte
   368		w := len(buf)
   369		exp -= int(flt.mantbits)
   370		esign := byte('+')
   371		if exp < 0 {
   372			esign = '-'
   373			exp = -exp
   374		}
   375		n := 0
   376		for exp > 0 || n < 1 {
   377			n++
   378			w--
   379			buf[w] = byte(exp%10 + '0')
   380			exp /= 10
   381		}
   382		w--
   383		buf[w] = esign
   384		w--
   385		buf[w] = 'p'
   386		n = 0
   387		for mant > 0 || n < 1 {
   388			n++
   389			w--
   390			buf[w] = byte(mant%10 + '0')
   391			mant /= 10
   392		}
   393		if neg {
   394			w--
   395			buf[w] = '-'
   396		}
   397		return string(buf[w:])
   398	}
   399	
   400	func max(a, b int) int {
   401		if a > b {
   402			return a
   403		}
   404		return b
   405	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.