github.com/iEvan-lhr/exciting-tool@v0.0.0-20230504054234-8e983f73cdd2/float.go (about)

     1  package tools
     2  
     3  import (
     4  	"math"
     5  )
     6  
     7  var float32info = floatInfo{23, 8, -127}
     8  var float64info = floatInfo{52, 11, -1023}
     9  var optimize = true // set to false to force slow-path conversions for testing
    10  
    11  func genericFtoa(dst *[]byte, val float64, fmt byte, prec, bitSize int) {
    12  	var bits uint64
    13  	var flt *floatInfo
    14  	switch bitSize {
    15  	case 32:
    16  		bits = uint64(math.Float32bits(float32(val)))
    17  		flt = &float32info
    18  	case 64:
    19  		bits = math.Float64bits(val)
    20  		flt = &float64info
    21  	default:
    22  		panic("strconv: illegal AppendFloat/FormatFloat bitSize")
    23  	}
    24  
    25  	neg := bits>>(flt.expbits+flt.mantbits) != 0
    26  	exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1)
    27  	mant := bits & (uint64(1)<<flt.mantbits - 1)
    28  
    29  	switch exp {
    30  	case 1<<flt.expbits - 1:
    31  		// Inf, NaN
    32  		switch {
    33  		case mant != 0:
    34  			*dst = append(*dst, []byte("NaN")...)
    35  		case neg:
    36  			*dst = append(*dst, []byte("-Inf")...)
    37  		default:
    38  			*dst = append(*dst, []byte("+Inf")...)
    39  		}
    40  		return
    41  	case 0:
    42  		// denormalized
    43  		exp++
    44  
    45  	default:
    46  		// add implicit top bit
    47  		mant |= uint64(1) << flt.mantbits
    48  	}
    49  	exp += flt.bias
    50  
    51  	// Pick off easy binary, hex formats.
    52  	if fmt == 'b' {
    53  		fmtB(dst, neg, mant, exp, flt)
    54  		return
    55  	}
    56  	if fmt == 'x' || fmt == 'X' {
    57  		fmtX(dst, prec, fmt, neg, mant, exp, flt)
    58  		return
    59  	}
    60  
    61  	if !optimize {
    62  		bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
    63  		return
    64  	}
    65  
    66  	var digs decimalSlice
    67  	ok := false
    68  	// Negative precision means "only as much as needed to be exact."
    69  	shortest := prec < 0
    70  	if shortest {
    71  		// Use Ryu algorithm.
    72  		var buf [32]byte
    73  		digs.d = buf[:]
    74  		ryuFtoaShortest(&digs, mant, exp-int(flt.mantbits), flt)
    75  		ok = true
    76  		// Precision for shortest representation mode.
    77  		switch fmt {
    78  		case 'e', 'E':
    79  			prec = max(digs.nd-1, 0)
    80  		case 'f':
    81  			prec = max(digs.nd-digs.dp, 0)
    82  		case 'g', 'G':
    83  			prec = digs.nd
    84  		}
    85  	} else if fmt != 'f' {
    86  		// Fixed number of digits.
    87  		digits := prec
    88  		switch fmt {
    89  		case 'e', 'E':
    90  			digits++
    91  		case 'g', 'G':
    92  			if prec == 0 {
    93  				prec = 1
    94  			}
    95  			digits = prec
    96  		default:
    97  			// Invalid mode.
    98  			digits = 1
    99  		}
   100  		var buf [24]byte
   101  		if bitSize == 32 && digits <= 9 {
   102  			digs.d = buf[:]
   103  			ryuFtoaFixed32(&digs, uint32(mant), exp-int(flt.mantbits), digits)
   104  			ok = true
   105  		} else if digits <= 18 {
   106  			digs.d = buf[:]
   107  			ryuFtoaFixed64(&digs, mant, exp-int(flt.mantbits), digits)
   108  			ok = true
   109  		}
   110  	}
   111  	if !ok {
   112  		bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
   113  		return
   114  	}
   115  	formatDigits(dst, shortest, neg, digs, prec, fmt)
   116  }
   117  
   118  // bigFtoa uses multiprecision computations to format a float.
   119  func bigFtoa(dst *[]byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) {
   120  	d := new(decimal)
   121  	d.Assign(mant)
   122  	d.Shift(exp - int(flt.mantbits))
   123  	var digs decimalSlice
   124  	shortest := prec < 0
   125  	if shortest {
   126  		roundShortest(d, mant, exp, flt)
   127  		digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
   128  		// Precision for shortest representation mode.
   129  		switch fmt {
   130  		case 'e', 'E':
   131  			prec = digs.nd - 1
   132  		case 'f':
   133  			prec = max(digs.nd-digs.dp, 0)
   134  		case 'g', 'G':
   135  			prec = digs.nd
   136  		}
   137  	} else {
   138  		// Round appropriately.
   139  		switch fmt {
   140  		case 'e', 'E':
   141  			d.Round(prec + 1)
   142  		case 'f':
   143  			d.Round(d.dp + prec)
   144  		case 'g', 'G':
   145  			if prec == 0 {
   146  				prec = 1
   147  			}
   148  			d.Round(prec)
   149  		}
   150  		digs = decimalSlice{d: d.d[:], nd: d.nd, dp: d.dp}
   151  	}
   152  	formatDigits(dst, shortest, neg, digs, prec, fmt)
   153  }
   154  
   155  // TODO: move elsewhere?
   156  type floatInfo struct {
   157  	mantbits uint
   158  	expbits  uint
   159  	bias     int
   160  }
   161  
   162  func formatDigits(dst *[]byte, shortest bool, neg bool, digs decimalSlice, prec int, fmt byte) {
   163  	switch fmt {
   164  	case 'e', 'E':
   165  		fmtE(dst, neg, digs, prec, fmt)
   166  		return
   167  	case 'f':
   168  		fmtF(dst, neg, digs, prec)
   169  		return
   170  	case 'g', 'G':
   171  		// trailing fractional zeros in 'e' form will be trimmed.
   172  		eprec := prec
   173  		if eprec > digs.nd && digs.nd >= digs.dp {
   174  			eprec = digs.nd
   175  		}
   176  		// %e is used if the exponent from the conversion
   177  		// is less than -4 or greater than or equal to the precision.
   178  		// if precision was the shortest possible, use precision 6 for this decision.
   179  		if shortest {
   180  			eprec = 6
   181  		}
   182  		exp := digs.dp - 1
   183  		if exp < -4 || exp >= eprec {
   184  			if prec > digs.nd {
   185  				prec = digs.nd
   186  			}
   187  			fmtE(dst, neg, digs, prec-1, fmt+'e'-'g')
   188  			return
   189  		}
   190  		if prec > digs.dp {
   191  			prec = digs.nd
   192  		}
   193  		fmtF(dst, neg, digs, max(prec-digs.dp, 0))
   194  		return
   195  	}
   196  
   197  	// unknown format
   198  	*dst = append(*dst, '%', fmt)
   199  }
   200  
   201  // roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
   202  // that will let the original floating point value be precisely reconstructed.
   203  func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
   204  	// If mantissa is zero, the number is zero; stop now.
   205  	if mant == 0 {
   206  		d.nd = 0
   207  		return
   208  	}
   209  
   210  	// Compute upper and lower such that any decimal number
   211  	// between upper and lower (possibly inclusive)
   212  	// will round to the original floating point number.
   213  
   214  	// We may see at once that the number is already shortest.
   215  	//
   216  	// Suppose d is not denormal, so that 2^exp <= d < 10^dp.
   217  	// The closest shorter number is at least 10^(dp-nd) away.
   218  	// The lower/upper bounds computed below are at distance
   219  	// at most 2^(exp-mantbits).
   220  	//
   221  	// So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
   222  	// or equivalently log2(10)*(dp-nd) > exp-mantbits.
   223  	// It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
   224  	minexp := flt.bias + 1 // minimum possible exponent
   225  	if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
   226  		// The number is already shortest.
   227  		return
   228  	}
   229  
   230  	// d = mant << (exp - mantbits)
   231  	// Next highest floating point number is mant+1 << exp-mantbits.
   232  	// Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
   233  	upper := new(decimal)
   234  	upper.Assign(mant*2 + 1)
   235  	upper.Shift(exp - int(flt.mantbits) - 1)
   236  
   237  	// d = mant << (exp - mantbits)
   238  	// Next lowest floating point number is mant-1 << exp-mantbits,
   239  	// unless mant-1 drops the significant bit and exp is not the minimum exp,
   240  	// in which case the next lowest is mant*2-1 << exp-mantbits-1.
   241  	// Either way, call it mantlo << explo-mantbits.
   242  	// Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
   243  	var mantlo uint64
   244  	var explo int
   245  	if mant > 1<<flt.mantbits || exp == minexp {
   246  		mantlo = mant - 1
   247  		explo = exp
   248  	} else {
   249  		mantlo = mant*2 - 1
   250  		explo = exp - 1
   251  	}
   252  	lower := new(decimal)
   253  	lower.Assign(mantlo*2 + 1)
   254  	lower.Shift(explo - int(flt.mantbits) - 1)
   255  
   256  	// The upper and lower bounds are possible outputs only if
   257  	// the original mantissa is even, so that IEEE round-to-even
   258  	// would round to the original mantissa and not the neighbors.
   259  	inclusive := mant%2 == 0
   260  
   261  	// As we walk the digits we want to know whether rounding up would fall
   262  	// within the upper bound. This is tracked by upperdelta:
   263  	//
   264  	// If upperdelta == 0, the digits of d and upper are the same so far.
   265  	//
   266  	// If upperdelta == 1, we saw a difference of 1 between d and upper on a
   267  	// previous digit and subsequently only 9s for d and 0s for upper.
   268  	// (Thus rounding up may fall outside the bound, if it is exclusive.)
   269  	//
   270  	// If upperdelta == 2, then the difference is greater than 1
   271  	// and we know that rounding up falls within the bound.
   272  	var upperdelta uint8
   273  
   274  	// Now we can figure out the minimum number of digits required.
   275  	// Walk along until d has distinguished itself from upper and lower.
   276  	for ui := 0; ; ui++ {
   277  		// lower, d, and upper may have the decimal points at different
   278  		// places. In this case upper is the longest, so we iterate from
   279  		// ui==0 and start li and mi at (possibly) -1.
   280  		mi := ui - upper.dp + d.dp
   281  		if mi >= d.nd {
   282  			break
   283  		}
   284  		li := ui - upper.dp + lower.dp
   285  		l := byte('0') // lower digit
   286  		if li >= 0 && li < lower.nd {
   287  			l = lower.d[li]
   288  		}
   289  		m := byte('0') // middle digit
   290  		if mi >= 0 {
   291  			m = d.d[mi]
   292  		}
   293  		u := byte('0') // upper digit
   294  		if ui < upper.nd {
   295  			u = upper.d[ui]
   296  		}
   297  
   298  		// Okay to round down (truncate) if lower has a different digit
   299  		// or if lower is inclusive and is exactly the result of rounding
   300  		// down (i.e., and we have reached the final digit of lower).
   301  		okdown := l != m || inclusive && li+1 == lower.nd
   302  
   303  		switch {
   304  		case upperdelta == 0 && m+1 < u:
   305  			// Example:
   306  			// m = 12345xxx
   307  			// u = 12347xxx
   308  			upperdelta = 2
   309  		case upperdelta == 0 && m != u:
   310  			// Example:
   311  			// m = 12345xxx
   312  			// u = 12346xxx
   313  			upperdelta = 1
   314  		case upperdelta == 1 && (m != '9' || u != '0'):
   315  			// Example:
   316  			// m = 1234598x
   317  			// u = 1234600x
   318  			upperdelta = 2
   319  		}
   320  		// Okay to round up if upper has a different digit and either upper
   321  		// is inclusive or upper is bigger than the result of rounding up.
   322  		okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd)
   323  
   324  		// If it's okay to do either, then round to the nearest one.
   325  		// If it's okay to do only one, do it.
   326  		switch {
   327  		case okdown && okup:
   328  			d.Round(mi + 1)
   329  			return
   330  		case okdown:
   331  			d.RoundDown(mi + 1)
   332  			return
   333  		case okup:
   334  			d.RoundUp(mi + 1)
   335  			return
   336  		}
   337  	}
   338  }
   339  
   340  type decimalSlice struct {
   341  	d      []byte
   342  	nd, dp int
   343  	neg    bool
   344  }
   345  
   346  // %e: -d.ddddde±dd
   347  func fmtE(dst *[]byte, neg bool, d decimalSlice, prec int, fmt byte) {
   348  	// sign
   349  	if neg {
   350  		*dst = append(*dst, '-')
   351  	}
   352  
   353  	// first digit
   354  	ch := byte('0')
   355  	if d.nd != 0 {
   356  		ch = d.d[0]
   357  	}
   358  	*dst = append(*dst, ch)
   359  
   360  	// .moredigits
   361  	if prec > 0 {
   362  		*dst = append(*dst, '.')
   363  		i := 1
   364  		m := min(d.nd, prec+1)
   365  		if i < m {
   366  			*dst = append(*dst, d.d[i:m]...)
   367  			i = m
   368  		}
   369  		for ; i <= prec; i++ {
   370  			*dst = append(*dst, '0')
   371  		}
   372  	}
   373  
   374  	// e±
   375  	*dst = append(*dst, fmt)
   376  	exp := d.dp - 1
   377  	if d.nd == 0 { // special case: 0 has exponent 0
   378  		exp = 0
   379  	}
   380  	if exp < 0 {
   381  		ch = '-'
   382  		exp = -exp
   383  	} else {
   384  		ch = '+'
   385  	}
   386  	*dst = append(*dst, ch)
   387  
   388  	// dd or ddd
   389  	switch {
   390  	case exp < 10:
   391  		*dst = append(*dst, '0', byte(exp)+'0')
   392  	case exp < 100:
   393  		*dst = append(*dst, byte(exp/10)+'0', byte(exp%10)+'0')
   394  	default:
   395  		*dst = append(*dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
   396  	}
   397  
   398  }
   399  
   400  // %f: -ddddddd.ddddd
   401  func fmtF(dst *[]byte, neg bool, d decimalSlice, prec int) {
   402  	// sign
   403  	if neg {
   404  		*dst = append(*dst, '-')
   405  	}
   406  
   407  	// integer, padded with zeros as needed.
   408  	if d.dp > 0 {
   409  		m := min(d.nd, d.dp)
   410  		*dst = append(*dst, d.d[:m]...)
   411  		for ; m < d.dp; m++ {
   412  			*dst = append(*dst, '0')
   413  		}
   414  	} else {
   415  		*dst = append(*dst, '0')
   416  	}
   417  
   418  	// fraction
   419  	if prec > 0 {
   420  		*dst = append(*dst, '.')
   421  		for i := 0; i < prec; i++ {
   422  			ch := byte('0')
   423  			if j := d.dp + i; 0 <= j && j < d.nd {
   424  				ch = d.d[j]
   425  			}
   426  			*dst = append(*dst, ch)
   427  		}
   428  	}
   429  
   430  }
   431  
   432  // %b: -ddddddddp±ddd
   433  func fmtB(dst *[]byte, neg bool, mant uint64, exp int, flt *floatInfo) {
   434  	// sign
   435  	if neg {
   436  		*dst = append(*dst, '-')
   437  	}
   438  
   439  	// mantissa
   440  	formatBits(dst, mant, 10, false)
   441  
   442  	// p
   443  	*dst = append(*dst, 'p')
   444  
   445  	// ±exponent
   446  	exp -= int(flt.mantbits)
   447  	if exp >= 0 {
   448  		*dst = append(*dst, '+')
   449  	}
   450  	formatBits(dst, uint64(exp), 10, exp < 0)
   451  }
   452  
   453  // %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit)
   454  func fmtX(dst *[]byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) {
   455  	if mant == 0 {
   456  		exp = 0
   457  	}
   458  
   459  	// Shift digits so leading 1 (if any) is at bit 1<<60.
   460  	mant <<= 60 - flt.mantbits
   461  	for mant != 0 && mant&(1<<60) == 0 {
   462  		mant <<= 1
   463  		exp--
   464  	}
   465  
   466  	// Round if requested.
   467  	if prec >= 0 && prec < 15 {
   468  		shift := uint(prec * 4)
   469  		extra := (mant << shift) & (1<<60 - 1)
   470  		mant >>= 60 - shift
   471  		if extra|(mant&1) > 1<<59 {
   472  			mant++
   473  		}
   474  		mant <<= 60 - shift
   475  		if mant&(1<<61) != 0 {
   476  			// Wrapped around.
   477  			mant >>= 1
   478  			exp++
   479  		}
   480  	}
   481  
   482  	hex := lowerhex
   483  	if fmt == 'X' {
   484  		hex = upperhex
   485  	}
   486  
   487  	// sign, 0x, leading digit
   488  	if neg {
   489  		*dst = append(*dst, '-')
   490  	}
   491  	*dst = append(*dst, '0', fmt, '0'+byte((mant>>60)&1))
   492  
   493  	// .fraction
   494  	mant <<= 4 // remove leading 0 or 1
   495  	if prec < 0 && mant != 0 {
   496  		*dst = append(*dst, '.')
   497  		for mant != 0 {
   498  			*dst = append(*dst, hex[(mant>>60)&15])
   499  			mant <<= 4
   500  		}
   501  	} else if prec > 0 {
   502  		*dst = append(*dst, '.')
   503  		for i := 0; i < prec; i++ {
   504  			*dst = append(*dst, hex[(mant>>60)&15])
   505  			mant <<= 4
   506  		}
   507  	}
   508  
   509  	// p±
   510  	ch := byte('P')
   511  	if fmt == lower(fmt) {
   512  		ch = 'p'
   513  	}
   514  	*dst = append(*dst, ch)
   515  	if exp < 0 {
   516  		ch = '-'
   517  		exp = -exp
   518  	} else {
   519  		ch = '+'
   520  	}
   521  	*dst = append(*dst, ch)
   522  
   523  	// dd or ddd or dddd
   524  	switch {
   525  	case exp < 100:
   526  		*dst = append(*dst, byte(exp/10)+'0', byte(exp%10)+'0')
   527  	case exp < 1000:
   528  		*dst = append(*dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   529  	default:
   530  		*dst = append(*dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
   531  	}
   532  }
   533  
   534  func min(a, b int) int {
   535  	if a < b {
   536  		return a
   537  	}
   538  	return b
   539  }
   540  
   541  func max(a, b int) int {
   542  	if a > b {
   543  		return a
   544  	}
   545  	return b
   546  }
   547  
   548  const (
   549  	lowerhex = "0123456789abcdef"
   550  	upperhex = "0123456789ABCDEF"
   551  )
   552  
   553  func lower(c byte) byte {
   554  	return c | ('x' - 'X')
   555  }