// Copyright 2009 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.

// Binary to decimal floating point conversion.
// Algorithm:
//   1) store mantissa in multiprecision decimal
//   2) shift decimal by exponent
//   3) read digits out & format

package strconv

import (
	
	
)

const (
	lowerhex = "0123456789abcdef"
	upperhex = "0123456789ABCDEF"
)

const (
	float32MantBits = 23
	float32ExpBits  = 8
	float32Bias     = -127
	float32MinExp   = -189

	float64MantBits = 52
	float64ExpBits  = 11
	float64Bias     = -1023
	float64MinExp   = -1085
)

// FormatFloat converts the floating-point number f to a string,
// according to the format fmt and precision prec. It rounds the
// result assuming that the original was obtained from a floating-point
// value of bitSize bits (32 for float32, 64 for float64).
//
// The format fmt is one of
//   - 'b' (-ddddp±ddd, a binary exponent),
//   - 'e' (-d.dddde±dd, a decimal exponent),
//   - 'E' (-d.ddddE±dd, a decimal exponent),
//   - 'f' (-ddd.dddd, no exponent),
//   - 'g' ('e' for large exponents, 'f' otherwise),
//   - 'G' ('E' for large exponents, 'f' otherwise),
//   - 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or
//   - 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).
//
// The precision prec controls the number of digits (excluding the exponent)
// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats.
// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point.
// For 'g' and 'G' it is the maximum number of significant digits (trailing
// zeros are removed).
// The special precision -1 uses the smallest number of digits
// necessary such that ParseFloat will return f exactly.
// The exponent is written as a decimal integer;
// for all formats other than 'b', it will be at least two digits.
func ( float64,  byte, ,  int) string {
	if  == 32 {
		return string(ftoa32(make([]byte, 0, max(+4, 24)), float32(), , ))
	}
	if  == 64 {
		return string(ftoa64(make([]byte, 0, max(+4, 24)), , , ))
	}
	panic("strconv: illegal FormatFloat bitSize")
}

// AppendFloat appends the string form of the floating-point number f,
// as generated by [FormatFloat], to dst and returns the extended buffer.
func ( []byte,  float64,  byte, ,  int) []byte {
	if  == 32 {
		return ftoa32(, float32(), , )
	}
	if  == 64 {
		return ftoa64(, , , )
	}
	panic("strconv: illegal AppendFloat bitSize")
}

// TODO(rsc): This should be ftoa[F float32 | float64](dst []byte, val F, ...),
// but due to some bad interaction between inlining, escape analysis, and generic functions,
// the result appears to escape dst to the heap with -l=4, which breaks
// TestAbstractOriginSanity. See go.dev/issue/79547.
// For now we make two manual specializations ftoa32 and ftoa64 instead.

func ( []byte,  float32,  byte,  int) []byte {
	type  = float32
	var  uint64
	var , ,  int // parameterized constants
	switch 8 * unsafe.Sizeof() {
	case 32:
		 = uint64(float32bits(float32()))
		 = float32ExpBits
		 = float32MantBits
		 = float32Bias
	case 64:
		 = float64bits(float64())
		 = float64ExpBits
		 = float64MantBits
		 = float64Bias
	}

	 := >>(+) != 0
	 := int(>>) & (1<< - 1)
	 :=  & (1<< - 1)
	if  == 1<<-1 {
		if  != 0 {
			return append(, "NaN"...)
		}
		if  {
			return append(, "-Inf"...)
		}
		return append(, "+Inf"...)
	}
	if  == 0 {
		++
	} else {
		 |= 1 << 
	}
	 += 

	// Pick off easy binary, hex formats.
	if  == 'b' {
		return fmtB(, , , -)
	}
	if  == 'x' ||  == 'X' {
		return fmtX(, , , , , , )
	}

	// Pick off zero.
	if  == 0 {
		return fmtEFG(, , nil, 0, 0, , ,  < 0)
	}

	// Negative precision means "only as much as needed to be exact."
	if  < 0 {
		// Use fast unrounded scaling.
		var  [32]byte
		 := 64 - bits.Len64()
		 :=  << 
		 :=  - 
		,  := shortFloat[](, -)
		,  := setDigits([:], , , numDigits())
		// Precision for shortest representation mode.
		switch  {
		case 'e', 'E':
			 = max(-1, 0)
		case 'f':
			 = max(-, 0)
		case 'g', 'G':
			 = 
		}
		return fmtEFG(, , [:], , , , , true)
	}

	if optimize {
		// Fixed number of digits.
		 := 
		switch  {
		case 'f':
			// %f precision specifies digits after the decimal point.
			// Estimate an upper bound on the total number of digits needed.
			// ftoaFixed will shorten as needed according to prec.
			if  >= 0 {
				 = 1 + log10Pow2(1+) + 
			} else {
				 = 1 +  - log10Pow2(-)
			}
		case 'e', 'E':
			++
		case 'g', 'G':
			if  == 0 {
				 = 1
			}
			 = 
		default:
			// Invalid mode.
			 = 1
		}
		if  <= 18 {
			// digits <= 0 happens for %f on very small numbers
			// and means that we're guaranteed to print all zeros.
			var  [24]byte
			var ,  int
			if  > 0 {
				 := 64 - bits.Len64()
				 :=  << 
				 :=  - 
				,  := fixedWidthFloat(, -, , , )
				if  != 0 {
					,  = setDigits([:], , , numDigits())
				}
			}
			return fmtEFG(, , [:], , , , , false)
		}
	}

	// Slow bignum case. Only for non-shortest results.
	 := new(decimal)
	.Assign()
	.Shift( - )
	switch  {
	case 'e', 'E':
		.Round( + 1)
	case 'f':
		.Round(.dp + )
	case 'g', 'G':
		if  == 0 {
			 = 1
		}
		.Round()
	}
	return fmtEFG(, , .d[:], .dp, .nd, , , false)
}

