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  }