package ftoa

import (
	
	
)

const (
	exp_11     = 0x3ff00000
	frac_mask1 = 0xfffff
	bletch     = 0x10
	quick_max  = 14
	int_max    = 14
)

var (
	tens = [...]float64{
		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
		1e20, 1e21, 1e22,
	}

	bigtens = [...]float64{1e16, 1e32, 1e64, 1e128, 1e256}

	big5  = big.NewInt(5)
	big10 = big.NewInt(10)

	p05       = []*big.Int{big5, big.NewInt(25), big.NewInt(125)}
	pow5Cache [7]*big.Int

	dtoaModes = []int{
		ModeStandard:            0,
		ModeStandardExponential: 0,
		ModeFixed:               3,
		ModeExponential:         2,
		ModePrecision:           2,
	}
)

/*
d must be > 0 and must not be Inf

mode:

	0 ==> shortest string that yields d when read in
		and rounded to nearest.
	1 ==> like 0, but with Steele & White stopping rule;
		e.g. with IEEE P754 arithmetic , mode 0 gives
		1e23 whereas mode 1 gives 9.999999999999999e22.
	2 ==> max(1,ndigits) significant digits.  This gives a
		return value similar to that of ecvt, except
		that trailing zeros are suppressed.
	3 ==> through ndigits past the decimal point.  This
		gives a return value similar to that from fcvt,
		except that trailing zeros are suppressed, and
		ndigits can be negative.
	4,5 ==> similar to 2 and 3, respectively, but (in
		round-nearest mode) with the tests of mode 0 to
		possibly return a shorter string that rounds to d.
		With IEEE arithmetic and compilation with
		-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
		as modes 2 and 3 when FLT_ROUNDS != 1.
	6-9 ==> Debugging modes similar to mode - 4:  don't try
		fast floating-point estimate (if applicable).

	Values of mode other than 0-9 are treated as mode 0.
*/
func ftoa( float64,  int,  bool,  int,  []byte) ([]byte, int) {
	 := len()
	 := make([]byte, 0, 8)
	, ,  := d2b(, )

	 := math.Float64bits()
	 := uint32( >> 32)
	 := uint32()

	 := int(( >> exp_shift1) & (exp_mask >> exp_shift1))
	var  float64
	var  bool
	if  != 0 {
		 = setWord0(, (&frac_mask1)|exp_11)
		 -= bias
		 = false
	} else {
		/* d is denormalized */
		 =  +  + (bias + (p - 1) - 1)
		var  uint64
		if  > 32 {
			 = uint64()<<(64-) | uint64()>>(-32)
		} else {
			 = uint64() << (32 - )
		}
		 = setWord0(float64(), uint32((>>32)-31*exp_mask))
		 -= (bias + (p - 1) - 1) + 1
		 = true
	}
	/* At this point d = f*2^i, where 1 <= f < 2.  d2 is an approximation of f. */
	 := (-1.5)*0.289529654602168 + 0.1760912590558 + float64()*0.301029995663981
	 := int()
	if  < 0.0 &&  != float64() {
		-- /* want k = floor(ds) */
	}
	 := true
	if  >= 0 &&  < len(tens) {
		if  < tens[] {
			--
		}
		 = false
	}
	/* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
	   If k_check is zero, we're guaranteed that k = floor(log10(d)). */
	 :=  -  - 1
	var , , ,  int
	/* At this point d = b/2^j, where b is an odd integer. */
	if  >= 0 {
		 = 0
		 = 
	} else {
		 = -
		 = 0
	}
	if  >= 0 {
		 = 0
		 = 
		 += 
	} else {
		 -= 
		 = -
		 = 0
	}
	/* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
	   b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
	if  < 0 ||  > 9 {
		 = 0
	}
	 := true
	if  > 5 {
		 -= 4
		 = false
	}
	 := true
	var ,  int
	switch  {
	case 0, 1:
		,  = -1, -1
		 = 0
	case 2:
		 = false
		fallthrough
	case 4:
		if  <= 0 {
			 = 1
		}
		,  = , 
	case 3:
		 = false
		fallthrough
	case 5:
		 =  +  + 1
		 = 
		 =  - 1
	}
	/* ilim is the maximum number of significant digits we want, based on k and ndigits. */
	/* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
	   when it turns out that k was computed too high by one. */
	 := false
	if  >= 0 &&  <= quick_max &&  {

		/* Try to get by with floating-point arithmetic. */

		 = 0
		 = 
		 := 
		 := 
		 := 2 /* conservative */
		/* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
		if  > 0 {
			 = tens[&0xf]
			 =  >> 4
			if ( & bletch) != 0 {
				/* prevent overflows */
				 &= bletch - 1
				 /= bigtens[len(bigtens)-1]
				++
			}
			for ;  != 0; ++ {
				if ( & 1) != 0 {
					++
					 *= bigtens[]
				}
				 >>= 1
			}
			 /= 
		} else if  := -;  != 0 {
			 *= tens[&0xf]
			for  =  >> 4;  != 0; ++ {
				if ( & 1) != 0 {
					++
					 *= bigtens[]
				}
				 >>= 1
			}
		}
		/* Check that k was computed correctly. */
		if  &&  < 1.0 &&  > 0 {
			if  <= 0 {
				 = true
			} else {
				 = 
				--
				 *= 10.
				++
			}
		}
		/* eps bounds the cumulative error. */
		 := float64()* + 7.0
		 = setWord0(, _word0()-(p-1)*exp_msk1)
		if  == 0 {
			 -= 5.0
			if  >  {
				 = append(, '1')
				++
				return ,  + 1
			}
			if  < - {
				 = append(, '0')
				return , 1
			}
			 = true
		}
		if ! {
			 = true
			if  {
				/* Use Steele & White method of only
				 * generating digits needed.
				 */
				 = 0.5/tens[-1] - 
				for  = 0; ; {
					 := int64()
					 -= float64()
					 = append(, byte('0'+))
					if  <  {
						return ,  + 1
					}
					if 1.0- <  {
						,  = bumpUp(, )
						return ,  + 1
					}
					++
					if  >=  {
						break
					}
					 *= 10.0
					 *= 10.0
				}
			} else {
				/* Generate ilim digits, then fix them up. */
				 *= tens[-1]
				for  = 1; ; ++ {
					 := int64()
					 -= float64()
					 = append(, byte('0'+))
					if  ==  {
						if  > 0.5+ {
							,  = bumpUp(, )
							return ,  + 1
						} else if  < 0.5- {
							 = stripTrailingZeroes(, )
							return ,  + 1
						}
						break
					}
					 *= 10.0
				}
			}
		}
		if  {
			 = [:]
			 = 
			 = 
			 = 
		}
	}

	/* Do we have a "small" integer? */
	if  >= 0 &&  <= int_max {
		/* Yes. */
		 = tens[]
		if  < 0 &&  <= 0 {
			if  < 0 ||  < 5* || (! &&  == 5*) {
				 = [:]
				 = append(, '0')
				return , 1
			}
			 = append(, '1')
			++
			return ,  + 1
		}
		for  = 1; ; ++ {
			 := int64( / )
			 -= float64() * 
			 = append(, byte('0'+))
			if  ==  {
				 += 
				if ( > ) || ( ==  && ((( & 1) != 0) || )) {
					,  = bumpUp(, )
				}
				break
			}
			 *= 10.0
			if  == 0 {
				break
			}
		}
		return ,  + 1
	}

	 := 
	 := 
	var ,  *big.Int
	if  {
		if  < 2 {
			if  {
				 =  + (bias + (p - 1) - 1 + 1)
			} else {
				 = 1 + p - 
			}
			/* i is 1 plus the number of trailing zero bits in d's significand. Thus,
			   (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
		} else {
			 =  - 1
			if  >=  {
				 -= 
			} else {
				 -= 
				 += 
				 += 
				 = 0
			}
			 = 
			if  < 0 {
				 -= 
				 = 0
			}
			/* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
		}
		 += 
		 += 
		 = big.NewInt(1)
		/* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
		   input (when mode < 2) significant digit, divided by 10^k. */
	}

	/* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5).  Reduce common factors in
	   b2, m2, and s2 without changing the equalities. */
	if  > 0 &&  > 0 {
		if  <  {
			 = 
		} else {
			 = 
		}
		 -= 
		 -= 
		 -= 
	}

	 := new(big.Int).SetBytes()
	/* Fold b5 into b and m5 into mhi. */
	if  > 0 {
		if  {
			if  > 0 {
				pow5mult(, )
				.Mul(, )
			}
			 =  - 
			if  != 0 {
				pow5mult(, )
			}
		} else {
			pow5mult(, )
		}
	}
	/* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
	   (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */

	 := big.NewInt(1)
	if  > 0 {
		pow5mult(, )
	}
	/* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
	   (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */

	/* Check for special case that d is a normalized power of 2. */
	 := false
	if  < 2 {
		if (_word1() == 0) && ((_word0() & bndry_mask) == 0) &&
			((_word0() & (exp_mask & (exp_mask << 1))) != 0) {
			/* The special case.  Here we want to be within a quarter of the last input
			   significant digit instead of one half of it when the decimal output string's value is less than d.  */
			 += log2P
			 += log2P
			 = true
		}
	}

	/* Arrange for convenient computation of quotients:
	 * shift left if necessary so divisor has 4 leading 0 bits.
	 *
	 * Perhaps we should just compute leading 28 bits of S once
	 * and for all and pass them and a shift to quorem, so it
	 * can do shifts and ors to compute the numerator for q.
	 */
	var  int
	if  != 0 {
		 := .Bytes()
		var  uint32
		for  := 0;  < 4; ++ {
			 =  << 8
			if  < len() {
				 |= uint32([])
			}
		}
		 = 32 - hi0bits()
	} else {
		 = 1
	}
	 = ( + ) & 0x1f
	if  != 0 {
		 = 32 - 
	}
	/* i is the number of leading zero bits in the most significant word of S*2^s2. */
	if  > 4 {
		 -= 4
		 += 
		 += 
		 += 
	} else if  < 4 {
		 += 28
		 += 
		 += 
		 += 
	}
	/* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
	if  > 0 {
		 = .Lsh(, uint())
	}
	if  > 0 {
		.Lsh(, uint())
	}
	/* Now we have d/10^k = b/S and
	   (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
	if  {
		if .Cmp() < 0 {
			--
			.Mul(, big10) /* we botched the k estimate */
			if  {
				.Mul(, big10)
			}
			 = 
		}
	}
	/* At this point 1 <= d/10^k = b/S < 10. */

	if  <= 0 &&  > 2 {
		/* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
		   Output either zero or the minimum nonzero output depending on which is closer to d. */
		if  >= 0 {
			 = .Cmp(.Mul(, big5))
		}
		if  < 0 ||  < 0 ||  == 0 && ! {
			/* Always emit at least one digit.  If the number appears to be zero
			   using the current mode, then emit one '0' digit and set decpt to 1. */
			 = [:]
			 = append(, '0')
			return , 1
		}
		 = append(, '1')
		++
		return ,  + 1
	}

	var  byte
	if  {
		if  > 0 {
			.Lsh(, uint())
		}

		/* Compute mlo -- check for special case
		 * that d is a normalized power of 2.
		 */

		 = 
		if  {
			 = 
			 = new(big.Int).Lsh(, log2P)
		}
		/* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
		/* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */
		var ,  big.Int
		for  = 1; ; ++ {
			.DivMod(, , )
			 = byte(.Int64() + '0')
			/* Do we yet have the shortest decimal string
			 * that will round to d?
			 */
			 = .Cmp()
			/* j is b/S compared with mlo/S. */
			.Sub(, )
			var  int
			if .Sign() <= 0 {
				 = 1
			} else {
				 = .Cmp(&)
			}
			/* j1 is b/S compared with 1 - mhi/S. */
			if ( == 0) && ( == 0) && ((_word1() & 1) == 0) {
				if  == '9' {
					var  bool
					 = append(, '9')
					if ,  = roundOff(, );  {
						++
						 = append(, '1')
					}
					return ,  + 1
				}
				if  > 0 {
					++
				}
				 = append(, )
				return ,  + 1
			}
			if ( < 0) || (( == 0) && ( == 0) && ((_word1() & 1) == 0)) {
				if  > 0 {
					/* Either dig or dig+1 would work here as the least significant decimal digit.
					   Use whichever would produce a decimal value closer to d. */
					.Lsh(, 1)
					 = .Cmp()
					if ( > 0) || ( == 0 && ((( & 1) == 1) || )) {
						++
						if  == '9' {
							 = append(, '9')
							,  := roundOff(, )
							if  {
								++
								 = append(, '1')
							}
							return ,  + 1
						}
					}
				}
				 = append(, )
				return ,  + 1
			}
			if  > 0 {
				if  == '9' { /* possible if i == 1 */
					 = append(, '9')
					,  := roundOff(, )
					if  {
						++
						 = append(, '1')
					}
					return ,  + 1
				}
				 = append(, +1)
				return ,  + 1
			}
			 = append(, )
			if  ==  {
				break
			}
			.Mul(, big10)
			if  ==  {
				.Mul(, big10)
			} else {
				.Mul(, big10)
				.Mul(, big10)
			}
		}
	} else {
		var  big.Int
		for  = 1; ; ++ {
			.DivMod(, , )
			 = byte(.Int64() + '0')
			 = append(, )
			if  >=  {
				break
			}

			.Mul(, big10)
		}
	}
	/* Round off last digit */

	.Lsh(, 1)
	 = .Cmp()
	if ( > 0) || ( == 0 && ((( & 1) == 1) || )) {
		var  bool
		,  = roundOff(, )
		if  {
			++
			 = append(, '1')
			return ,  + 1
		}
	} else {
		 = stripTrailingZeroes(, )
	}

	return ,  + 1
}

