├── README ├── LICENSE ├── uint128_test.go └── uint128.go /README: -------------------------------------------------------------------------------- 1 | This package implements some basic math (multiplication and addition) 2 | and bitwise operations for unsigned 128 bit integers in go. 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 David Minor 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /uint128_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014, David Minor. All rights reserved. 2 | // Use of this source code is governed by the MIT 3 | // license which can be found in the LICENSE file. 4 | 5 | package uint128 6 | 7 | import ( 8 | "math/big" 9 | "math/rand" 10 | "testing" 11 | "encoding/binary" 12 | ) 13 | 14 | func makeUint128(a []uint32) Uint128 { 15 | return Uint128{uint64(a[0]) << 32 | uint64(a[1]), 16 | uint64(a[2]) << 32 | uint64(a[3])} 17 | } 18 | 19 | func makeBigInt(a []uint32) *big.Int { 20 | buf := make([]byte, 16) 21 | binary.BigEndian.PutUint32(buf, a[0]) 22 | binary.BigEndian.PutUint32(buf[4:], a[1]) 23 | binary.BigEndian.PutUint32(buf[8:], a[2]) 24 | binary.BigEndian.PutUint32(buf[12:], a[3]) 25 | return (&big.Int{}).SetBytes(buf) 26 | } 27 | 28 | func bigIntToUint128(a big.Int) Uint128 { 29 | bytes := a.Bytes() 30 | resbytes := make([]byte, 16) 31 | i := len(bytes) - 1; 32 | if i > 15 { 33 | i = 15; 34 | } 35 | for i := len(bytes) - 1; i >= 0; i-- { 36 | resbytes[i] = bytes[i] 37 | } 38 | result := Uint128{} 39 | result.H = binary.BigEndian.Uint64(bytes) 40 | result.L = binary.BigEndian.Uint64(bytes[8:]) 41 | return result 42 | } 43 | 44 | func uint128ToBigInt(a Uint128) *big.Int { 45 | buf := make([]byte, 16) 46 | binary.BigEndian.PutUint64(buf, a.H) 47 | binary.BigEndian.PutUint64(buf[8:], a.L) 48 | return (&big.Int{}).SetBytes(buf) 49 | } 50 | 51 | func TestMult(t *testing.T) { 52 | rand.Seed(0) 53 | mod := big.NewInt(1) 54 | mod.Lsh(mod, 128) 55 | resbig, multbig := &big.Int{}, &big.Int{} 56 | for i := 0; i < 100000; i++ { 57 | a := []uint32{rand.Uint32(),rand.Uint32(),rand.Uint32(),rand.Uint32()} 58 | b := []uint32{rand.Uint32(),rand.Uint32(),rand.Uint32(),rand.Uint32()} 59 | au := makeUint128(a) 60 | bu := makeUint128(b) 61 | abig := makeBigInt(a) 62 | bbig := makeBigInt(b) 63 | resu := au.Mult(bu) 64 | resbig.Mod(multbig.Mul(abig, bbig), mod) 65 | //compare abig, resu 66 | resubig := uint128ToBigInt(resu) 67 | if resbig.Cmp(resubig) != 0 { 68 | t.Errorf("Multiplied %x by %x (%x %x x %x %x), expected %x got %x (%x %x)", 69 | abig, bbig, au.H, au.L, bu.H, bu.L, resbig, resubig, resu.H, resu.L) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /uint128.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014, David Minor. All rights reserved. 2 | // Use of this source code is governed by the MIT 3 | // license which can be found in the LICENSE file. 4 | 5 | package uint128 6 | 7 | type Uint128 struct { 8 | H, L uint64 9 | } 10 | 11 | func (i Uint128) ShiftLeft(bits uint) Uint128 { 12 | if bits >= 128 { 13 | i.H = 0 14 | i.L = 0 15 | } else if bits >= 64 { 16 | i.H = i.L << (bits - 64) 17 | i.L = 0 18 | } else { 19 | i.H <<= bits 20 | i.H |= i.L >> (64 - bits) 21 | i.L <<= bits 22 | } 23 | return i 24 | } 25 | 26 | func (i Uint128) ShiftRight(bits uint) Uint128 { 27 | if bits >= 128 { 28 | i.H = 0 29 | i.L = 0 30 | } else if bits >= 64 { 31 | i.L = i.H >> (bits - 64) 32 | i.H = 0 33 | } else { 34 | i.L >>= bits 35 | i.L |= i.H << (64 - bits) 36 | i.H >>= bits 37 | } 38 | return i 39 | } 40 | 41 | func (x Uint128) And(y Uint128) Uint128 { 42 | x.H &= y.H 43 | x.L &= y.L 44 | return x 45 | } 46 | 47 | func (x Uint128) Xor(y Uint128) Uint128 { 48 | x.H ^= y.H 49 | x.L ^= y.L 50 | return x 51 | } 52 | 53 | func (x Uint128) Or(y Uint128) Uint128 { 54 | x.H |= y.H 55 | x.L |= y.L 56 | return x 57 | } 58 | 59 | func (augend Uint128) Add(addend Uint128) Uint128 { 60 | origlow := augend.L 61 | augend.L += addend.L 62 | augend.H += addend.H 63 | if augend.L < origlow { // wrapping occurred, so carry the 1 64 | augend.H += 1 65 | } 66 | return augend 67 | } 68 | 69 | // (Adapted from go's math/big) 70 | // z1<<64 + z0 = x*y 71 | // Adapted from Warren, Hacker's Delight, p. 132. 72 | func mult(x, y uint64) (z1, z0 uint64) { 73 | z0 = x * y // lower 64 bits are easy 74 | // break the multiplication into (x1 << 32 + x0)(y1 << 32 + y0) 75 | // which is x1*y1 << 64 + (x0*y1 + x1*y0) << 32 + x0*y0 76 | // so now we can do 64 bit multiplication and addition and 77 | // shift the results into the right place 78 | x0, x1 := x & 0x00000000ffffffff, x >> 32 79 | y0, y1 := y & 0x00000000ffffffff, y >> 32 80 | w0 := x0 * y0 81 | t := x1 * y0 + w0 >> 32 82 | w1 := t & 0x00000000ffffffff 83 | w2 := t >> 32 84 | w1 += x0 * y1 85 | z1 = x1 * y1 + w2 + w1 >> 32 86 | return 87 | } 88 | 89 | func (multiplicand Uint128) Mult(multiplier Uint128) Uint128 { 90 | hl := multiplicand.H * multiplier.L + multiplicand.L * multiplier.H 91 | multiplicand.H, multiplicand.L = mult(multiplicand.L, multiplier.L) 92 | multiplicand.H += hl 93 | return multiplicand 94 | } 95 | 96 | --------------------------------------------------------------------------------