func ( []byte,  float64,  byte,  int) []byte {
	type  = float64
	var  uint64
	var , ,  int // parameterized constants
	switch 8 * unsafe.Sizeof() {
	case 32:
		 = uint64(float32bits(float32()))
		 = float32ExpBits
		 = float32MantBits
		 = float32Bias
	case 64:
		 = float64bits(float64())
		 = float64ExpBits
		 = float64MantBits
		 = float64Bias
	}

	 := >>(+) != 0
	 := int(>>) & (1<< - 1)
	 :=  & (1<< - 1)
	if  == 1<<-1 {
		if  != 0 {
			return append(, "NaN"...)
		}
		if  {
			return append(, "-Inf"...)
		}
		return append(, "+Inf"...)
	}
	if  == 0 {
		++
	} else {
		 |= 1 << 
	}
	 += 

	// Pick off easy binary, hex formats.
	if  == 'b' {
		return fmtB(, , , -)
	}
	if  == 'x' ||  == 'X' {
		return fmtX(, , , , , , )
	}

	// Pick off zero.
	if  == 0 {
		return fmtEFG(, , nil, 0, 0, , ,  < 0)
	}

	// Negative precision means "only as much as needed to be exact."
	if  < 0 {
		// Use fast unrounded scaling.
		var  [32]byte
		 := 64 - bits.Len64()
		 :=  << 
		 :=  - 
		,  := shortFloat[](, -)
		,  := setDigits([:], , , numDigits())
		// Precision for shortest representation mode.
		switch  {
		case 'e', 'E':
			 = max(-1, 0)
		case 'f':
			 = max(-, 0)
		case 'g', 'G':
			 = 
		}
		return fmtEFG(, , [:], , , , , true)
	}

	if optimize {
		// Fixed number of digits.
		 := 
		switch  {
		case 'f':
			// %f precision specifies digits after the decimal point.
			// Estimate an upper bound on the total number of digits needed.
			// ftoaFixed will shorten as needed according to prec.
			if  >= 0 {
				 = 1 + log10Pow2(1+) + 
			} else {
				 = 1 +  - log10Pow2(-)
			}
		case 'e', 'E':
			++
		case 'g', 'G':
			if  == 0 {
				 = 1
			}
			 = 
		default:
			// Invalid mode.
			 = 1
		}
		if  <= 18 {
			// digits <= 0 happens for %f on very small numbers
			// and means that we're guaranteed to print all zeros.
			var  [24]byte
			var ,  int
			if  > 0 {
				 := 64 - bits.Len64()
				 :=  << 
				 :=  - 
				,  := fixedWidthFloat(, -, , , )
				if  != 0 {
					,  = setDigits([:], , , numDigits())
				}
			}
			return fmtEFG(, , [:], , , , , false)
		}
	}

	// Slow bignum case. Only for non-shortest results.
	 := new(decimal)
	.Assign()
	.Shift( - )
	switch  {
	case 'e', 'E':
		.Round( + 1)
	case 'f':
		.Round(.dp + )
	case 'g', 'G':
		if  == 0 {
			 = 1
		}
		.Round()
	}
	return fmtEFG(, , .d[:], .dp, .nd, , , false)
}

