github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/args/grey_code.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package args 7 8 import "math/bits" 9 10 // Converts a linear binary number to a binary-reflected grey code 11 func Grey(v uint) uint { 12 return v ^ (v >> 1) 13 } 14 15 // Converts a binary-reflected grey code to a linear binary number 16 func FromGrey(g uint) uint { 17 if bits.UintSize == 64 { 18 g ^= g >> 32 19 } 20 g ^= g >> 16 21 g ^= g >> 8 22 g ^= g >> 4 23 g ^= g >> 2 24 g ^= g >> 1 25 return g 26 } 27 28 // Gives a grey-code increment for the given binary. Result always has only one non-zero bit. 29 // The following is always true: Grey(v) ^ GreyInc(v) == Grey(v + 1) 30 func GreyInc(v uint) uint { 31 // This can also be calculated in a classical way with parity (count non-zero bits) of value, but it will be slower 32 // 33 // Classical gray_inc(x): 34 // if parity of x is even: 35 // return x ^ 1 36 // if parity of x is odd: 37 // y := rightmost 1 bit in x 38 // return x ^ (y << 1) 39 // 40 41 // The fastest way is the shorter version of Grey(v) ^ Grey(v+1) 42 return Grey(v ^ (v + 1)) 43 } 44 45 // Returns a bit (offset) that will change in grey-code equivalent of v on incrementing it 46 // The following is always true: 1<<GreyIncBit(v) == GreyInc(v) 47 func GreyIncBit(v uint) uint8 { 48 if v&1 == 0 { 49 return 0 // a faster way 50 } 51 return greyIncBitCalc(v) 52 } 53 54 func greyIncBitCalc(v uint) uint8 { 55 return uint8(bits.Len(GreyInc(v)) - 1) 56 }