github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/math/big/ftoa.go (about)

     1  // Copyright 2015 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  // This file implements Float-to-string conversion functions.
     6  // It is closely following the corresponding implementation
     7  // in strconv/ftoa.go, but modified and simplified for Float.
     8  
     9  package big
    10  
    11  import (
    12  	"bytes"
    13  	"fmt"
    14  	"strconv"
    15  )
    16  
    17  // Text converts the floating-point number x to a string according
    18  // to the given format and precision prec. The format is one of:
    19  //
    20  //	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
    21  //	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
    22  //	'f'	-ddddd.dddd, no exponent
    23  //	'g'	like 'e' for large exponents, like 'f' otherwise
    24  //	'G'	like 'E' for large exponents, like 'f' otherwise
    25  //	'b'	-ddddddp±dd, binary exponent
    26  //	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
    27  //
    28  // For the binary exponent formats, the mantissa is printed in normalized form:
    29  //
    30  //	'b'	decimal integer mantissa using x.Prec() bits, or -0
    31  //	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
    32  //
    33  // If format is a different character, Text returns a "%" followed by the
    34  // unrecognized format character.
    35  //
    36  // The precision prec controls the number of digits (excluding the exponent)
    37  // printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
    38  // it is the number of digits after the decimal point. For 'g' and 'G' it is
    39  // the total number of digits. A negative precision selects the smallest
    40  // number of decimal digits necessary to identify the value x uniquely using
    41  // x.Prec() mantissa bits.
    42  // The prec value is ignored for the 'b' or 'p' format.
    43  func (x *Float) Text(format byte, prec int) string {
    44  	const extra = 10 // TODO(gri) determine a good/better value here
    45  	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
    46  }
    47  
    48  // String formats x like x.Text('g', 10).
    49  // (String must be called explicitly, Float.Format does not support %s verb.)
    50  func (x *Float) String() string {
    51  	return x.Text('g', 10)
    52  }
    53  
    54  // Append appends to buf the string form of the floating-point number x,
    55  // as generated by x.Text, and returns the extended buffer.
    56  func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
    57  	// sign
    58  	if x.neg {
    59  		buf = append(buf, '-')
    60  	}
    61  
    62  	// Inf
    63  	if x.form == inf {
    64  		if !x.neg {
    65  			buf = append(buf, '+')
    66  		}
    67  		return append(buf, "Inf"...)
    68  	}
    69  
    70  	// pick off easy formats
    71  	switch fmt {
    72  	case 'b':
    73  		return x.fmtB(buf)
    74  	case 'p':
    75  		return x.fmtP(buf)
    76  	}
    77  
    78  	// Algorithm:
    79  	//   1) convert Float to multiprecision decimal
    80  	//   2) round to desired precision
    81  	//   3) read digits out and format
    82  
    83  	// 1) convert Float to multiprecision decimal
    84  	var d decimal // == 0.0
    85  	if x.form == finite {
    86  		// x != 0
    87  		d.init(x.mant, int(x.exp)-x.mant.bitLen())
    88  	}
    89  
    90  	// 2) round to desired precision
    91  	shortest := false
    92  	if prec < 0 {
    93  		shortest = true
    94  		roundShortest(&d, x)
    95  		// Precision for shortest representation mode.
    96  		switch fmt {
    97  		case 'e', 'E':
    98  			prec = len(d.mant) - 1
    99  		case 'f':
   100  			prec = max(len(d.mant)-d.exp, 0)
   101  		case 'g', 'G':
   102  			prec = len(d.mant)
   103  		}
   104  	} else {
   105  		// round appropriately
   106  		switch fmt {
   107  		case 'e', 'E':
   108  			// one digit before and number of digits after decimal point
   109  			d.round(1 + prec)
   110  		case 'f':
   111  			// number of digits before and after decimal point
   112  			d.round(d.exp + prec)
   113  		case 'g', 'G':
   114  			if prec == 0 {
   115  				prec = 1
   116  			}
   117  			d.round(prec)
   118  		}
   119  	}
   120  
   121  	// 3) read digits out and format
   122  	switch fmt {
   123  	case 'e', 'E':
   124  		return fmtE(buf, fmt, prec, d)
   125  	case 'f':
   126  		return fmtF(buf, prec, d)
   127  	case 'g', 'G':
   128  		// trim trailing fractional zeros in %e format
   129  		eprec := prec
   130  		if eprec > len(d.mant) && len(d.mant) >= d.exp {
   131  			eprec = len(d.mant)
   132  		}
   133  		// %e is used if the exponent from the conversion
   134  		// is less than -4 or greater than or equal to the precision.
   135  		// If precision was the shortest possible, use eprec = 6 for
   136  		// this decision.
   137  		if shortest {
   138  			eprec = 6
   139  		}
   140  		exp := d.exp - 1
   141  		if exp < -4 || exp >= eprec {
   142  			if prec > len(d.mant) {
   143  				prec = len(d.mant)
   144  			}
   145  			return fmtE(buf, fmt+'e'-'g', prec-1, d)
   146  		}
   147  		if prec > d.exp {
   148  			prec = len(d.mant)
   149  		}
   150  		return fmtF(buf, max(prec-d.exp, 0), d)
   151  	}
   152  
   153  	// unknown format
   154  	if x.neg {
   155  		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
   156  	}
   157  	return append(buf, '%', fmt)
   158  }
   159  
   160  func roundShortest(d *decimal, x *Float) {
   161  	// if the mantissa is zero, the number is zero - stop now
   162  	if len(d.mant) == 0 {
   163  		return
   164  	}
   165  
   166  	// Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
   167  	// (possibly exclusive) round to x for the given precision of x.
   168  	// Compute the lower and upper bound in decimal form and find the
   169  	// shortest decimal number d such that lower <= d <= upper.
   170  
   171  	// TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
   172  	// See if we can use it (in adjusted form) here as well.
   173  
   174  	// 1) Compute normalized mantissa mant and exponent exp for x such
   175  	// that the lsb of mant corresponds to 1/2 ulp for the precision of
   176  	// x (i.e., for mant we want x.prec + 1 bits).
   177  	mant := nat(nil).set(x.mant)
   178  	exp := int(x.exp) - mant.bitLen()
   179  	s := mant.bitLen() - int(x.prec+1)
   180  	switch {
   181  	case s < 0:
   182  		mant = mant.shl(mant, uint(-s))
   183  	case s > 0:
   184  		mant = mant.shr(mant, uint(+s))
   185  	}
   186  	exp += s
   187  	// x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
   188  
   189  	// 2) Compute lower bound by subtracting 1/2 ulp.
   190  	var lower decimal
   191  	var tmp nat
   192  	lower.init(tmp.sub(mant, natOne), exp)
   193  
   194  	// 3) Compute upper bound by adding 1/2 ulp.
   195  	var upper decimal
   196  	upper.init(tmp.add(mant, natOne), exp)
   197  
   198  	// The upper and lower bounds are possible outputs only if
   199  	// the original mantissa is even, so that ToNearestEven rounding
   200  	// would round to the original mantissa and not the neighbors.
   201  	inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
   202  
   203  	// Now we can figure out the minimum number of digits required.
   204  	// Walk along until d has distinguished itself from upper and lower.
   205  	for i, m := range d.mant {
   206  		l := lower.at(i)
   207  		u := upper.at(i)
   208  
   209  		// Okay to round down (truncate) if lower has a different digit
   210  		// or if lower is inclusive and is exactly the result of rounding
   211  		// down (i.e., and we have reached the final digit of lower).
   212  		okdown := l != m || inclusive && i+1 == len(lower.mant)
   213  
   214  		// Okay to round up if upper has a different digit and either upper
   215  		// is inclusive or upper is bigger than the result of rounding up.
   216  		okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
   217  
   218  		// If it's okay to do either, then round to the nearest one.
   219  		// If it's okay to do only one, do it.
   220  		switch {
   221  		case okdown && okup:
   222  			d.round(i + 1)
   223  			return
   224  		case okdown:
   225  			d.roundDown(i + 1)
   226  			return
   227  		case okup:
   228  			d.roundUp(i + 1)
   229  			return
   230  		}
   231  	}
   232  }
   233  
   234  // %e: d.ddddde±dd
   235  func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
   236  	// first digit
   237  	ch := byte('0')
   238  	if len(d.mant) > 0 {
   239  		ch = d.mant[0]
   240  	}
   241  	buf = append(buf, ch)
   242  
   243  	// .moredigits
   244  	if prec > 0 {
   245  		buf = append(buf, '.')
   246  		i := 1
   247  		m := min(len(d.mant), prec+1)
   248  		if i < m {
   249  			buf = append(buf, d.mant[i:m]...)
   250  			i = m
   251  		}
   252  		for ; i <= prec; i++ {
   253  			buf = append(buf, '0')
   254  		}
   255  	}
   256  
   257  	// e±
   258  	buf = append(buf, fmt)
   259  	var exp int64
   260  	if len(d.mant) > 0 {
   261  		exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
   262  	}
   263  	if exp < 0 {
   264  		ch = '-'
   265  		exp = -exp
   266  	} else {
   267  		ch = '+'
   268  	}
   269  	buf = append(buf, ch)
   270  
   271  	// dd...d
   272  	if exp < 10 {
   273  		buf = append(buf, '0') // at least 2 exponent digits
   274  	}
   275  	return strconv.AppendInt(buf, exp, 10)
   276  }
   277  
   278  // %f: ddddddd.ddddd
   279  func fmtF(buf []byte, prec int, d decimal) []byte {
   280  	// integer, padded with zeros as needed
   281  	if d.exp > 0 {
   282  		m := min(len(d.mant), d.exp)
   283  		buf = append(buf, d.mant[:m]...)
   284  		for ; m < d.exp; m++ {
   285  			buf = append(buf, '0')
   286  		}
   287  	} else {
   288  		buf = append(buf, '0')
   289  	}
   290  
   291  	// fraction
   292  	if prec > 0 {
   293  		buf = append(buf, '.')
   294  		for i := 0; i < prec; i++ {
   295  			buf = append(buf, d.at(d.exp+i))
   296  		}
   297  	}
   298  
   299  	return buf
   300  }
   301  
   302  // fmtB appends the string of x in the format mantissa "p" exponent
   303  // with a decimal mantissa and a binary exponent, or 0" if x is zero,
   304  // and returns the extended buffer.
   305  // The mantissa is normalized such that is uses x.Prec() bits in binary
   306  // representation.
   307  // The sign of x is ignored, and x must not be an Inf.
   308  func (x *Float) fmtB(buf []byte) []byte {
   309  	if x.form == zero {
   310  		return append(buf, '0')
   311  	}
   312  
   313  	if debugFloat && x.form != finite {
   314  		panic("non-finite float")
   315  	}
   316  	// x != 0
   317  
   318  	// adjust mantissa to use exactly x.prec bits
   319  	m := x.mant
   320  	switch w := uint32(len(x.mant)) * _W; {
   321  	case w < x.prec:
   322  		m = nat(nil).shl(m, uint(x.prec-w))
   323  	case w > x.prec:
   324  		m = nat(nil).shr(m, uint(w-x.prec))
   325  	}
   326  
   327  	buf = append(buf, m.utoa(10)...)
   328  	buf = append(buf, 'p')
   329  	e := int64(x.exp) - int64(x.prec)
   330  	if e >= 0 {
   331  		buf = append(buf, '+')
   332  	}
   333  	return strconv.AppendInt(buf, e, 10)
   334  }
   335  
   336  // fmtP appends the string of x in the format 0x." mantissa "p" exponent
   337  // with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
   338  // ad returns the extended buffer.
   339  // The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
   340  // The sign of x is ignored, and x must not be an Inf.
   341  func (x *Float) fmtP(buf []byte) []byte {
   342  	if x.form == zero {
   343  		return append(buf, '0')
   344  	}
   345  
   346  	if debugFloat && x.form != finite {
   347  		panic("non-finite float")
   348  	}
   349  	// x != 0
   350  
   351  	// remove trailing 0 words early
   352  	// (no need to convert to hex 0's and trim later)
   353  	m := x.mant
   354  	i := 0
   355  	for i < len(m) && m[i] == 0 {
   356  		i++
   357  	}
   358  	m = m[i:]
   359  
   360  	buf = append(buf, "0x."...)
   361  	buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
   362  	buf = append(buf, 'p')
   363  	if x.exp >= 0 {
   364  		buf = append(buf, '+')
   365  	}
   366  	return strconv.AppendInt(buf, int64(x.exp), 10)
   367  }
   368  
   369  func min(x, y int) int {
   370  	if x < y {
   371  		return x
   372  	}
   373  	return y
   374  }
   375  
   376  // Format implements fmt.Formatter. It accepts all the regular
   377  // formats for floating-point numbers ('e', 'E', 'f', 'F', 'g',
   378  // 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the
   379  // interpretation of 'b' and 'p'. The 'v' format is handled like
   380  // 'g'.
   381  // Format also supports specification of the minimum precision
   382  // in digits, the output field width, as well as the format verbs
   383  // '+' and ' ' for sign control, '0' for space or zero padding,
   384  // and '-' for left or right justification. See the fmt package
   385  // for details.
   386  func (x *Float) Format(s fmt.State, format rune) {
   387  	prec, hasPrec := s.Precision()
   388  	if !hasPrec {
   389  		prec = 6 // default precision for 'e', 'f'
   390  	}
   391  
   392  	switch format {
   393  	case 'e', 'E', 'f', 'b', 'p':
   394  		// nothing to do
   395  	case 'F':
   396  		// (*Float).Text doesn't support 'F'; handle like 'f'
   397  		format = 'f'
   398  	case 'v':
   399  		// handle like 'g'
   400  		format = 'g'
   401  		fallthrough
   402  	case 'g', 'G':
   403  		if !hasPrec {
   404  			prec = -1 // default precision for 'g', 'G'
   405  		}
   406  	default:
   407  		fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
   408  		return
   409  	}
   410  	var buf []byte
   411  	buf = x.Append(buf, byte(format), prec)
   412  	if len(buf) == 0 {
   413  		buf = []byte("?") // should never happen, but don't crash
   414  	}
   415  	// len(buf) > 0
   416  
   417  	var sign string
   418  	switch {
   419  	case buf[0] == '-':
   420  		sign = "-"
   421  		buf = buf[1:]
   422  	case buf[0] == '+':
   423  		// +Inf
   424  		sign = "+"
   425  		if s.Flag(' ') {
   426  			sign = " "
   427  		}
   428  		buf = buf[1:]
   429  	case s.Flag('+'):
   430  		sign = "+"
   431  	case s.Flag(' '):
   432  		sign = " "
   433  	}
   434  
   435  	var padding int
   436  	if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
   437  		padding = width - len(sign) - len(buf)
   438  	}
   439  
   440  	switch {
   441  	case s.Flag('0') && !x.IsInf():
   442  		// 0-padding on left
   443  		writeMultiple(s, sign, 1)
   444  		writeMultiple(s, "0", padding)
   445  		s.Write(buf)
   446  	case s.Flag('-'):
   447  		// padding on right
   448  		writeMultiple(s, sign, 1)
   449  		s.Write(buf)
   450  		writeMultiple(s, " ", padding)
   451  	default:
   452  		// padding on left
   453  		writeMultiple(s, " ", padding)
   454  		writeMultiple(s, sign, 1)
   455  		s.Write(buf)
   456  	}
   457  }