github.com/afumu/libc@v0.0.6/int128.go (about)

     1  // Copyright 2020 The Libc 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  // Some code is copied and adjusted from
     6  // https://github.com/lukechampine/uint128, the original LICENSE file
     7  // reproduced below in full as of 2021-01-19:
     8  
     9  /*
    10  The MIT License (MIT)
    11  
    12  Copyright (c) 2019 Luke Champine
    13  
    14  Permission is hereby granted, free of charge, to any person obtaining a copy
    15  of this software and associated documentation files (the "Software"), to deal
    16  in the Software without restriction, including without limitation the rights
    17  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    18  copies of the Software, and to permit persons to whom the Software is
    19  furnished to do so, subject to the following conditions:
    20  
    21  The above copyright notice and this permission notice shall be included in
    22  all copies or substantial portions of the Software.
    23  
    24  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    25  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    26  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    27  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    28  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    29  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    30  THE SOFTWARE.
    31  */
    32  
    33  package libc // import "github.com/afumu/libc"
    34  
    35  import (
    36  	mbits "math/bits"
    37  
    38  	"modernc.org/mathutil"
    39  )
    40  
    41  type Int128 mathutil.Int128
    42  
    43  var (
    44  	int128Minus1 = Int128{-1, -1}
    45  	int128Plus1  = Int128{Lo: 1}
    46  )
    47  
    48  func Int128FromFloat32(n float32) Int128 { return Int128(mathutil.NewInt128FromFloat32(n)) }
    49  func Int128FromFloat64(n float64) Int128 { return Int128(mathutil.NewInt128FromFloat64(n)) }
    50  func Int128FromInt16(n int16) Int128     { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    51  func Int128FromInt32(n int32) Int128     { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    52  func Int128FromInt64(n int64) Int128     { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    53  func Int128FromInt8(n int8) Int128       { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    54  func Int128FromUint16(n uint16) Int128   { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    55  func Int128FromUint32(n uint32) Int128   { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    56  func Int128FromUint64(n uint64) Int128   { return Int128(mathutil.NewInt128FromUint64(n)) }
    57  func Int128FromUint8(n uint8) Int128     { return Int128(mathutil.NewInt128FromInt64(int64(n))) }
    58  func Int128FromUint128(n Uint128) Int128 { return Int128{Lo: int64(n.Lo), Hi: int64(n.Hi)} }
    59  
    60  func (n *Int128) LValueDec()          { *n = n.Add(int128Minus1) }
    61  func (n *Int128) LValueInc()          { *n = n.Add(int128Plus1) }
    62  func (n *Int128) LValueShl(c int32)   { *n = n.Shl(c) }
    63  func (n *Int128) LValueShr(c int32)   { *n = n.Shr(c) }
    64  func (n Int128) And(v Int128) Int128  { return Int128{n.Lo & v.Lo, n.Hi & v.Hi} }
    65  func (n Int128) Cmp(y Int128) int     { return mathutil.Int128(n).Cmp(mathutil.Int128(y)) }
    66  func (n Int128) Int16() int16         { return int16(n.Lo) }
    67  func (n Int128) Int32() int32         { return int32(n.Lo) }
    68  func (n Int128) Int64() int64         { return int64(n.Lo) }
    69  func (n Int128) Int8() int8           { return int8(n.Lo) }
    70  func (n Int128) Or(v Int128) Int128   { return Int128{n.Lo | v.Lo, n.Hi | v.Hi} }
    71  func (n Int128) Uint128() (r Uint128) { return Uint128{uint64(n.Lo), uint64(n.Hi)} }
    72  func (n Int128) Uint16() uint16       { return uint16(n.Lo) }
    73  func (n Int128) Uint32() uint32       { return uint32(n.Lo) }
    74  func (n Int128) Uint64() uint64       { return uint64(n.Lo) }
    75  func (n Int128) Uint8() uint8         { return uint8(n.Lo) }
    76  func (n Int128) Xor(v Int128) Int128  { return Int128{n.Lo ^ v.Lo, n.Hi ^ v.Hi} }
    77  
    78  func (n Int128) Neg() Int128 {
    79  	n.Lo ^= -1
    80  	n.Hi ^= -1
    81  	return n.Add(int128Plus1)
    82  }
    83  
    84  func (n Int128) Float32() float32 {
    85  	switch n.Hi {
    86  	case 0:
    87  		return float32(uint64(n.Lo))
    88  	case -1:
    89  		return -float32(uint64(n.Lo))
    90  	}
    91  
    92  	if n.Hi < 0 {
    93  		n = n.Neg()
    94  		return -float32(n.Hi)*(1<<64) + float32(uint64(n.Lo))
    95  	}
    96  
    97  	return -float32(n.Hi)*(1<<64) + float32(uint64(n.Lo))
    98  }
    99  
   100  func (n Int128) Float64() float64 {
   101  	switch n.Hi {
   102  	case 0:
   103  		return float64(uint64(n.Lo))
   104  	case -1:
   105  		return -float64(uint64(n.Lo))
   106  	}
   107  
   108  	if n.Hi < 0 {
   109  		n = n.Neg()
   110  		return -float64(n.Hi)*(1<<64) + float64(uint64(n.Lo))
   111  	}
   112  
   113  	return float64(n.Hi)*(1<<64) + float64(uint64(n.Lo))
   114  }
   115  
   116  func (n Int128) Add(m Int128) (r Int128) {
   117  	r.Lo = n.Lo + m.Lo
   118  	r.Hi = n.Hi + m.Hi
   119  	if uint64(r.Lo) < uint64(n.Lo) {
   120  		r.Hi++
   121  	}
   122  	return r
   123  }
   124  
   125  func (n Int128) Mul(m Int128) Int128 {
   126  	hi, lo := mbits.Mul64(uint64(n.Lo), uint64(m.Lo))
   127  	_, p1 := mbits.Mul64(uint64(n.Hi), uint64(m.Lo))
   128  	_, p3 := mbits.Mul64(uint64(n.Lo), uint64(m.Hi))
   129  	hi, _ = mbits.Add64(hi, p1, 0)
   130  	hi, _ = mbits.Add64(hi, p3, 0)
   131  	return Int128{int64(lo), int64(hi)}
   132  }
   133  
   134  func (n Int128) Shl(c int32) (r Int128) {
   135  	if c > 64 {
   136  		r.Lo = 0
   137  		r.Hi = n.Lo << (c - 64)
   138  	} else {
   139  		r.Lo = n.Lo << c
   140  		r.Hi = n.Hi<<c | n.Lo>>(64-c)
   141  	}
   142  	return r
   143  }
   144  
   145  func (n Int128) Shr(c int32) (r Int128) {
   146  	if c > 64 {
   147  		r.Lo = n.Hi >> (c - 64)
   148  		switch {
   149  		case n.Hi < 0:
   150  			r.Hi = -1
   151  		default:
   152  			r.Hi = 0
   153  		}
   154  	} else {
   155  		r.Lo = n.Lo>>c | n.Hi<<(64-c)
   156  		r.Hi = n.Hi >> c
   157  	}
   158  	return r
   159  }
   160  
   161  type Uint128 mathutil.Uint128
   162  
   163  func Uint128FromFloat32(n float32) Uint128 { return Uint128(mathutil.NewUint128FromFloat32(n)) }
   164  func Uint128FromFloat64(n float64) Uint128 { return Uint128(mathutil.NewUint128FromFloat64(n)) }
   165  func Uint128FromInt128(n Int128) Uint128   { return Uint128{Lo: uint64(n.Lo), Hi: uint64(n.Hi)} }
   166  func Uint128FromInt16(n int16) Uint128     { return Uint128FromInt64(int64(n)) }
   167  func Uint128FromInt32(n int32) Uint128     { return Uint128FromInt64(int64(n)) }
   168  func Uint128FromInt8(n int8) Uint128       { return Uint128FromInt64(int64(n)) }
   169  func Uint128FromUint16(n uint16) Uint128   { return Uint128{Lo: uint64(n)} }
   170  func Uint128FromUint32(n uint32) Uint128   { return Uint128{Lo: uint64(n)} }
   171  func Uint128FromUint64(n uint64) Uint128   { return Uint128{Lo: n} }
   172  func Uint128FromUint8(n uint8) Uint128     { return Uint128{Lo: uint64(n)} }
   173  
   174  func Uint128FromInt64(n int64) (r Uint128) {
   175  	r.Lo = uint64(n)
   176  	if n < 0 {
   177  		r.Hi = ^uint64(0)
   178  	}
   179  	return r
   180  }
   181  
   182  func (n *Uint128) LValueShl(c int32)    { *n = n.Shl(c) }
   183  func (n *Uint128) LValueShr(c int32)    { *n = n.Shr(c) }
   184  func (n Uint128) And(m Uint128) Uint128 { return Uint128{n.Lo & m.Lo, n.Hi & m.Hi} }
   185  func (n Uint128) Int128() Int128        { return Int128{int64(n.Lo), int64(n.Hi)} }
   186  func (n Uint128) Int16() int16          { return int16(n.Lo) }
   187  func (n Uint128) Int32() int32          { return int32(n.Lo) }
   188  func (n Uint128) Int64() int64          { return int64(n.Lo) }
   189  func (n Uint128) Int8() int8            { return int8(n.Lo) }
   190  func (n Uint128) Or(m Uint128) Uint128  { return Uint128{n.Lo | m.Lo, n.Hi | m.Hi} }
   191  func (n Uint128) Uint16() uint16        { return uint16(n.Lo) }
   192  func (n Uint128) Uint32() uint32        { return uint32(n.Lo) }
   193  func (n Uint128) Uint64() uint64        { return n.Lo }
   194  func (n Uint128) Uint8() uint8          { return uint8(n.Lo) }
   195  func (n Uint128) Xor(m Uint128) Uint128 { return Uint128{n.Lo ^ m.Lo, n.Hi ^ m.Hi} }
   196  
   197  func (n Uint128) Add(m Uint128) (r Uint128) {
   198  	var carry uint64
   199  	r.Lo, carry = mbits.Add64(n.Lo, m.Lo, 0)
   200  	r.Hi, _ = mbits.Add64(n.Hi, m.Hi, carry)
   201  	return r
   202  }
   203  
   204  func (n Uint128) Mul(m Uint128) Uint128 {
   205  	hi, lo := mbits.Mul64(n.Lo, m.Lo)
   206  	_, p1 := mbits.Mul64(n.Hi, m.Lo)
   207  	_, p3 := mbits.Mul64(n.Lo, m.Hi)
   208  	hi, _ = mbits.Add64(hi, p1, 0)
   209  	hi, _ = mbits.Add64(hi, p3, 0)
   210  	return Uint128{lo, hi}
   211  }
   212  
   213  func (n Uint128) Shr(c int32) (r Uint128) {
   214  	if c > 64 {
   215  		r.Lo = n.Hi >> (c - 64)
   216  		r.Hi = 0
   217  	} else {
   218  		r.Lo = n.Lo>>c | n.Hi<<(64-c)
   219  		r.Hi = n.Hi >> c
   220  	}
   221  	return r
   222  }
   223  
   224  func (n Uint128) mulOvf(m Uint128) (_ Uint128, ovf bool) {
   225  	hi, lo := mbits.Mul64(n.Lo, m.Lo)
   226  	p0, p1 := mbits.Mul64(n.Hi, m.Lo)
   227  	p2, p3 := mbits.Mul64(n.Lo, m.Hi)
   228  	hi, c0 := mbits.Add64(hi, p1, 0)
   229  	hi, c1 := mbits.Add64(hi, p3, 0)
   230  	ovf = p0 != 0 || p2 != 0 || c0 != 0 || c1 != 0
   231  	return Uint128{lo, hi}, ovf
   232  }
   233  
   234  func (n Uint128) quoRem(m Uint128) (q, r Uint128) {
   235  	if m.Hi == 0 {
   236  		var r64 uint64
   237  		q, r64 = n.quoRem64(m.Lo)
   238  		r = Uint128FromUint64(r64)
   239  	} else {
   240  		// generate a "trial quotient," guaranteed to be within 1 of the actual
   241  		// quotient, then adjust.
   242  		nz := mbits.LeadingZeros64(m.Hi)
   243  		v1 := m.Shl(int32(nz))
   244  		u1 := n.Shr(1)
   245  		tq, _ := mbits.Div64(u1.Hi, u1.Lo, v1.Hi)
   246  		tq >>= 63 - nz
   247  		if tq != 0 {
   248  			tq--
   249  		}
   250  		q = Uint128FromUint64(tq)
   251  		// calculate remainder using trial quotient, then adjust if remainder is
   252  		// greater than divisor
   253  		r = n.Sub(m.mul64(tq))
   254  		if r.Cmp(m) >= 0 {
   255  			q = q.add64(1)
   256  			r = r.Sub(m)
   257  		}
   258  	}
   259  	return
   260  }
   261  
   262  func (n Uint128) quoRem64(m uint64) (q Uint128, r uint64) {
   263  	if n.Hi < m {
   264  		q.Lo, r = mbits.Div64(n.Hi, n.Lo, m)
   265  	} else {
   266  		q.Hi, r = mbits.Div64(0, n.Hi, m)
   267  		q.Lo, r = mbits.Div64(r, n.Lo, m)
   268  	}
   269  	return
   270  }
   271  
   272  func (n Uint128) Div(m Uint128) (r Uint128) {
   273  	r, _ = n.quoRem(m)
   274  	return r
   275  }
   276  
   277  func (n Uint128) Shl(c int32) (r Uint128) {
   278  	if c > 64 {
   279  		r.Lo = 0
   280  		r.Hi = n.Lo << (c - 64)
   281  	} else {
   282  		r.Lo = n.Lo << c
   283  		r.Hi = n.Hi<<c | n.Lo>>(64-c)
   284  	}
   285  	return
   286  }
   287  
   288  func (n Uint128) Sub(m Uint128) Uint128 {
   289  	lo, borrow := mbits.Sub64(n.Lo, m.Lo, 0)
   290  	hi, _ := mbits.Sub64(n.Hi, m.Hi, borrow)
   291  	return Uint128{lo, hi}
   292  }
   293  
   294  func (n Uint128) mul64(m uint64) Uint128 {
   295  	hi, lo := mbits.Mul64(n.Lo, m)
   296  	_, p1 := mbits.Mul64(n.Hi, m)
   297  	hi, _ = mbits.Add64(hi, p1, 0)
   298  	return Uint128{lo, hi}
   299  }
   300  
   301  func (n Uint128) Cmp(m Uint128) int {
   302  	if n == m {
   303  		return 0
   304  	} else if n.Hi < m.Hi || (n.Hi == m.Hi && n.Lo < m.Lo) {
   305  		return -1
   306  	} else {
   307  		return 1
   308  	}
   309  }
   310  
   311  func (n Uint128) add64(m uint64) Uint128 {
   312  	lo, carry := mbits.Add64(n.Lo, m, 0)
   313  	hi, _ := mbits.Add64(n.Hi, 0, carry)
   314  	return Uint128{lo, hi}
   315  }
   316  
   317  func (n Uint128) Float32() float32 {
   318  	if n.Hi == 0 {
   319  		return float32(uint64(n.Lo))
   320  	}
   321  
   322  	return float32(n.Hi)*(1<<64) + float32(uint64(n.Lo))
   323  }
   324  
   325  func (n Uint128) Float64() float64 {
   326  	if n.Hi == 0 {
   327  		return float64(uint64(n.Lo))
   328  	}
   329  
   330  	return float64(n.Hi)*(1<<64) + float64(uint64(n.Lo))
   331  }