func bumpUp( []byte,  int) ([]byte, int) {
	var  byte
	 := 0
	if len() > 0 && [0] == '-' {
		 = 1
	}
	for {
		 = [len()-1]
		 = [:len()-1]
		if  != '9' {
			break
		}
		if len() ==  {
			++
			 = '0'
			break
		}
	}
	 = append(, +1)
	return , 
}

func setWord0( float64,  uint32) float64 {
	 := math.Float64bits()
	return math.Float64frombits(uint64()<<32 | &0xffffffff)
}

func _word0( float64) uint32 {
	 := math.Float64bits()
	return uint32( >> 32)
}

func _word1( float64) uint32 {
	 := math.Float64bits()
	return uint32()
}

func stripTrailingZeroes( []byte,  int) []byte {
	 := len() - 1
	for  >=  && [] == '0' {
		--
	}
	return [:+1]
}

/* Set b = b * 5^k.  k must be nonnegative. */
func pow5mult( *big.Int,  int) *big.Int {
	if  < (1 << (len(pow5Cache) + 2)) {
		 :=  & 3
		if  != 0 {
			.Mul(, p05[-1])
		}
		 >>= 2
		 = 0
		for {
			if &1 != 0 {
				.Mul(, pow5Cache[])
			}
			 >>= 1
			if  == 0 {
				break
			}
			++
		}
		return 
	}
	return .Mul(, new(big.Int).Exp(big5, big.NewInt(int64()), nil))
}

func roundOff( []byte,  int) ([]byte, bool) {
	 := len()
	for  !=  {
		--
		if [] != '9' {
			[]++
			return [:+1], false
		}
	}
	return [:], true
}

func init() {
	 := big.NewInt(625)
	pow5Cache[0] = 
	for  := 1;  < len(pow5Cache); ++ {
		 = new(big.Int).Mul(, )
		pow5Cache[] = 
	}
}