github.com/primecitizens/pcz/std@v0.2.1/core/bits/ones.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright 2023 The Prime Citizens
     3  //
     4  // Copyright 2017 The Go Authors. All rights reserved.
     5  // Use of this source code is governed by a BSD-style
     6  // license that can be found in the LICENSE file.
     7  
     8  package bits
     9  
    10  import (
    11  	"github.com/primecitizens/pcz/std/core/arch"
    12  )
    13  
    14  const (
    15  	m0 = 0x5555555555555555 // 01010101 ...
    16  	m1 = 0x3333333333333333 // 00110011 ...
    17  	m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
    18  	m3 = 0x00ff00ff00ff00ff // etc.
    19  	m4 = 0x0000ffff0000ffff
    20  )
    21  
    22  // OnesCount returns the number of one bits ("population count") in x.
    23  func OnesCount(x uint) int {
    24  	if arch.UintBits == 32 {
    25  		return OnesCount32(uint32(x))
    26  	}
    27  	return OnesCount64(uint64(x))
    28  }
    29  
    30  const Pop8Table = "" +
    31  	"\x00\x01\x01\x02\x01\x02\x02\x03\x01\x02\x02\x03\x02\x03\x03\x04" +
    32  	"\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" +
    33  	"\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" +
    34  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    35  	"\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" +
    36  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    37  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    38  	"\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" +
    39  	"\x01\x02\x02\x03\x02\x03\x03\x04\x02\x03\x03\x04\x03\x04\x04\x05" +
    40  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    41  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    42  	"\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" +
    43  	"\x02\x03\x03\x04\x03\x04\x04\x05\x03\x04\x04\x05\x04\x05\x05\x06" +
    44  	"\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" +
    45  	"\x03\x04\x04\x05\x04\x05\x05\x06\x04\x05\x05\x06\x05\x06\x06\x07" +
    46  	"\x04\x05\x05\x06\x05\x06\x06\x07\x05\x06\x06\x07\x06\x07\x07\x08"
    47  
    48  // OnesCount8 returns the number of one bits ("population count") in x.
    49  func OnesCount8(x uint8) int {
    50  	return int(Pop8Table[x])
    51  }
    52  
    53  // OnesCount16 returns the number of one bits ("population count") in x.
    54  func OnesCount16(x uint16) int {
    55  	return int(Pop8Table[x>>8] + Pop8Table[x&0xff])
    56  }
    57  
    58  // OnesCount32 returns the number of one bits ("population count") in x.
    59  func OnesCount32(x uint32) int {
    60  	return int(Pop8Table[x>>24] + Pop8Table[x>>16&0xff] + Pop8Table[x>>8&0xff] + Pop8Table[x&0xff])
    61  }
    62  
    63  // OnesCount64 returns the number of one bits ("population count") in x.
    64  func OnesCount64(x uint64) int {
    65  	// Implementation: Parallel summing of adjacent bits.
    66  	// See "Hacker's Delight", Chap. 5: Counting Bits.
    67  	// The following pattern shows the general approach:
    68  	//
    69  	//   x = x>>1&(m0&m) + x&(m0&m)
    70  	//   x = x>>2&(m1&m) + x&(m1&m)
    71  	//   x = x>>4&(m2&m) + x&(m2&m)
    72  	//   x = x>>8&(m3&m) + x&(m3&m)
    73  	//   x = x>>16&(m4&m) + x&(m4&m)
    74  	//   x = x>>32&(m5&m) + x&(m5&m)
    75  	//   return int(x)
    76  	//
    77  	// Masking (& operations) can be left away when there's no
    78  	// danger that a field's sum will carry over into the next
    79  	// field: Since the result cannot be > 64, 8 bits is enough
    80  	// and we can ignore the masks for the shifts by 8 and up.
    81  	// Per "Hacker's Delight", the first line can be simplified
    82  	// more, but it saves at best one instruction, so we leave
    83  	// it alone for clarity.
    84  	const m = 1<<64 - 1
    85  	x = x>>1&(m0&m) + x&(m0&m)
    86  	x = x>>2&(m1&m) + x&(m1&m)
    87  	x = (x>>4 + x) & (m2 & m)
    88  	x += x >> 8
    89  	x += x >> 16
    90  	x += x >> 32
    91  	return int(x) & (1<<7 - 1)
    92  }