How Ruby Modifies Bits

Asked 2 years ago, Updated 2 years ago, 27 views

Looking for a way to modify the bits specified in Ruby.
Ruby 2.7 and later has a very useful method called Integer#[] according to the official reference.

 Same as i[nth,len]#(n>>i)&((1<<len)-1) 
i [range]

Then you can take out the bits.

https://docs.ruby-lang.org/ja/latest/method/Integer/i/=5b=5d.html

On the other hand,

The reason why self[nth] = bit (i.e., bit modification) is not available is because the Numeric related class is immutable.

The bit cannot be modified (the Integer cannot be modified, so you must create a new Integer object).Modify the bits listed here

self[nth,len]=n

How should I write the equivalent operation in Ruby?

Using Wikipedia's mask (information engineering), I wrote:

class Integer
  def[] = (start, width, value)
    if value.bit_length>width
      # If FIXME:value is negative, the error is a little strange...
      raise "Value#{value} is larger than #{(1<width)-1}"
    end

    all=(1<<self.bit_length) -1)
    mask=all^((1<<width)-1)<<start)
    masked_value = self&mask
    new_value = masked_value | (value <<start)
    p new_value
  end
end

This is the way I came up with it, but there may be other better ways.Please let me know if you know.Also, I would appreciate it if you could point out any deficiencies in the above implementation methods.I look forward to your kind cooperation.

ruby

2022-09-29 20:28

2 Answers

According to a certain rack

class Integer
  def bitset (start, width, value)
    mask=~(~0<<width)
    (self&~(mask<<start))|(value&mask)<<start)
  end
end


2022-09-29 20:28

[ ] = is bf_set() and can also be specified in Array 0.bf_set(3,5,[1,0,1,0])#=>176
That's all I need, so I added whatever I wanted.
Simpler and more compact than faster algorithms.(In other words, cut corners)

#bf_?? Bit Field...
# Ruby Compatibility Notes
#   One-line method definition is Ruby 3.0.0 or later
#   Integer# bit_length is Runy 2.1.0 or later
class Integer
  def bf_set(start, width, value)# bf_set(start, width, value) ->Integer;bf_set(start, width, [array]) ->Integer
    if value.is_a?(Array)
#     raise if width > value.size # width and value.size do not expect to match (prefer lower bit)
      value=value.inject(0){|r,w|r<<1|((w==0||w==?0||w==false||w==nil)?0:1)}
    end
    mask=(1<width) - 1<<start
    (mask&self^self) | (mask&value<<start)
  end
  def bf_and (start, width, value)
    mask=(1<width) - 1<<start
    (mask&self^self) | (mask&value<<start)&self
  end
  def bf_add(start, width, value)
    mask=(1<width) - 1<<start
    (mask&self^self) | mask&(self+(value<<start))
  end
  def bf_inc(start, width) = self.bf_add(start, width, 1)
  def bf_dec(start, width) = self.bf_add(start, width, -1)
  def bf_get(start, width)=(1<<width)-1&self>>start#self[start, width]
  def bf_or(start, width, value)=((1<<width)-1)&value)<<start|self
  def bf_xor(start, width, value)=((1<width)-1)&value)<<start^self
  def bf_clear(start, width)=((1<<width)-1)<start&self^self
  def bf_full(start, width)=(1<<width)-1)<<start|self
  def bf_not(start, width)=((1<<width)-1)<<start^self
  def bf_rotate(start, width, cnt)
    mask=(1<width) - 1<<start
    rotate=cnt%width
    wrk = self&mask
    val=self^wrk
    val|=mask&(wrk<<rotate|wrk>width-rotate)
  end
  def bf_sign(start, width)#sign->-1 | 0 | 1
    case
    when self&1<<start+width-1!=0then-1
    when self&(1<width) - 1<<start==0then0
    else1
    end
  end
  def bf_reverse(start, width=nil)# bf_reverse(start, width)->Integer;bf_reverse(Range)->Integer
    If start.is_a?(Range)#12..4, both start.min and start.max are nil, but .first, .last are valid.
      width = start.last
      start = start.first
      start, width = width, start if start > width
      width-=start
    end
    mask = 1 <<start
    wrk = (1<width) - 1<<start)&self
    val=wrk^self
    rv = 0
    width.times{
      rv = rv <<1 | wrk & mask
      wrk>>=1
    }
    val | rv
  end
  Number of def bf_count(start, width)#1
    val=(((1<width)-1<<start)&self)>>start#Lighten the processing in the loop (>start)
    count = 0
    while val!=0
      val&=val-1
      count+=1
    end
    count
  end
  Maximum length that def bf_max(start, width)#1 continues.0101110110->30101010101->1
    val=(((1<<width)-1<<start)&self)>start
    max = 0
    while val!=0
      val&=val>>1
      max + = 1
    end
    max
  end
  Minimum length that def bf_min(start, width)#1 continues.011111001110110->20101010101->1
    val=(((1<<width)-1<<start)&self)>start
    min = 0
    while val!=0
      min + = 1
      w=val&val>>1
      US>break if val!=w|w<<1
      val=w
    end
    min
  end
  def bf_rbit(start, width)# lowest 1 bit position 0->0,1...
    val=(((1<<width)-1<<start)&self)>start
    (val&-val).bit_length
  end
  def bf_lbit(start, width)# top 1 bit position
    ((((1<width)-1<<start)&self)>>start.bit_length
  end
  def bf_unpack(width)#bf_unpack([width])->[val]#0x52f50170.bf_unpack([7,4,5,5,6,5])#=>[41,7,21,0,11,16]
    raise unless width.is_a?(Array)
    val = [ ]
    wrk = self
    width.reverse.each { | w |
      val.unshift ((1<<w.to_i) - 1&wrk)
      wrk>>=w.to_i
    }
    val
  end
  def bf_dot?(start, width) #1 is true (2**n)
    val=(((1<<width)-1<<start)&self)>start
    (val==0)?false:val&val-1==0
  end
end

class array
  def bf_pack(value)#[width].bt_pack([value]) - > Integer #width, value is Little Endian
    raise unless value.is_a?(Array)&self.size==value.size
    val = 0
    start = 0
    self.reverse.each_with_index {|w, i|
      val=val.bf_set (start, w.to_i, value [value.size-i-1])
      start+=w.to_i
    }
    val
  end
end


2022-09-29 20:28

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.