Category:Jq/bitwise.jq

NEWS: 2024.04.06 - flip/1

module {
  "name": "bitwise",
  "description": "bit arrays, bit streams, and integers",
  "version": "2024.04.06",
  "homepage": "https://rosettacode.org/w/index.php?title=Category:Jq/bitwise.jq",
  "license": "MIT",
  "author": "pkoppstein at gmail dot com",
};

# This jq module defines functions for bit-wise operations on integers,
# together with an integer-divsion function, div/1, which is defined
# to take advantage of gojq's support for ininite-precision integer arithmetic.

# To take advantage of gojq's infinite-precision integer arithmetic:
# if the input and $j are integers, then the result will be an integer.
def div($j):
  (. - (. % $j)) / $j;

# Convert the input integer to a stream of 0s and 1s, least significant bit first
def bitwise:
  recurse( if . >= 2 then div(2) else empty end) | . % 2;

# Input is normally an integer but could be a number
def rightshift($n):
  reduce range(0;$n) as $i (.; div(2));

# Input is normally an integer but could be a number
def leftshift($n):
  reduce range(0;$n) as $i (.; . * 2);

# Flip 0 and 1 and leave everything else as is
def flipbits(stream):
  stream | if . == 0 then 1 elif . == 1 then 0 else . end;

# The inverse of `bitwise`
def stream_to_integer(stream):
  reduce stream as $c ( {power:1 , ans: 0};
      .ans += ($c * .power) | .power *= 2 )
  | .ans;

# If the input is a number, emit its round value (because jaq uses `round` to convert real to integer);
# otherwise, the input should be a a bit-array interpreted as having the least-significant bit first
def to_int:
  if type == "number" then round
  else stream_to_integer(.[])
  end ;

# If $n is null, then the bitwise bits of the input integer are simply flipped;
# otherwise, $n, which should be non-negative, determines the width for padding or truncation
def flip($n):
  if $n == null then stream_to_integer(flipbits(bitwise))
  else [limit($n; bitwise)] as $bits
  | stream_to_integer(flipbits( $bits[], (range(0; $n - ($bits|length)) | 0)))
  end;

# Emit an array of the $n least-significant bits of the input non-negative integer;
# the length of the array will thus be less than or equal to $n
def lsbits($n): [limit($n; bitwise)];

# $x and $y should be two non-negative integers or arrays as produced by [bitwise].
# Emit the integer corresponding to the bitwise-or of $x and $y
def bitwise_or($x;$y):
   def tobitarray: if type == "number" then [bitwise] else . end;
   def lor($a;$b):
     if $a==1 or $b==1 then 1
     else 0
     end;
   if   $x == 0 or $x == [0] then $y | to_int
   elif $y == 0 or $y == [0] then $x | to_int
   else ($x|tobitarray) as $s
   | ($y|tobitarray) as $t
   | stream_to_integer(
       range(0; [($s|length), ($t|length)] | max) as $i
       | lor($s[$i]; $t[$i]) )
   end;

# Emit the integer corresponding to `$x bitwise-and $y`,
# assuming these are non-negative integers or bitarrays
def bitwise_xor($x;$y):
   def tobitarray: if type == "number" then [bitwise] else . end;
   def lxor($a; $b):
     if ($a==1 or $b==1) and (($a==1 and $b==1)|not) then 1
     elif $a == null then $b
     elif $b == null then $a
     else 0
     end;
   if $x == 0 or $x == [0] then $y | to_int
   elif $y == 0 or $y == [0] then $x | to_int
   else
     ($x|tobitarray) as $s
   | ($y|tobitarray) as $t
   | stream_to_integer(
       range(0; [($s|length), ($t|length)] | max) as $i
       | lxor($s[$i]; $t[$i]) )
   end ;

# Emit the integer corresponding to `$x bitwise-and $y`,
# assuming these are non-negative integers or bitarrays
def bitwise_and($x; $y):
   def tobitarray: if type == "number" then [bitwise] else . end;      
   def land($a;$b):
      if ($a==1 and $b==1) then 1 else 0 end;

   if $x == 0 or $y == 0 or $x == [0] or $y == [0] then 0
   else ($x|tobitarray) as $s
   | ($y|tobitarray) as $t
   | stream_to_integer(
       range(0; [($s|length), ($t|length)] | min) as $i
       | land($s[$i]; $t[$i]) )
   end ;

# A special case of $x xor $y where both are non-negative integers
# If the input is a number, it determines the maximum number of bits to consider
def xor($x;$y):
  (if type == "number" then round else null end) as $n
  | if $n == null then bitwise_xor($x;$y)
    else bitwise_xor( $x | lsbits($n); $y | lsbits($n) )
    end ;

This category currently contains no pages or media.