Source File
ftoa.go
Belonging Package
math/big
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file implements Float-to-string conversion functions.
// It is closely following the corresponding implementation
// in strconv/ftoa.go, but modified and simplified for Float.
package big
import (
)
// Text converts the floating-point number x to a string according
// to the given format and precision prec. The format is one of:
//
// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
// 'f' -ddddd.dddd, no exponent
// 'g' like 'e' for large exponents, like 'f' otherwise
// 'G' like 'E' for large exponents, like 'f' otherwise
// 'x' -0xd.dddddp±dd, hexadecimal mantissa, decimal power of two exponent
// 'p' -0x.dddp±dd, hexadecimal mantissa, decimal power of two exponent (non-standard)
// 'b' -ddddddp±dd, decimal mantissa, decimal power of two exponent (non-standard)
//
// For the power-of-two exponent formats, the mantissa is printed in normalized form:
//
// 'x' hexadecimal mantissa in [1, 2), or 0
// 'p' hexadecimal mantissa in [½, 1), or 0
// 'b' decimal integer mantissa using x.Prec() bits, or 0
//
// Note that the 'x' form is the one used by most other languages and libraries.
//
// If format is a different character, Text returns a "%" followed by the
// unrecognized format character.
//
// The precision prec controls the number of digits (excluding the exponent)
// printed by the 'e', 'E', 'f', 'g', 'G', and 'x' formats.
// For 'e', 'E', 'f', and 'x', it is the number of digits after the decimal point.
// For 'g' and 'G' it is the total number of digits. A negative precision selects
// the smallest number of decimal digits necessary to identify the value x uniquely
// using x.Prec() mantissa bits.
// The prec value is ignored for the 'b' and 'p' formats.
func ( *Float) ( byte, int) string {
:= 10 // TODO(gri) determine a good/better value here
if > 0 {
+=
}
return string(.Append(make([]byte, 0, ), , ))
}
// String formats x like x.Text('g', 10).
// (String must be called explicitly, Float.Format does not support %s verb.)
func ( *Float) () string {
return .Text('g', 10)
}
// Append appends to buf the string form of the floating-point number x,
// as generated by x.Text, and returns the extended buffer.
func ( *Float) ( []byte, byte, int) []byte {
// sign
if .neg {
= append(, '-')
}
// Inf
if .form == inf {
if !.neg {
= append(, '+')
}
return append(, "Inf"...)
}
// pick off easy formats
switch {
case 'b':
return .fmtB()
case 'p':
return .fmtP()
case 'x':
return .fmtX(, )
}
// Algorithm:
// 1) convert Float to multiprecision decimal
// 2) round to desired precision
// 3) read digits out and format
// 1) convert Float to multiprecision decimal
var decimal // == 0.0
if .form == finite {
// x != 0
.init(.mant, int(.exp)-.mant.bitLen())
}
// 2) round to desired precision
:= false
if < 0 {
= true
roundShortest(&, )
// Precision for shortest representation mode.
switch {
case 'e', 'E':
= len(.mant) - 1
case 'f':
= max(len(.mant)-.exp, 0)
case 'g', 'G':
= len(.mant)
}
} else {
// round appropriately
switch {
case 'e', 'E':
// one digit before and number of digits after decimal point
.round(1 + )
case 'f':
// number of digits before and after decimal point
.round(.exp + )
case 'g', 'G':
if == 0 {
= 1
}
.round()
}
}
// 3) read digits out and format
switch {
case 'e', 'E':
return fmtE(, , , )
case 'f':
return fmtF(, , )
case 'g', 'G':
// trim trailing fractional zeros in %e format
:=
if > len(.mant) && len(.mant) >= .exp {
= len(.mant)
}
// %e is used if the exponent from the conversion
// is less than -4 or greater than or equal to the precision.
// If precision was the shortest possible, use eprec = 6 for
// this decision.
if {
= 6
}
:= .exp - 1
if < -4 || >= {
if > len(.mant) {
= len(.mant)
}
return fmtE(, +'e'-'g', -1, )
}
if > .exp {
= len(.mant)
}
return fmtF(, max(-.exp, 0), )
}
// unknown format
if .neg {
= [:len()-1] // sign was added prematurely - remove it again
}
return append(, '%', )
}
func ( *decimal, *Float) {
// if the mantissa is zero, the number is zero - stop now
if len(.mant) == 0 {
return
}
// Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
// (possibly exclusive) round to x for the given precision of x.
// Compute the lower and upper bound in decimal form and find the
// shortest decimal number d such that lower <= d <= upper.
// TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
// See if we can use it (in adjusted form) here as well.
// 1) Compute normalized mantissa mant and exponent exp for x such
// that the lsb of mant corresponds to 1/2 ulp for the precision of
// x (i.e., for mant we want x.prec + 1 bits).
:= nat(nil).set(.mant)
:= int(.exp) - .bitLen()
:= .bitLen() - int(.prec+1)
switch {
case < 0:
= .shl(, uint(-))
case > 0:
= .shr(, uint(+))
}
+=
// x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
// 2) Compute lower bound by subtracting 1/2 ulp.
var decimal
var nat
.init(.sub(, natOne), )
// 3) Compute upper bound by adding 1/2 ulp.
var decimal
.init(.add(, natOne), )
// The upper and lower bounds are possible outputs only if
// the original mantissa is even, so that ToNearestEven rounding
// would round to the original mantissa and not the neighbors.
:= [0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
// Now we can figure out the minimum number of digits required.
// Walk along until d has distinguished itself from upper and lower.
for , := range .mant {
:= .at()
:= .at()
// Okay to round down (truncate) if lower has a different digit
// or if lower is inclusive and is exactly the result of rounding
// down (i.e., and we have reached the final digit of lower).
:= != || && +1 == len(.mant)
// Okay to round up if upper has a different digit and either upper
// is inclusive or upper is bigger than the result of rounding up.
:= != && ( || +1 < || +1 < len(.mant))
// If it's okay to do either, then round to the nearest one.
// If it's okay to do only one, do it.
switch {
case && :
.round( + 1)
return
case :
.roundDown( + 1)
return
case :
.roundUp( + 1)
return
}
}
}
// %e: d.ddddde±dd
func ( []byte, byte, int, decimal) []byte {
// first digit
:= byte('0')
if len(.mant) > 0 {
= .mant[0]
}
= append(, )
// .moredigits
if > 0 {
= append(, '.')
:= 1
:= min(len(.mant), +1)
if < {
= append(, .mant[:]...)
=
}
for ; <= ; ++ {
= append(, '0')
}
}
// e±
= append(, )
var int64
if len(.mant) > 0 {
= int64(.exp) - 1 // -1 because first digit was printed before '.'
}
if < 0 {
= '-'
= -
} else {
= '+'
}
= append(, )
// dd...d
if < 10 {
= append(, '0') // at least 2 exponent digits
}
return strconv.AppendInt(, , 10)
}
// %f: ddddddd.ddddd
func ( []byte, int, decimal) []byte {
// integer, padded with zeros as needed
if .exp > 0 {
:= min(len(.mant), .exp)
= append(, .mant[:]...)
for ; < .exp; ++ {
= append(, '0')
}
} else {
= append(, '0')
}
// fraction
if > 0 {
= append(, '.')
for := 0; < ; ++ {
= append(, .at(.exp+))
}
}
return
}
// fmtB appends the string of x in the format mantissa "p" exponent
// with a decimal mantissa and a binary exponent, or 0" if x is zero,
// and returns the extended buffer.
// The mantissa is normalized such that is uses x.Prec() bits in binary
// representation.
// The sign of x is ignored, and x must not be an Inf.
// (The caller handles Inf before invoking fmtB.)
func ( *Float) ( []byte) []byte {
if .form == zero {
return append(, '0')
}
if debugFloat && .form != finite {
panic("non-finite float")
}
// x != 0
// adjust mantissa to use exactly x.prec bits
:= .mant
switch := uint32(len(.mant)) * _W; {
case < .prec:
= nat(nil).shl(, uint(.prec-))
case > .prec:
= nat(nil).shr(, uint(-.prec))
}
= append(, .utoa(10)...)
= append(, 'p')
:= int64(.exp) - int64(.prec)
if >= 0 {
= append(, '+')
}
return strconv.AppendInt(, , 10)
}
// fmtX appends the string of x in the format "0x1." mantissa "p" exponent
// with a hexadecimal mantissa and a binary exponent, or "0x0p0" if x is zero,
// and returns the extended buffer.
// A non-zero mantissa is normalized such that 1.0 <= mantissa < 2.0.
// The sign of x is ignored, and x must not be an Inf.
// (The caller handles Inf before invoking fmtX.)
func ( *Float) ( []byte, int) []byte {
if .form == zero {
= append(, "0x0"...)
if > 0 {
= append(, '.')
for := 0; < ; ++ {
= append(, '0')
}
}
= append(, "p+00"...)
return
}
if debugFloat && .form != finite {
panic("non-finite float")
}
// round mantissa to n bits
var uint
if < 0 {
= 1 + (.MinPrec()-1+3)/4*4 // round MinPrec up to 1 mod 4
} else {
= 1 + 4*uint()
}
// n%4 == 1
= new(Float).SetPrec().SetMode(.mode).Set()
// adjust mantissa to use exactly n bits
:= .mant
switch := uint(len(.mant)) * _W; {
case < :
= nat(nil).shl(, -)
case > :
= nat(nil).shr(, -)
}
:= int64(.exp) - 1 // avoid wrap-around
:= .utoa(16)
if debugFloat && [0] != '1' {
panic("incorrect mantissa: " + string())
}
= append(, "0x1"...)
if len() > 1 {
= append(, '.')
= append(, [1:]...)
}
= append(, 'p')
if >= 0 {
= append(, '+')
} else {
= -
= append(, '-')
}
// Force at least two exponent digits, to match fmt.
if < 10 {
= append(, '0')
}
return strconv.AppendInt(, , 10)
}
// fmtP appends the string of x in the format "0x." mantissa "p" exponent
// with a hexadecimal mantissa and a binary exponent, or "0" if x is zero,
// and returns the extended buffer.
// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
// The sign of x is ignored, and x must not be an Inf.
// (The caller handles Inf before invoking fmtP.)
func ( *Float) ( []byte) []byte {
if .form == zero {
return append(, '0')
}
if debugFloat && .form != finite {
panic("non-finite float")
}
// x != 0
// remove trailing 0 words early
// (no need to convert to hex 0's and trim later)
:= .mant
:= 0
for < len() && [] == 0 {
++
}
= [:]
= append(, "0x."...)
= append(, bytes.TrimRight(.utoa(16), "0")...)
= append(, 'p')
if .exp >= 0 {
= append(, '+')
}
return strconv.AppendInt(, int64(.exp), 10)
}
func (, int) int {
if < {
return
}
return
}
var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
// Format implements fmt.Formatter. It accepts all the regular
// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
// 'g', 'G', 'x') as well as 'p' and 'v'. See (*Float).Text for the
// interpretation of 'p'. The 'v' format is handled like 'g'.
// Format also supports specification of the minimum precision
// in digits, the output field width, as well as the format flags
// '+' and ' ' for sign control, '0' for space or zero padding,
// and '-' for left or right justification. See the fmt package
// for details.
func ( *Float) ( fmt.State, rune) {
, := .Precision()
if ! {
= 6 // default precision for 'e', 'f'
}
switch {
case 'e', 'E', 'f', 'b', 'p', 'x':
// nothing to do
case 'F':
// (*Float).Text doesn't support 'F'; handle like 'f'
= 'f'
case 'v':
// handle like 'g'
= 'g'
fallthrough
case 'g', 'G':
if ! {
= -1 // default precision for 'g', 'G'
}
default:
fmt.Fprintf(, "%%!%c(*big.Float=%s)", , .String())
return
}
var []byte
= .Append(, byte(), )
if len() == 0 {
= []byte("?") // should never happen, but don't crash
}
// len(buf) > 0
var string
switch {
case [0] == '-':
= "-"
= [1:]
case [0] == '+':
// +Inf
= "+"
if .Flag(' ') {
= " "
}
= [1:]
case .Flag('+'):
= "+"
case .Flag(' '):
= " "
}
var int
if , := .Width(); && > len()+len() {
= - len() - len()
}
switch {
case .Flag('0') && !.IsInf():
// 0-padding on left
writeMultiple(, , 1)
writeMultiple(, "0", )
.Write()
case .Flag('-'):
// padding on right
writeMultiple(, , 1)
.Write()
writeMultiple(, " ", )
default:
// padding on left
writeMultiple(, " ", )
writeMultiple(, , 1)
.Write()
}
}