gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

int.go (5897B)


      1 // Copyright (c) 2018 The mathutil Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package mathutil // import "modernc.org/mathutil"
      6 
      7 import (
      8 	"fmt"
      9 	"math"
     10 	"math/big"
     11 )
     12 
     13 var (
     14 	// MaxInt128 represents the maximun Int128 value as big.Int
     15 	MaxInt128 *big.Int
     16 	// MinInt128 represents the minimun Int128 value as big.Int
     17 	MinInt128 *big.Int
     18 	// MaxUint128 represents the maximun Uint128 value as big.Int
     19 	MaxUint128 *big.Int
     20 )
     21 
     22 func init() {
     23 	var ok bool
     24 	MaxInt128, ok = big.NewInt(0).SetString("0x7fffffff_ffffffff_ffffffff_ffffffff", 0)
     25 	if !ok {
     26 		panic("internal error")
     27 	}
     28 
     29 	MinInt128 = big.NewInt(0).Set(MaxInt128)
     30 	MinInt128.Add(MinInt128, _1)
     31 	MinInt128.Neg(MinInt128)
     32 
     33 	MaxUint128, ok = big.NewInt(0).SetString("0xffffffff_ffffffff_ffffffff_ffffffff", 0)
     34 	if !ok {
     35 		panic("internal error")
     36 	}
     37 }
     38 
     39 const (
     40 	maxInt128  = 1<<127 - 1
     41 	maxUint128 = 1<<128 - 1
     42 	minInt128  = -maxInt128 - 1
     43 )
     44 
     45 // Int128 is an 128 bit signed integer.
     46 type Int128 struct {
     47 	Lo int64 // Bits 63..0.
     48 	Hi int64 // Bits 127..64.
     49 }
     50 
     51 // Add returns the sum of x and y and a carry indication.
     52 func (x Int128) Add(y Int128) (r Int128, cy bool) {
     53 	r.Lo = x.Lo + y.Lo
     54 	r.Hi = x.Hi + y.Hi
     55 	if uint64(r.Lo) < uint64(x.Lo) {
     56 		r.Hi++
     57 	}
     58 	return r, (r.Cmp(x) < 0) == (y.Sign() >= 0)
     59 }
     60 
     61 // BigInt returns x in the form of a big.Int.
     62 func (x Int128) BigInt() *big.Int {
     63 	r := big.NewInt(x.Hi)
     64 	r.Lsh(r, 64)
     65 	lo := big.NewInt(0)
     66 	lo.SetUint64(uint64(x.Lo))
     67 	return r.Add(r, lo)
     68 }
     69 
     70 // Cmp compares x and y and returns:
     71 //
     72 //	-1 if x <  y
     73 //	 0 if x == y
     74 //	+1 if x >  y
     75 func (x Int128) Cmp(y Int128) int {
     76 	if x.Hi > y.Hi {
     77 		return 1
     78 	}
     79 
     80 	if x.Hi < y.Hi {
     81 		return -1
     82 	}
     83 
     84 	if uint64(x.Lo) > uint64(y.Lo) {
     85 		return 1
     86 	}
     87 
     88 	if uint64(x.Lo) < uint64(y.Lo) {
     89 		return -1
     90 	}
     91 
     92 	return 0
     93 }
     94 
     95 // Neg returns -x and an indication that x was not equal to MinInt128.
     96 func (x Int128) Neg() (r Int128, ok bool) {
     97 	if x == (Int128{Hi: math.MinInt64}) {
     98 		return x, false
     99 	}
    100 
    101 	x.Lo = ^x.Lo
    102 	x.Hi = ^x.Hi
    103 	r, _ = x.Add(Int128{Lo: 1})
    104 	return r, true
    105 }
    106 
    107 // SetBigInt sets x to y, returns x and an error, if any.
    108 func (x *Int128) SetBigInt(y *big.Int) (r Int128, err error) {
    109 	if y.Cmp(MaxInt128) > 0 {
    110 		return *x, fmt.Errorf("%T.SetInt: overflow", x)
    111 	}
    112 	if y.Cmp(MinInt128) < 0 {
    113 		return *x, fmt.Errorf("%T.SetInt: underflow", x)
    114 	}
    115 	neg := y.Sign() < 0
    116 	var z big.Int
    117 	z.Set(y)
    118 	if neg {
    119 		z.Neg(&z)
    120 	}
    121 	r.Lo = z.Int64()
    122 	z.Rsh(&z, 64)
    123 	r.Hi = z.Int64()
    124 	if neg {
    125 		r, _ = r.Neg()
    126 	}
    127 	*x = r
    128 	return r, nil
    129 }
    130 
    131 // SetInt64 sets x to y and returns x.
    132 func (x *Int128) SetInt64(y int64) (r Int128) {
    133 	r.Lo = y
    134 	if y >= 0 {
    135 		r.Hi = 0
    136 		*x = r
    137 		return r
    138 	}
    139 
    140 	r.Hi = -1
    141 	*x = r
    142 	return r
    143 }
    144 
    145 // SetUint64 sets x to y and returns x.
    146 func (x *Int128) SetUint64(y uint64) (r Int128) {
    147 	r = Int128{Lo: int64(y)}
    148 	*x = r
    149 	return r
    150 }
    151 
    152 // Sign returns:
    153 //
    154 //	-1 if x <  0
    155 //	 0 if x == 0
    156 //	+1 if x >  0
    157 func (x Int128) Sign() int {
    158 	if x.Hi < 0 {
    159 		return -1
    160 	}
    161 
    162 	if x.Hi != 0 || x.Lo != 0 {
    163 		return 1
    164 	}
    165 
    166 	return 0
    167 }
    168 
    169 // String implements fmt.Stringer()
    170 func (x Int128) String() string { return x.BigInt().String() }
    171 
    172 // NewInt128FromInt64 return a new Int128 value initialized to n.
    173 func NewInt128FromInt64(n int64) (r Int128) {
    174 	r.Lo = n
    175 	if n < 0 {
    176 		r.Hi = -1
    177 	}
    178 	return r
    179 }
    180 
    181 // NewInt128FromUint64 return a new Int128 value initialized to n.
    182 func NewInt128FromUint64(n uint64) (r Int128) { return Int128{Lo: int64(n)} }
    183 
    184 // NewInt128FromFloat32 returns a new Int128 value initialized to n. Result is
    185 // not specified in n does not represent a number within the range of Int128
    186 // values.
    187 func NewInt128FromFloat32(n float32) (r Int128) {
    188 	if n >= minInt128 && n <= maxInt128 {
    189 		if n >= math.MinInt64 && n <= math.MaxInt64 {
    190 			return NewInt128FromInt64(int64(n))
    191 		}
    192 
    193 		f := big.NewFloat(float64(n))
    194 		bi, _ := f.Int(nil)
    195 		r.SetBigInt(bi)
    196 	}
    197 	return r
    198 }
    199 
    200 // NewInt128FromFloat64 returns a new Int128 value initialized to n. Result is
    201 // not specified in n does not represent a number within the range of Int128
    202 // values.
    203 func NewInt128FromFloat64(n float64) (r Int128) {
    204 	if n >= minInt128 && n <= maxInt128 {
    205 		if n >= math.MinInt64 && n <= math.MaxInt64 {
    206 			return NewInt128FromInt64(int64(n))
    207 		}
    208 
    209 		f := big.NewFloat(n)
    210 		bi, _ := f.Int(nil)
    211 		r.SetBigInt(bi)
    212 	}
    213 	return r
    214 }
    215 
    216 // Uint128 is an 128 bit unsigned integer.
    217 type Uint128 struct {
    218 	Lo uint64 // Bits 63..0.
    219 	Hi uint64 // Bits 127..64.
    220 }
    221 
    222 // NewUint128FromInt64 return a new Uint128 value initialized to n.
    223 func NewUint128FromInt64(n int64) (r Uint128) {
    224 	r.Lo = uint64(n)
    225 	if n < 0 {
    226 		r.Hi = ^uint64(0)
    227 	}
    228 	return r
    229 }
    230 
    231 // NewUint128FromUint64 return a new Uint128 value initialized to n.
    232 func NewUint128FromUint64(n uint64) (r Uint128) { return Uint128{Lo: n} }
    233 
    234 // NewUint128FromFloat32 returns a new Uint128 value initialized to n. Result is
    235 // not specified in n does not represent a number within the range of Uint128
    236 // values.
    237 func NewUint128FromFloat32(n float32) (r Uint128) {
    238 	if n >= 0 {
    239 		if n <= math.MaxUint64 {
    240 			return NewUint128FromUint64(uint64(n))
    241 		}
    242 
    243 		f := big.NewFloat(float64(n))
    244 		bi, _ := f.Int(nil)
    245 		r.SetBigInt(bi)
    246 	}
    247 	return r
    248 }
    249 
    250 // NewUint128FromFloat64 returns a new Uint128 value initialized to n. Result is
    251 // not specified in n does not represent a number within the range of Uint128
    252 // values.
    253 func NewUint128FromFloat64(n float64) (r Uint128) {
    254 	if n >= 0 && n <= maxUint128 {
    255 		if n <= math.MaxUint64 {
    256 			return NewUint128FromUint64(uint64(n))
    257 		}
    258 
    259 		f := big.NewFloat(n)
    260 		bi, _ := f.Int(nil)
    261 		r.SetBigInt(bi)
    262 	}
    263 	return r
    264 }
    265 
    266 // SetBigInt sets x to y, returns x and an error, if any.
    267 func (x *Uint128) SetBigInt(y *big.Int) (r Uint128, err error) {
    268 	if y.Sign() < 0 || y.Cmp(MaxUint128) > 0 {
    269 		return *x, fmt.Errorf("%T.SetInt: overflow", x)
    270 	}
    271 
    272 	var z big.Int
    273 	z.Set(y)
    274 	r.Lo = z.Uint64()
    275 	z.Rsh(&z, 64)
    276 	r.Hi = z.Uint64()
    277 	*x = r
    278 	return r, nil
    279 }