// Copyright (c) 2018 The mathutil Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package mathutil // import "modernc.org/mathutil"

import (
	
	
	
)

var (
	// MaxInt128 represents the maximun Int128 value as big.Int
	MaxInt128 *big.Int
	// MinInt128 represents the minimun Int128 value as big.Int
	MinInt128 *big.Int
	// MaxUint128 represents the maximun Uint128 value as big.Int
	MaxUint128 *big.Int
)

func () {
	var  bool
	MaxInt128,  = big.NewInt(0).SetString("0x7fffffff_ffffffff_ffffffff_ffffffff", 0)
	if ! {
		panic("internal error")
	}

	MinInt128 = big.NewInt(0).Set(MaxInt128)
	MinInt128.Add(MinInt128, _1)
	MinInt128.Neg(MinInt128)

	MaxUint128,  = big.NewInt(0).SetString("0xffffffff_ffffffff_ffffffff_ffffffff", 0)
	if ! {
		panic("internal error")
	}
}

const (
	maxInt128  = 1<<127 - 1
	maxUint128 = 1<<128 - 1
	minInt128  = -maxInt128 - 1
)

// Int128 is an 128 bit signed integer.
type Int128 struct {
	Lo int64 // Bits 63..0.
	Hi int64 // Bits 127..64.
}

// Add returns the sum of x and y and a carry indication.
func ( Int128) ( Int128) ( Int128,  bool) {
	.Lo = .Lo + .Lo
	.Hi = .Hi + .Hi
	if uint64(.Lo) < uint64(.Lo) {
		.Hi++
	}
	return , (.Cmp() < 0) == (.Sign() >= 0)
}

// BigInt returns x in the form of a big.Int.
func ( Int128) () *big.Int {
	 := big.NewInt(.Hi)
	.Lsh(, 64)
	 := big.NewInt(0)
	.SetUint64(uint64(.Lo))
	return .Add(, )
}

// Cmp compares x and y and returns:
//
//	-1 if x <  y
//	 0 if x == y
//	+1 if x >  y
func ( Int128) ( Int128) int {
	if .Hi > .Hi {
		return 1
	}

	if .Hi < .Hi {
		return -1
	}

	if uint64(.Lo) > uint64(.Lo) {
		return 1
	}

	if uint64(.Lo) < uint64(.Lo) {
		return -1
	}

	return 0
}

// Neg returns -x and an indication that x was not equal to MinInt128.
func ( Int128) () ( Int128,  bool) {
	if  == (Int128{Hi: math.MinInt64}) {
		return , false
	}

	.Lo = ^.Lo
	.Hi = ^.Hi
	, _ = .Add(Int128{Lo: 1})
	return , true
}

// SetBigInt sets x to y, returns x and an error, if any.
func ( *Int128) ( *big.Int) ( Int128,  error) {
	if .Cmp(MaxInt128) > 0 {
		return *, fmt.Errorf("%T.SetInt: overflow", )
	}
	if .Cmp(MinInt128) < 0 {
		return *, fmt.Errorf("%T.SetInt: underflow", )
	}
	 := .Sign() < 0
	var  big.Int
	.Set()
	if  {
		.Neg(&)
	}
	.Lo = .Int64()
	.Rsh(&, 64)
	.Hi = .Int64()
	if  {
		, _ = .Neg()
	}
	* = 
	return , nil
}

// SetInt64 sets x to y and returns x.
func ( *Int128) ( int64) ( Int128) {
	.Lo = 
	if  >= 0 {
		.Hi = 0
		* = 
		return 
	}

	.Hi = -1
	* = 
	return 
}

// SetUint64 sets x to y and returns x.
func ( *Int128) ( uint64) ( Int128) {
	 = Int128{Lo: int64()}
	* = 
	return 
}

// Sign returns:
//
//	-1 if x <  0
//	 0 if x == 0
//	+1 if x >  0
func ( Int128) () int {
	if .Hi < 0 {
		return -1
	}

	if .Hi != 0 || .Lo != 0 {
		return 1
	}

	return 0
}

// String implements fmt.Stringer()
func ( Int128) () string { return .BigInt().String() }

// NewInt128FromInt64 return a new Int128 value initialized to n.
func ( int64) ( Int128) {
	.Lo = 
	if  < 0 {
		.Hi = -1
	}
	return 
}

// NewInt128FromUint64 return a new Int128 value initialized to n.
func ( uint64) ( Int128) { return Int128{Lo: int64()} }

// NewInt128FromFloat32 returns a new Int128 value initialized to n. Result is
// not specified in n does not represent a number within the range of Int128
// values.
func ( float32) ( Int128) {
	if  >= minInt128 &&  <= maxInt128 {
		if  >= math.MinInt64 &&  <= math.MaxInt64 {
			return NewInt128FromInt64(int64())
		}

		 := big.NewFloat(float64())
		,  := .Int(nil)
		.SetBigInt()
	}
	return 
}

// NewInt128FromFloat64 returns a new Int128 value initialized to n. Result is
// not specified in n does not represent a number within the range of Int128
// values.
func ( float64) ( Int128) {
	if  >= minInt128 &&  <= maxInt128 {
		if  >= math.MinInt64 &&  <= math.MaxInt64 {
			return NewInt128FromInt64(int64())
		}

		 := big.NewFloat()
		,  := .Int(nil)
		.SetBigInt()
	}
	return 
}

// Uint128 is an 128 bit unsigned integer.
type Uint128 struct {
	Lo uint64 // Bits 63..0.
	Hi uint64 // Bits 127..64.
}

// NewUint128FromInt64 return a new Uint128 value initialized to n.
func ( int64) ( Uint128) {
	.Lo = uint64()
	if  < 0 {
		.Hi = ^uint64(0)
	}
	return 
}

// NewUint128FromUint64 return a new Uint128 value initialized to n.
func ( uint64) ( Uint128) { return Uint128{Lo: } }

// NewUint128FromFloat32 returns a new Uint128 value initialized to n. Result is
// not specified in n does not represent a number within the range of Uint128
// values.
func ( float32) ( Uint128) {
	if  >= 0 {
		if  <= math.MaxUint64 {
			return NewUint128FromUint64(uint64())
		}

		 := big.NewFloat(float64())
		,  := .Int(nil)
		.SetBigInt()
	}
	return 
}

// NewUint128FromFloat64 returns a new Uint128 value initialized to n. Result is
// not specified in n does not represent a number within the range of Uint128
// values.
func ( float64) ( Uint128) {
	if  >= 0 &&  <= maxUint128 {
		if  <= math.MaxUint64 {
			return NewUint128FromUint64(uint64())
		}

		 := big.NewFloat()
		,  := .Int(nil)
		.SetBigInt()
	}
	return 
}

// SetBigInt sets x to y, returns x and an error, if any.
func ( *Uint128) ( *big.Int) ( Uint128,  error) {
	if .Sign() < 0 || .Cmp(MaxUint128) > 0 {
		return *, fmt.Errorf("%T.SetInt: overflow", )
	}

	var  big.Int
	.Set()
	.Lo = .Uint64()
	.Rsh(&, 64)
	.Hi = .Uint64()
	* = 
	return , nil
}