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