Source file src/pkg/strconv/ftoa.go
     1	
     2	
     3	
     4	
     5	
     6	
     7	
     8	
     9	
    10	
    11	package strconv
    12	
    13	import "math"
    14	
    15	
    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	
    26	
    27	
    28	
    29	
    30	
    31	
    32	
    33	
    34	
    35	
    36	
    37	
    38	
    39	
    40	
    41	
    42	
    43	
    44	
    45	
    46	
    47	func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
    48		return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
    49	}
    50	
    51	
    52	
    53	func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
    54		return genericFtoa(dst, f, fmt, prec, bitSize)
    55	}
    56	
    57	func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
    58		var bits uint64
    59		var flt *floatInfo
    60		switch bitSize {
    61		case 32:
    62			bits = uint64(math.Float32bits(float32(val)))
    63			flt = &float32info
    64		case 64:
    65			bits = math.Float64bits(val)
    66			flt = &float64info
    67		default:
    68			panic("strconv: illegal AppendFloat/FormatFloat bitSize")
    69		}
    70	
    71		neg := bits>>(flt.expbits+flt.mantbits) != 0
    72		exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
    73		mant := bits & (uint64(1)<<flt.mantbits - 1)
    74	
    75		switch exp {
    76		case 1<<flt.expbits - 1:
    77			
    78			var s string
    79			switch {
    80			case mant != 0:
    81				s = "NaN"
    82			case neg:
    83				s = "-Inf"
    84			default:
    85				s = "+Inf"
    86			}
    87			return append(dst, s...)
    88	
    89		case 0:
    90			
    91			exp++
    92	
    93		default:
    94			
    95			mant |= uint64(1) << flt.mantbits
    96		}
    97		exp += flt.bias
    98	
    99		
   100		if fmt == 'b' {
   101			return fmtB(dst, neg, mant, exp, flt)
   102		}
   103		if fmt == 'x' || fmt == 'X' {
   104			return fmtX(dst, prec, fmt, neg, mant, exp, flt)
   105		}
   106	
   107		if !optimize {
   108			return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
   109		}
   110	
   111		var digs decimalSlice
   112		ok := false
   113		
   114		shortest := prec < 0
   115		if shortest {
   116			
   117			f := new(extFloat)
   118			lower, upper := f.AssignComputeBounds(mant, exp, neg, flt)
   119			var buf [32]byte
   120			digs.d = buf[:]
   121			ok = f.ShortestDecimal(&digs, &lower, &upper)
   122			if !ok {
   123				return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
   124			}
   125			
   126			switch fmt {
   127			case 'e', 'E':
   128				prec = max(digs.nd-1, 0)
   129			case 'f':
   130				prec = max(digs.nd-digs.dp, 0)
   131			case 'g', 'G':
   132				prec = digs.nd
   133			}
   134		} else if fmt != 'f' {
   135			
   136			digits := prec
   137			switch fmt {
   138			case 'e', 'E':
   139				digits++
   140			case 'g', 'G':
   141				if prec == 0 {
   142					prec = 1
   143				}
   144				digits = prec
   145			}
   146			if digits <= 15 {
   147				
   148				var buf [24]byte
   149				digs.d = buf[:]
   150				f := extFloat{mant, exp - int(flt.mantbits), neg}
   151				ok = f.FixedDecimal(&digs, digits)
   152			}
   153		}
   154		if !ok {
   155			return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
   156		}
   157		return formatDigits(dst, shortest, neg, digs, prec, fmt)
   158	}
   159	
   160	
   161	func bigFtoa(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
   162		d := new(decimal)
   163		d.Assign(mant)
   164		d.Shift(exp - int(flt.mantbits))
   165		var digs decimalSlice
   166		shortest := prec < 0
   167		if shortest {
   168			roundShortest(d, mant, exp, flt)
   169			digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
   170			
   171			switch fmt {
   172			case 'e', 'E':
   173				prec = digs.nd - 1
   174			case 'f':
   175				prec = max(digs.nd-digs.dp, 0)
   176			case 'g', 'G':
   177				prec = digs.nd
   178			}
   179		} else {
   180			
   181			switch fmt {
   182			case 'e', 'E':
   183				d.Round(prec + 1)
   184			case 'f':
   185				d.Round(d.dp + prec)
   186			case 'g', 'G':
   187				if prec == 0 {
   188					prec = 1
   189				}
   190				d.Round(prec)
   191			}
   192			digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
   193		}
   194		return formatDigits(dst, shortest, neg, digs, prec, fmt)
   195	}
   196	
   197	func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec int, fmt byte) []byte {
   198		switch fmt {
   199		case 'e', 'E':
   200			return fmtE(dst, neg, digs, prec, fmt)
   201		case 'f':
   202			return fmtF(dst, neg, digs, prec)
   203		case 'g', 'G':
   204			
   205			eprec := prec
   206			if eprec > digs.nd && digs.nd >= digs.dp {
   207				eprec = digs.nd
   208			}
   209			
   210			
   211			
   212			if shortest {
   213				eprec = 6
   214			}
   215			exp := digs.dp - 1
   216			if exp < -4 || exp >= eprec {
   217				if prec > digs.nd {
   218					prec = digs.nd
   219				}
   220				return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g')
   221			}
   222			if prec > digs.dp {
   223				prec = digs.nd
   224			}
   225			return fmtF(dst, neg, digs, max(prec-digs.dp, 0))
   226		}
   227	
   228		
   229		return append(dst, '%', fmt)
   230	}
   231	
   232	
   233	
   234	func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
   235		
   236		if mant == 0 {
   237			d.nd = 0
   238			return
   239		}
   240	
   241		
   242		
   243		
   244	
   245		
   246		
   247		
   248		
   249		
   250		
   251		
   252		
   253		
   254		
   255		minexp := flt.bias + 1 
   256		if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
   257			
   258			return
   259		}
   260	
   261		
   262		
   263		
   264		upper := new(decimal)
   265		upper.Assign(mant*2 + 1)
   266		upper.Shift(exp - int(flt.mantbits) - 1)
   267	
   268		
   269		
   270		
   271		
   272		
   273		
   274		var mantlo uint64
   275		var explo int
   276		if mant > 1<<flt.mantbits || exp == minexp {
   277			mantlo = mant - 1
   278			explo = exp
   279		} else {
   280			mantlo = mant*2 - 1
   281			explo = exp - 1
   282		}
   283		lower := new(decimal)
   284		lower.Assign(mantlo*2 + 1)
   285		lower.Shift(explo - int(flt.mantbits) - 1)
   286	
   287		
   288		
   289		
   290		inclusive := mant%2 == 0
   291	
   292		
   293		
   294		
   295		
   296		
   297		
   298		
   299		
   300		
   301		
   302		
   303		var upperdelta uint8
   304	
   305		
   306		
   307		for ui := 0; ; ui++ {
   308			
   309			
   310			
   311			mi := ui - upper.dp + d.dp
   312			if mi >= d.nd {
   313				break
   314			}
   315			li := ui - upper.dp + lower.dp
   316			l := byte('0') 
   317			if li >= 0 && li < lower.nd {
   318				l = lower.d[li]
   319			}
   320			m := byte('0') 
   321			if mi >= 0 {
   322				m = d.d[mi]
   323			}
   324			u := byte('0') 
   325			if ui < upper.nd {
   326				u = upper.d[ui]
   327			}
   328	
   329			
   330			
   331			
   332			okdown := l != m || inclusive && li+1 == lower.nd
   333	
   334			switch {
   335			case upperdelta == 0 && m+1 < u:
   336				
   337				
   338				
   339				upperdelta = 2
   340			case upperdelta == 0 && m != u:
   341				
   342				
   343				
   344				upperdelta = 1
   345			case upperdelta == 1 && (m != '9' || u != '0'):
   346				
   347				
   348				
   349				upperdelta = 2
   350			}
   351			
   352			
   353			okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd)
   354	
   355			
   356			
   357			switch {
   358			case okdown && okup:
   359				d.Round(mi + 1)
   360				return
   361			case okdown:
   362				d.RoundDown(mi + 1)
   363				return
   364			case okup:
   365				d.RoundUp(mi + 1)
   366				return
   367			}
   368		}
   369	}
   370	
   371	type decimalSlice struct {
   372		d      []byte
   373		nd, dp int
   374		neg    bool
   375	}
   376	
   377	
   378	func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
   379		
   380		if neg {
   381			dst = append(dst, '-')
   382		}
   383	
   384		
   385		ch := byte('0')
   386		if d.nd != 0 {
   387			ch = d.d[0]
   388		}
   389		dst = append(dst, ch)
   390	
   391		
   392		if prec > 0 {
   393			dst = append(dst, '.')
   394			i := 1
   395			m := min(d.nd, prec+1)
   396			if i < m {
   397				dst = append(dst, d.d[i:m]...)
   398				i = m
   399			}
   400			for ; i <= prec; i++ {
   401				dst = append(dst, '0')
   402			}
   403		}
   404	
   405		
   406		dst = append(dst, fmt)
   407		exp := d.dp - 1
   408		if d.nd == 0 { 
   409			exp = 0
   410		}
   411		if exp < 0 {
   412			ch = '-'
   413			exp = -exp
   414		} else {
   415			ch = '+'
   416		}
   417		dst = append(dst, ch)
   418	
   419		
   420		switch {
   421		case exp < 10:
   422			dst = append(dst, '0', byte(exp)+'0')
   423		case exp < 100:
   424			dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
   425		default:
   426			dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
   427		}
   428	
   429		return dst
   430	}
   431	
   432	
   433	func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
   434		
   435		if neg {
   436			dst = append(dst, '-')
   437		}
   438	
   439		
   440		if d.dp > 0 {
   441			m := min(d.nd, d.dp)
   442			dst = append(dst, d.d[:m]...)
   443			for ; m < d.dp; m++ {
   444				dst = append(dst, '0')
   445			}
   446		} else {
   447			dst = append(dst, '0')
   448		}
   449	
   450		
   451		if prec > 0 {
   452			dst = append(dst, '.')
   453			for i := 0; i < prec; i++ {
   454				ch := byte('0')
   455				if j := d.dp + i; 0 <= j && j < d.nd {
   456					ch = d.d[j]
   457				}
   458				dst = append(dst, ch)
   459			}
   460		}
   461	
   462		return dst
   463	}
   464	
   465	
   466	func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
   467		
   468		if neg {
   469			dst = append(dst, '-')
   470		}
   471	
   472		
   473		dst, _ = formatBits(dst, mant, 10, false, true)
   474	
   475		
   476		dst = append(dst, 'p')
   477	
   478		
   479		exp -= int(flt.mantbits)
   480		if exp >= 0 {
   481			dst = append(dst, '+')
   482		}
   483		dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
   484	
   485		return dst
   486	}
   487	
   488	
   489	func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
   490		if mant == 0 {
   491			exp = 0
   492		}
   493	
   494		
   495		mant <<= 60 - flt.mantbits
   496		for mant != 0 && mant&(1<<60) == 0 {
   497			mant <<= 1
   498			exp--
   499		}
   500	
   501		
   502		if prec >= 0 && prec < 15 {
   503			shift := uint(prec * 4)
   504			extra := (mant << shift) & (1<<60 - 1)
   505			mant >>= 60 - shift
   506			if extra|(mant&1) > 1<<59 {
   507				mant++
   508			}
   509			mant <<= 60 - shift
   510			if mant&(1<<61) != 0 {
   511				
   512				mant >>= 1
   513				exp++
   514			}
   515		}
   516	
   517		hex := lowerhex
   518		if fmt == 'X' {
   519			hex = upperhex
   520		}
   521	
   522		
   523		if neg {
   524			dst = append(dst, '-')
   525		}
   526		dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
   527	
   528		
   529		mant <<= 4 
   530		if prec < 0 && mant != 0 {
   531			dst = append(dst, '.')
   532			for mant != 0 {
   533				dst = append(dst, hex[(mant>>60)&15])
   534				mant <<= 4
   535			}
   536		} else if prec > 0 {
   537			dst = append(dst, '.')
   538			for i := 0; i < prec; i++ {
   539				dst = append(dst, hex[(mant>>60)&15])
   540				mant <<= 4
   541			}
   542		}
   543	
   544		
   545		ch := byte('P')
   546		if fmt == lower(fmt) {
   547			ch = 'p'
   548		}
   549		dst = append(dst, ch)
   550		if exp < 0 {
   551			ch = '-'
   552			exp = -exp
   553		} else {
   554			ch = '+'
   555		}
   556		dst = append(dst, ch)
   557	
   558		
   559		switch {
   560		case exp < 100:
   561			dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
   562		case exp < 1000:
   563			dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   564		default:
   565			dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   566		}
   567	
   568		return dst
   569	}
   570	
   571	func min(a, b int) int {
   572		if a < b {
   573			return a
   574		}
   575		return b
   576	}
   577	
   578	func max(a, b int) int {
   579		if a > b {
   580			return a
   581		}
   582		return b
   583	}
   584	
View as plain text