github.com/primecitizens/pcz/std@v0.2.1/core/bits/zeros.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  // LeadingZeros returns the number of leading zero bits in x; the result is UintSize for x == 0.
    15  func LeadingZeros(x uint) int { return arch.UintBits - Len(x) }
    16  
    17  // LeadingZeros8 returns the number of leading zero bits in x; the result is 8 for x == 0.
    18  func LeadingZeros8(x uint8) int { return 8 - Len8(x) }
    19  
    20  // LeadingZeros16 returns the number of leading zero bits in x; the result is 16 for x == 0.
    21  func LeadingZeros16(x uint16) int { return 16 - Len16(x) }
    22  
    23  // LeadingZeros32 returns the number of leading zero bits in x; the result is 32 for x == 0.
    24  func LeadingZeros32(x uint32) int { return 32 - Len32(x) }
    25  
    26  // LeadingZeros64 returns the number of leading zero bits in x; the result is 64 for x == 0.
    27  func LeadingZeros64(x uint64) int { return 64 - Len64(x) }
    28  
    29  // See http://supertech.csail.mit.edu/papers/debruijn.pdf
    30  const (
    31  	DeBruijn32      = 0x077CB531
    32  	DeBruijn32Table = "" +
    33  		"\x00\x01\x28\x02\x29\x14\x24\x03\x30\x22\x20\x15\x25\x17\x04\x08" +
    34  		"\x31\x27\x13\x23\x21\x19\x16\x07\x26\x12\x18\x06\x11\x05\x10\x09"
    35  )
    36  
    37  const (
    38  	DeBruijn64      = 0x03f79d71b4ca8b09
    39  	DeBruijn64Table = "" +
    40  		"\x00\x01\x56\x02\x57\x49\x28\x03\x61\x58\x42\x50\x38\x29\x17\x04" +
    41  		"\x62\x47\x59\x36\x45\x43\x51\x22\x53\x39\x33\x30\x24\x18\x12\x05" +
    42  		"\x63\x55\x48\x27\x60\x41\x37\x16\x46\x35\x44\x21\x52\x32\x23\x11" +
    43  		"\x54\x26\x40\x15\x34\x20\x31\x10\x25\x14\x19\x09\x13\x08\x07\x06"
    44  )
    45  
    46  // TrailingZeros returns the number of trailing zero bits in x; the result is UintSize for x == 0.
    47  func TrailingZeros(x uint) int {
    48  	if arch.UintBits == 32 {
    49  		return TrailingZeros32(uint32(x))
    50  	}
    51  	return TrailingZeros64(uint64(x))
    52  }
    53  
    54  const Ntz8Table = "" +
    55  	"\x08\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    56  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    57  	"\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    58  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    59  	"\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    60  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    61  	"\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    62  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    63  	"\x07\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    64  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    65  	"\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    66  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    67  	"\x06\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    68  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    69  	"\x05\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00" +
    70  	"\x04\x00\x01\x00\x02\x00\x01\x00\x03\x00\x01\x00\x02\x00\x01\x00"
    71  
    72  // TrailingZeros8 returns the number of trailing zero bits in x; the result is 8 for x == 0.
    73  func TrailingZeros8(x uint8) int {
    74  	return int(Ntz8Table[x])
    75  }
    76  
    77  // TrailingZeros16 returns the number of trailing zero bits in x; the result is 16 for x == 0.
    78  func TrailingZeros16(x uint16) int {
    79  	if x == 0 {
    80  		return 16
    81  	}
    82  	// see comment in TrailingZeros64
    83  	return int(DeBruijn32Table[uint32(x&-x)*DeBruijn32>>(32-5)])
    84  }
    85  
    86  // TrailingZeros32 returns the number of trailing zero bits in x; the result is 32 for x == 0.
    87  func TrailingZeros32(x uint32) int {
    88  	if x == 0 {
    89  		return 32
    90  	}
    91  	// see comment in TrailingZeros64
    92  	return int(DeBruijn32Table[(x&-x)*DeBruijn32>>(32-5)])
    93  }
    94  
    95  // TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
    96  func TrailingZeros64(x uint64) int {
    97  	if x == 0 {
    98  		return 64
    99  	}
   100  	// If popcount is fast, replace code below with return popcount(^x & (x - 1)).
   101  	//
   102  	// x & -x leaves only the right-most bit set in the word. Let k be the
   103  	// index of that bit. Since only a single bit is set, the value is two
   104  	// to the power of k. Multiplying by a power of two is equivalent to
   105  	// left shifting, in this case by k bits. The de Bruijn (64 bit) constant
   106  	// is such that all six bit, consecutive substrings are distinct.
   107  	// Therefore, if we have a left shifted version of this constant we can
   108  	// find by how many bits it was shifted by looking at which six bit
   109  	// substring ended up at the top of the word.
   110  	// (Knuth, volume 4, section 7.3.1)
   111  	return int(DeBruijn64Table[(x&-x)*DeBruijn64>>(64-6)])
   112  }