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
According to a certain rack
class Integer
def bitset (start, width, value)
mask=~(~0<<width)
(self&~(mask<<start))|(value&mask)<<start)
end
end
[ ] = 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
© 2024 OneMinuteCode. All rights reserved.