popcount.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //
  2. // Package hamming distance calculations in Go
  3. //
  4. // https://github.com/steakknife/hamming
  5. //
  6. // Copyright © 2014, 2015, 2016, 2018 Barry Allard
  7. //
  8. // MIT license
  9. //
  10. package hamming
  11. import "strconv"
  12. // References: check out Hacker's Delight, about p. 70
  13. func table() [256]uint8 {
  14. return [256]uint8{
  15. 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
  16. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  17. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  18. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  19. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  20. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  21. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  22. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  23. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  24. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  25. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  26. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  27. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  28. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  29. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  30. 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
  31. }
  32. }
  33. // CountBitsByteAlt table-less, branch-free implementation
  34. func CountBitsByteAlt(x byte) int {
  35. x = (x & 0x55) + ((x >> 1) & 0x55)
  36. x = (x & 0x33) + ((x >> 2) & 0x33)
  37. return int((x & 0x0f) + ((x >> 4) & 0x0f))
  38. }
  39. // CountBitsInt8 count 1's in x
  40. func CountBitsInt8(x int8) int { return CountBitsByte(byte(x)) }
  41. // CountBitsInt16 count 1's in x
  42. func CountBitsInt16(x int16) int { return CountBitsUint16(uint16(x)) }
  43. // CountBitsInt32 count 1's in x
  44. func CountBitsInt32(x int32) int { return CountBitsUint32(uint32(x)) }
  45. // CountBitsInt64 count 1's in x
  46. func CountBitsInt64(x int64) int { return CountBitsUint64(uint64(x)) }
  47. // CountBitsInt count 1's in x
  48. func CountBitsInt(x int) int { return CountBitsUint(uint(x)) }
  49. // CountBitsByte count 1's in x
  50. func CountBitsByte(x byte) int { return CountBitsUint8(x) }
  51. // CountBitsRune count 1's in x
  52. func CountBitsRune(x rune) int { return CountBitsInt32(x) }
  53. // CountBitsUint8 count 1's in x
  54. func CountBitsUint8(x uint8) int { return int(table()[x]) }
  55. // CountBitsUint16 count 1's in x
  56. func CountBitsUint16(x uint16) int {
  57. return int(table()[x&0xFF] + table()[(x>>8)&0xFF])
  58. }
  59. const (
  60. m1d uint32 = 0x55555555
  61. m2d = 0x33333333
  62. m4d = 0x0f0f0f0f
  63. )
  64. // CountBitsUint32 count 1's in x
  65. func CountBitsUint32(x uint32) int {
  66. x -= ((x >> 1) & m1d)
  67. x = (x & m2d) + ((x >> 2) & m2d)
  68. x = (x + (x >> 4)) & m4d
  69. x += x >> 8
  70. x += x >> 16
  71. return int(x & 0x3f)
  72. }
  73. const (
  74. m1q uint64 = 0x5555555555555555
  75. m2q = 0x3333333333333333
  76. m4q = 0x0f0f0f0f0f0f0f0f
  77. hq = 0x0101010101010101
  78. )
  79. // CountBitsUint64 count 1's in x
  80. func CountBitsUint64(x uint64) int {
  81. // put count of each 2 bits into those 2 bits
  82. x -= (x >> 1) & m1q
  83. // put count of each 4 bits into those 4 bits
  84. x = (x & m2q) + ((x >> 2) & m2q)
  85. // put count of each 8 bits into those 8 bits
  86. x = (x + (x >> 4)) & m4q
  87. // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
  88. return int((x * hq) >> 56)
  89. }
  90. // CountBitsUint64Alt count 1's in x
  91. func CountBitsUint64Alt(x uint64) int {
  92. return CountBitsUint32(uint32(x>>32)) + CountBitsUint32(uint32(x))
  93. }
  94. // CountBitsUintReference count 1's in x
  95. func CountBitsUintReference(x uint) int {
  96. c := 0
  97. for x != 0 {
  98. x &= x - 1
  99. c++
  100. }
  101. return c
  102. }
  103. // CountBitsUint count 1's in x
  104. func CountBitsUint(x uint) int {
  105. if strconv.IntSize == 64 {
  106. return CountBitsUint64(uint64(x))
  107. } else if strconv.IntSize == 32 {
  108. return CountBitsUint32(uint32(x))
  109. }
  110. panic("strconv.IntSize must be 32 or 64 bits")
  111. }