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

// Floating point binary↔decimal conversion by fast unrounded scaling.
// See “Floating-Point Printing and Parsing Can Be Simple And Fast”,
// https://research.swtch.com/fp

package strconv

import (
	
	
)

// bool2 converts b to an integer: 1 for true, 0 for false.
func [ ~int | ~uint32 | ~uint64]( bool)  {
	if  {
		return 1
	}
	return 0
}

// pack64 takes m, e and returns f = m * 2**e.
// It assumes the caller has provided a 53-bit mantissa m
// and an exponent that is in range for the mantissa.
func ( uint64,  int) (float64, error) {
	if &(1<<52) == 0 {
		return float64frombits(), nil
	}
	if  >= 0x7FF-1075 {
		return float64frombits(&(1<<63) | 0x7ff<<52), ErrRange
	}
	return float64frombits(&^(1<<52) | uint64(1075+)<<52), nil
}

// pack32 takes m, e and returns f = m * 2**e.
// It assumes the caller has provided a 24-bit mantissa m
// and an exponent that is in range for the mantissa.
func ( uint32,  int) (float32, error) {
	if &(1<<23) == 0 {
		return float32frombits(), nil
	}
	if  >= 0xFF-150 {
		return float32frombits(&(1<<31) | 0xff<<23), ErrRange
	}
	return float32frombits(&^(1<<23) | uint32(150+)<<23), nil
}

// An unrounded represents an unrounded value.
type unrounded uint64

func ( unrounded) () uint64         { return uint64(( + 0) >> 2) }
func ( unrounded) () uint64 { return uint64(( + 1) >> 2) }
func ( unrounded) () uint64         { return uint64(( + 1 + (>>2)&1) >> 2) }
func ( unrounded) () uint64   { return uint64(( + 2) >> 2) }
func ( unrounded) () uint64          { return uint64(( + 3) >> 2) }
func ( unrounded) ( int) unrounded { return  + unrounded() }

func ( unrounded) ( uint64) unrounded {
	 := uint64()
	return unrounded(/) | &1 | bool2[unrounded](% != 0)
}

func ( unrounded) ( int) unrounded {
	return >> | &1 | bool2[unrounded](&((1<<)-1) != 0)
}

// log10Pow2(x) returns ⌊log₁₀ 2**x⌋ = ⌊x * log₁₀ 2⌋.
func ( int) int {
	// log₁₀ 2 ≈ 0.30102999566 ≈ 78913 / 2^18
	return ( * 78913) >> 18
}

// log2Pow10(x) returns ⌊log₂ 10**x⌋ = ⌊x * log₂ 10⌋.
func ( int) int {
	// log₂ 10 ≈ 3.32192809489 ≈ 108853 / 2^15
	return ( * 108853) >> 15
}

// uint64pow10[x] is 10**x.
var uint64pow10 = [...]uint64{
	1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
}

// fixedWidthFloat returns the n-digit decimal form of f = m * 2**e as d * 10**p.
// n can be at most 18.
// If fmt == 'f' then n is a conservative estimate of the number of digits,
// and digits are discarded to match prec.
func ( uint64, , ,  int,  byte) ( uint64,  int) {
	 =  - 1 - log10Pow2(+63)
	var  scaler
	prescale(&, , , log2Pow10())
	 := uscale(, &)
	if  >= unmin(uint64pow10[]) {
		 = .div(10)
		--
	}
	if  == 'f' {
		for  >  {
			 = .div(10)
			--
		}
	}
	return .round(), -
}

// parseFloat64 rounds d * 10**p to the nearest float64 f.
// d can have at most 19 digits.
// It returns ErrRange if the result rounds to infinity.
func ( uint64,  int,  uint64) (float64, error) {
	 := bits.Len64()
	 := log2Pow10()
	 := min(1074, 53--)
	var  scaler
	prescale(&, -(64-), , )
	if .s >= 64 {
		return float64frombits( | 0), nil
	}
	 := uscale(<<(64-), &)

	// This block is branch-free code for:
	//	if u.round() >= 1<<53 {
	//		u = u.rsh(1)
	//		e = e - 1
	//	}
	 := bool2[int]( >= unmin(1<<53))
	 = >> | &1
	 =  - 

	return pack64(|.round(), -)
}

// parseFloat32 rounds d * 10**p to the nearest float32 f.
// d can have at most 19 digits.
// It returns ErrRange if the result rounds to infinity.
func ( uint64,  int,  uint32) (float32, error) {
	 := bits.Len64()
	 := log2Pow10()
	 := min(149, 24--)
	var  scaler
	prescale(&, -(64-), , )
	if .s >= 64 {
		return float32frombits( | 0), nil
	}
	 := uscale(<<(64-), &)

	// This block is branch-free code for:
	//	if u.round() >= 1<<24 {
	//		u = u.rsh(1)
	//		e = e - 1
	//	}
	 := bool2[int]( >= unmin(1<<24))
	 = >> | &1
	 =  - 

	return pack32(|uint32(.round()), -)
}

