proc nthBitZero(data: uint64, n: uint64): bool {.inline.} =
(data shr n) mod 2'u64 == 0'u64
So far, so good. Later, I tried to change the size to just one byte, so use uint8 instead.
proc nthBitZero(data: uint8, n: uint8): bool {.inline.} =
(data shr n) mod 2'u8 == 0'u8
Unfortunately this does not compile (nor does uint32 or uint16, failing with
lib/core/unsigned.nim(32, 30) Error: invalid type: 'proc (range 0..1(uint8), range 0..1(uint8)): bool{.noSideEffect.}'.
Does anyone know what is going on?
Maybe instead of using mod you can use bitwise operations to extract the value? Example:
proc test() =
let
up: int = 0xF0
down: int = 0x0F
mask: int = 0x88
echo up, " ", down, " ", mask
echo (up and down)
echo (up or down)
echo ((up or down) and mask)
when isMainModule: test()
I would be happy to do so, but I need a little more help. I can use bitwise operations to extract a fixed bit, but is there a way to extract a bit knowing its position (other than hardcoding all the bitmasks and using a switch?
I was under the assumption that compilers would make mod 2 operations into just checking a bit.
This seems to be a bug in the comparison of subranges of uints. The compiler knows that "mod 2" for unsigned ints will generate an integer in the range 0..1 and remembers that, but that then seems to fail some internal check (that I haven't gotten around to looking at yet).
Workaround: Convert both sides of a comparison to uint or in your specific case, cast the result to bool:
proc nthBitZero(data: uint8, n: uint8): bool {.inline.} =
not bool((data shr n) mod 2'u8)
I am trying to do something similar to the above, namely counting the number of set bits in an integer, but can't quite figure out how to get it to work. Following the above, I tried (along with many other configurations):
proc count_set_bits(val, len: int): int =
var copy = val
for i in [0..len-1]:
if bool(copy mod 2):
inc(result)
copy shr 1
I don't want to change val, and len will usually be a constant. I get either compiler errors relating to discard, or I see that copy's value never gets updated. Any clues what's going wrong? Thanks, Royecopy = copy shr 1
@jibal thanks, but for now just having it work would be nice ;) @Stefan_Salewski, tried it, added some prints, and it seems copy's value never gets updated:
proc count_set_bits(val, len: int): int =
var copy = val
echo("initial val is " & $val)
for i in [0..len-1]:
echo("val updated to " & $copy)
if bool(copy mod 2):
inc(result)
echo("result updated to " & $result)
copy = copy shr 1
echo("final result is " & $result)
the output I see is like this:
initial val is 1
val updated to 1
result updated to 1
final result is 1
initial val is 2
val updated to 2
final result is 0
initial val is 8
val updated to 8
final result is 0
initial val is 2
val updated to 2
final result is 0
I tried using other options such as having val be a var int, but couldn't get it to work that way either...
[0..len-1] is an array that contains a single element Slice(a: 0, b: len-1). Instead you want 0..len-1 or 0..<len. This should work:
proc count_set_bits(val, len: int): int =
var copy = val
echo "initial val is ", val
for i in 0..<len:
echo "val updated to ", copy
if copy mod 2 == 1:
inc result
echo "result updated to ", result
copy = copy shr 1
echo "final result is ", result
echo count_set_bits(1, 64)