github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/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  	"fmt"
    13  	"strconv"
    14  	"strings"
    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 digits necessary to identify the value x uniquely.
    41  // The prec value is ignored for the 'b' or 'p' format.
    42  //
    43  // BUG(gri) Float.Text does not accept negative precisions (issue #10991).
    44  func (x *Float) Text(format byte, prec int) string {
    45  	const extra = 10 // TODO(gri) determine a good/better value here
    46  	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
    47  }
    48  
    49  // String formats x like x.Text('g', 10).
    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  		d.init(x.mant, int(x.exp)-x.mant.bitLen())
    87  	}
    88  
    89  	// 2) round to desired precision
    90  	shortest := false
    91  	if prec < 0 {
    92  		shortest = true
    93  		panic("unimplemented")
    94  		// TODO(gri) complete this
    95  		// roundShortest(&d, f.mant, int(f.exp))
    96  		// Precision for shortest representation mode.
    97  		switch fmt {
    98  		case 'e', 'E':
    99  			prec = len(d.mant) - 1
   100  		case 'f':
   101  			prec = max(len(d.mant)-d.exp, 0)
   102  		case 'g', 'G':
   103  			prec = len(d.mant)
   104  		}
   105  	} else {
   106  		// round appropriately
   107  		switch fmt {
   108  		case 'e', 'E':
   109  			// one digit before and number of digits after decimal point
   110  			d.round(1 + prec)
   111  		case 'f':
   112  			// number of digits before and after decimal point
   113  			d.round(d.exp + prec)
   114  		case 'g', 'G':
   115  			if prec == 0 {
   116  				prec = 1
   117  			}
   118  			d.round(prec)
   119  		}
   120  	}
   121  
   122  	// 3) read digits out and format
   123  	switch fmt {
   124  	case 'e', 'E':
   125  		return fmtE(buf, fmt, prec, d)
   126  	case 'f':
   127  		return fmtF(buf, prec, d)
   128  	case 'g', 'G':
   129  		// trim trailing fractional zeros in %e format
   130  		eprec := prec
   131  		if eprec > len(d.mant) && len(d.mant) >= d.exp {
   132  			eprec = len(d.mant)
   133  		}
   134  		// %e is used if the exponent from the conversion
   135  		// is less than -4 or greater than or equal to the precision.
   136  		// If precision was the shortest possible, use eprec = 6 for
   137  		// this decision.
   138  		if shortest {
   139  			eprec = 6
   140  		}
   141  		exp := d.exp - 1
   142  		if exp < -4 || exp >= eprec {
   143  			if prec > len(d.mant) {
   144  				prec = len(d.mant)
   145  			}
   146  			return fmtE(buf, fmt+'e'-'g', prec-1, d)
   147  		}
   148  		if prec > d.exp {
   149  			prec = len(d.mant)
   150  		}
   151  		return fmtF(buf, max(prec-d.exp, 0), d)
   152  	}
   153  
   154  	// unknown format
   155  	if x.neg {
   156  		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
   157  	}
   158  	return append(buf, '%', fmt)
   159  }
   160  
   161  // %e: d.ddddde±dd
   162  func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
   163  	// first digit
   164  	ch := byte('0')
   165  	if len(d.mant) > 0 {
   166  		ch = d.mant[0]
   167  	}
   168  	buf = append(buf, ch)
   169  
   170  	// .moredigits
   171  	if prec > 0 {
   172  		buf = append(buf, '.')
   173  		i := 1
   174  		m := min(len(d.mant), prec+1)
   175  		if i < m {
   176  			buf = append(buf, d.mant[i:m]...)
   177  			i = m
   178  		}
   179  		for ; i <= prec; i++ {
   180  			buf = append(buf, '0')
   181  		}
   182  	}
   183  
   184  	// e±
   185  	buf = append(buf, fmt)
   186  	var exp int64
   187  	if len(d.mant) > 0 {
   188  		exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
   189  	}
   190  	if exp < 0 {
   191  		ch = '-'
   192  		exp = -exp
   193  	} else {
   194  		ch = '+'
   195  	}
   196  	buf = append(buf, ch)
   197  
   198  	// dd...d
   199  	if exp < 10 {
   200  		buf = append(buf, '0') // at least 2 exponent digits
   201  	}
   202  	return strconv.AppendInt(buf, exp, 10)
   203  }
   204  
   205  // %f: ddddddd.ddddd
   206  func fmtF(buf []byte, prec int, d decimal) []byte {
   207  	// integer, padded with zeros as needed
   208  	if d.exp > 0 {
   209  		m := min(len(d.mant), d.exp)
   210  		buf = append(buf, d.mant[:m]...)
   211  		for ; m < d.exp; m++ {
   212  			buf = append(buf, '0')
   213  		}
   214  	} else {
   215  		buf = append(buf, '0')
   216  	}
   217  
   218  	// fraction
   219  	if prec > 0 {
   220  		buf = append(buf, '.')
   221  		for i := 0; i < prec; i++ {
   222  			ch := byte('0')
   223  			if j := d.exp + i; 0 <= j && j < len(d.mant) {
   224  				ch = d.mant[j]
   225  			}
   226  			buf = append(buf, ch)
   227  		}
   228  	}
   229  
   230  	return buf
   231  }
   232  
   233  // fmtB appends the string of x in the format mantissa "p" exponent
   234  // with a decimal mantissa and a binary exponent, or 0" if x is zero,
   235  // and returns the extended buffer.
   236  // The mantissa is normalized such that is uses x.Prec() bits in binary
   237  // representation.
   238  // The sign of x is ignored, and x must not be an Inf.
   239  func (x *Float) fmtB(buf []byte) []byte {
   240  	if x.form == zero {
   241  		return append(buf, '0')
   242  	}
   243  
   244  	if debugFloat && x.form != finite {
   245  		panic("non-finite float")
   246  	}
   247  	// x != 0
   248  
   249  	// adjust mantissa to use exactly x.prec bits
   250  	m := x.mant
   251  	switch w := uint32(len(x.mant)) * _W; {
   252  	case w < x.prec:
   253  		m = nat(nil).shl(m, uint(x.prec-w))
   254  	case w > x.prec:
   255  		m = nat(nil).shr(m, uint(w-x.prec))
   256  	}
   257  
   258  	buf = append(buf, m.decimalString()...)
   259  	buf = append(buf, 'p')
   260  	e := int64(x.exp) - int64(x.prec)
   261  	if e >= 0 {
   262  		buf = append(buf, '+')
   263  	}
   264  	return strconv.AppendInt(buf, e, 10)
   265  }
   266  
   267  // fmtP appends the string of x in the format 0x." mantissa "p" exponent
   268  // with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
   269  // ad returns the extended buffer.
   270  // The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
   271  // The sign of x is ignored, and x must not be an Inf.
   272  func (x *Float) fmtP(buf []byte) []byte {
   273  	if x.form == zero {
   274  		return append(buf, '0')
   275  	}
   276  
   277  	if debugFloat && x.form != finite {
   278  		panic("non-finite float")
   279  	}
   280  	// x != 0
   281  
   282  	// remove trailing 0 words early
   283  	// (no need to convert to hex 0's and trim later)
   284  	m := x.mant
   285  	i := 0
   286  	for i < len(m) && m[i] == 0 {
   287  		i++
   288  	}
   289  	m = m[i:]
   290  
   291  	buf = append(buf, "0x."...)
   292  	buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
   293  	buf = append(buf, 'p')
   294  	if x.exp >= 0 {
   295  		buf = append(buf, '+')
   296  	}
   297  	return strconv.AppendInt(buf, int64(x.exp), 10)
   298  }
   299  
   300  func min(x, y int) int {
   301  	if x < y {
   302  		return x
   303  	}
   304  	return y
   305  }
   306  
   307  // Format implements fmt.Formatter. It accepts all the regular
   308  // formats for floating-point numbers ('e', 'E', 'f', 'F', 'g',
   309  // 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the
   310  // interpretation of 'b' and 'p'. The 'v' format is handled like
   311  // 'g'.
   312  // Format also supports specification of the minimum precision
   313  // in digits, the output field width, as well as the format verbs
   314  // '+' and ' ' for sign control, '0' for space or zero padding,
   315  // and '-' for left or right justification. See the fmt package
   316  // for details.
   317  //
   318  // BUG(gri) A missing precision for the 'g' format, or a negative
   319  //          (via '*') precision is not yet supported. Instead the
   320  //          default precision (6) is used in that case (issue #10991).
   321  func (x *Float) Format(s fmt.State, format rune) {
   322  	prec, hasPrec := s.Precision()
   323  	if !hasPrec {
   324  		prec = 6 // default precision for 'e', 'f'
   325  	}
   326  
   327  	switch format {
   328  	case 'e', 'E', 'f', 'b', 'p':
   329  		// nothing to do
   330  	case 'F':
   331  		// (*Float).Text doesn't support 'F'; handle like 'f'
   332  		format = 'f'
   333  	case 'v':
   334  		// handle like 'g'
   335  		format = 'g'
   336  		fallthrough
   337  	case 'g', 'G':
   338  		if !hasPrec {
   339  			// TODO(gri) uncomment once (*Float).Text handles prec < 0
   340  			// prec = -1 // default precision for 'g', 'G'
   341  		}
   342  	default:
   343  		fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
   344  		return
   345  	}
   346  	var buf []byte
   347  	buf = x.Append(buf, byte(format), prec)
   348  	if len(buf) == 0 {
   349  		buf = []byte("?") // should never happen, but don't crash
   350  	}
   351  	// len(buf) > 0
   352  
   353  	var sign string
   354  	switch {
   355  	case buf[0] == '-':
   356  		sign = "-"
   357  		buf = buf[1:]
   358  	case buf[0] == '+':
   359  		// +Inf
   360  		sign = "+"
   361  		if s.Flag(' ') {
   362  			sign = " "
   363  		}
   364  		buf = buf[1:]
   365  	case s.Flag('+'):
   366  		sign = "+"
   367  	case s.Flag(' '):
   368  		sign = " "
   369  	}
   370  
   371  	var padding int
   372  	if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
   373  		padding = width - len(sign) - len(buf)
   374  	}
   375  
   376  	switch {
   377  	case s.Flag('0') && !x.IsInf():
   378  		// 0-padding on left
   379  		writeMultiple(s, sign, 1)
   380  		writeMultiple(s, "0", padding)
   381  		s.Write(buf)
   382  	case s.Flag('-'):
   383  		// padding on right
   384  		writeMultiple(s, sign, 1)
   385  		s.Write(buf)
   386  		writeMultiple(s, " ", padding)
   387  	default:
   388  		// padding on left
   389  		writeMultiple(s, " ", padding)
   390  		writeMultiple(s, sign, 1)
   391  		s.Write(buf)
   392  	}
   393  }