// unmin returns the minimum unrounded that rounds to x.
func ( uint64) unrounded {
	return unrounded(<<2 - 2)
}

// shortFloat computes the shortest formatting of f,
// using as few digits as possible that will still round trip
// back to the original float.
func [ float32 | float64]( uint64,  int) ( uint64,  int) {
	var ,  int // parameterized constants
	switch 8 * unsafe.Sizeof((0)) {
	case 32:
		 = float32MantBits
		 = float32MinExp
	case 64:
		 = float64MantBits
		 = float64MinExp
	}

	// Note: these cases could be factored a little more,
	// but in the first two branches, z is a constant,
	// allowing the compiler to greatly simplify the code.
	var ,  uint64
	var  int
	 := 63 - 
	if  == 1<<63 &&  >  {
		 = -skewed( + )
		 =  - 1<<(-2) // min = m - 1/4 * 2**(e+z)
		 =  + 1<<(-1) // max = m + 1/2 * 2**(e+z)
		 = int(>>) & 1
	} else if  >=  {
		 = -log10Pow2( + )
		 =  - 1<<(-1) // min = m - 1/2 * 2**(e+z)
		 =  + 1<<(-1) // max = m + 1/2 * 2**(e+z)
		 = int(>>) & 1
	} else {
		 =  + ( - )
		 = -log10Pow2( + )
		 =  - 1<<(-1) // min = m - 1/2 * 2**(e+z)
		 =  + 1<<(-1) // max = m + 1/2 * 2**(e+z)
		 = int(>>) & 1
	}

	var  scaler
	prescale(&, , , log2Pow10())
	 := uscale(, &).nudge(+).ceil()
	 := uscale(, &).nudge(-).floor()

	if  =  / 10; *10 >=  {
		return , -( - 1)
	}
	if  = ;  <  {
		 = uscale(, &).round()
	}
	return , -
}

// skewed computes the skewed footprint of m * 2**e,
// which is ⌊log₁₀ 3/4 * 2**e⌋ = ⌊e*(log₁₀ 2)-(log₁₀ 4/3)⌋.
func ( int) int {
	return (*631305 - 261663) >> 21
}

// A pmHiLo represents hi<<64 - lo.
type pmHiLo struct {
	hi uint64
	lo uint64
}

// A scaler holds derived scaling constants for a given e, p pair.
type scaler struct {
	// Note: using pm pmHiLo here nudges uscale just over the inlining boundary. Don't.
	pmHi uint64
	pmLo uint64
	s    int
}

// prescale returns the scaling constants for e, p.
// lp must be log2Pow10(p).
// The caller is responsible for either avoiding e, p pairs
// that cause pre.s < 0 or pre.s >= 64, or else handling
// those cases before passing the result to uscale.
// In practice, pre.s < 0 would indicate a buggy caller
// and pre.s >= 64 can only happen for parsing and is
// picked off at those call sites.
func ( *scaler, , ,  int) {
	.pmHi = pow10Tab[-pow10Min].hi
	.pmLo = pow10Tab[-pow10Min].lo
	.s = -( +  + 3)
}

// uscale returns unround(x * 2**e * 10**p).
// The caller should pass &pre for prescale(&pre, e, p, log2Pow10(p))
// and should have left-justified x so its high bit is set.
// The caller is also responsible for checking that c.s < 64.
// For formatting, that's always true.
// For parsing, the caller needs to pick it off early and return a signed 0.
func ( uint64,  *scaler) unrounded {
	,  := bits.Mul64(, .pmHi)
	 := .s & 63 // make shifts cheaper
	if >><< !=  {
		return unrounded(>> | 1)
	}
	,  := bits.Mul64(, .pmLo)
	 -= bool2[uint64]( < )
	return unrounded(>> | bool2[uint64](- > 1))
}

// setDigits sets digs to the nd digits described by d, p.
func ( []byte,  uint64, ,  int) (,  int) {
	// Note: nd <= len(s) is guaranteed by caller,
	// but writing it explicitly here lets the compiler know,
	// so that it can remove the bounds check in the loop.
	// (The slice s[:nd] not panicking only establishes nd <= cap(s).)
	if  <= len() {
		formatBase10([:], )
		 =  + 
		for  > 0 && [-1] == '0' {
			--
		}
	}
	return , 
}

// numDigits returns the number of decimal digits in d.
// It requires d ≥ 1.
func ( uint64) int {
	 := log10Pow2(bits.Len64())
	return  + bool2[int]( >= uint64pow10[])
}