func ( []byte,  bool,  []byte, , ,  int,  byte,  bool) []byte {
	if  == 'g' ||  == 'G' {
		// trailing fractional zeros in 'e' form will be trimmed.
		 := 
		if  >  &&  >=  {
			 = 
		}
		// %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 precision 6 for this decision.
		if  {
			 = 6
		}
		 :=  - 1
		if  < -4 ||  >=  {
			if  >  {
				 = 
			}
			--
			 =  + 'e' - 'g'
		} else {
			if  >  {
				 = 
			}
			 = max(-, 0)
			 = 'f'
		}
	}

	switch  {
	case 'e', 'E': // %e: -d.ddddde±dd
		// sign
		if  {
			 = append(, '-')
		}

		// first digit
		 := byte('0')
		if  != 0 {
			 = [0]
		}
		 = append(, )

		// .moredigits
		if  > 0 {
			 = append(, '.')
			 := 1
			 := min(, +1)
			if  <  {
				 = append(, [:]...)
				 = 
			}
			for range  + 1 -  {
				 = append(, '0')
			}
		}

		// e±
		 = append(, )
		 :=  - 1
		if  == 0 { // special case: 0 has exponent 0
			 = 0
		}
		if  < 0 {
			 = '-'
			 = -
		} else {
			 = '+'
		}
		 = append(, )

		// dd or ddd
		switch {
		case  < 10:
			 = append(, '0', byte()+'0')
		case  < 100:
			 = append(, byte(/10)+'0', byte(%10)+'0')
		default:
			 = append(, byte(/100)+'0', byte(/10)%10+'0', byte(%10)+'0')
		}
		return 

	case 'f': // %f: -ddddddd.ddddd
		// sign
		if  {
			 = append(, '-')
		}

		// integer, padded with zeros as needed.
		if  > 0 {
			 := min(, )
			for ,  := range [:] {
				 = append(, )
			}
			for range  -  {
				 = append(, '0')
			}
		} else {
			 = append(, '0')
		}

		// fraction
		if  > 0 {
			 = append(, '.')
			 := min(, max(0, -)) // leading zeros
			 :=  + 
			 := min(-, max(0, -)) // middle digits
			 := max(0, --)           // trailing zeros
			for range  {
				 = append(, '0')
			}
			for  := range  {
				 = append(, [+])
			}
			for range  {
				 = append(, '0')
			}
		}
		return 
	}

	// unknown format
	return append(, '%', )
}

// %b: -ddddddddp±ddd
func ( []byte,  bool,  uint64,  int) []byte {
	if  {
		 = append(, '-')
	}
	 = AppendUint(, , 10)
	 = append(, 'p')
	if  >= 0 {
		 = append(, '+')
	}
	 = AppendInt(, int64(), 10)
	return 
}

// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit)
func ( []byte,  int,  byte,  bool,  uint64, ,  int) []byte {
	if  == 0 {
		 = 0
	}

	// Shift digits so leading 1 (if any) is at bit 1<<60.
	// TODO: Is this the right way to handle subnormals?
	 <<= 60 - 
	for  != 0 && &(1<<60) == 0 {
		 <<= 1
		--
	}

	// Round if requested.
	if  >= 0 &&  < 15 {
		 := uint( * 4)
		 := ( << ) & (1<<60 - 1)
		 >>= 60 - 
		if |(&1) > 1<<59 {
			++
		}
		 <<= 60 - 
		if &(1<<61) != 0 {
			// Wrapped around.
			 >>= 1
			++
		}
	}

	 := lowerhex
	if  == 'X' {
		 = upperhex
	}

	// sign, 0x, leading digit
	if  {
		 = append(, '-')
	}
	 = append(, '0', , '0'+byte((>>60)&1))

	// .fraction
	 <<= 4 // remove leading 0 or 1
	if  < 0 &&  != 0 {
		 = append(, '.')
		for  != 0 {
			 = append(, [(>>60)&15])
			 <<= 4
		}
	} else if  > 0 {
		 = append(, '.')
		for  := 0;  < ; ++ {
			 = append(, [(>>60)&15])
			 <<= 4
		}
	}

	// p±
	 := byte('P')
	if  == lower() {
		 = 'p'
	}
	 = append(, )
	if  < 0 {
		 = '-'
		 = -
	} else {
		 = '+'
	}
	 = append(, )

	// dd or ddd or dddd
	switch {
	case  < 100:
		 = append(, byte(/10)+'0', byte(%10)+'0')
	case  < 1000:
		 = append(, byte(/100)+'0', byte((/10)%10)+'0', byte(%10)+'0')
	default:
		 = append(, byte(/1000)+'0', byte(/100)%10+'0', byte((/10)%10)+'0', byte(%10)+'0')
	}

	return 
}