Reputation: 12693
Substrings work where "hello"[0..2]
returns "hel"
Is there an integer equivalent, that returns the sub-bits, as in 9[1..3]
returns 4
or "100"
?
Context:
I'm trying to do a genetic algorithm, and there is a cross over stage where you split two chromosomes in two, then swap halves, e.g. "10101010"
crossed with "00000000"
at i = 4
would be "00001010", "10100000"
However, I'm doing this a few million times, so using strings is inefficient, so is there a bitwise way to do this?
Upvotes: 0
Views: 149
Reputation: 110685
You might consider refining the class Fixnum to permit Fixnum#[]'s argument to be either a bit index or a range of bit indices.
module StabBitRange
def [](arg)
case arg
when Range
mask = arg.reduce(0) { |n, idx| n |= (1 << idx) }
(self & mask) >> arg.first
else
super
end
end
end
module StabBits
refine Fixnum do
prepend StabBitRange
end
end
See Refinements and Module#prepend. Prepend StabBitRange
moves the methods contained therein (here just one) before the methods with the same names in Fixnum
in the ancestor chain. The alternative (commonly used before Prepend
was introduced in Ruby v2.0) is to alias Fixnum#[]
and then redefine Fixnum[]
to be the new method that takes either a bit index or a range of bit indices. (See the edit history of this answer to see how that is done.) I expect readers will agree that Prepend
is a more sensible way of doing that.
To make this code available for use we need only invoke the keyword using
.
using StabBits
n = 682
n.to_s(2) #=> "1010101010"
n[0] #=> 0
n[1] #=> 1
n[2] #=> 0
n[0..7] #=> 170 170.to_s(2) => "10101010"
n[1..7] #=> 85 85.to_s(2) => "1010101"
n[2..6] #=> 10 10.to_s(2) => "1010"
When StabBitRange#\[\]
is called and the argument is not a range, super
invokes Fixnum#[]
and passes the argument. That method handles argument errors as well as returning the desired bit when there are no errors.
When this code is run in IRB, the following exception is raised: RuntimeError: main.using is permitted only at top level
. That's because IRB is running at the top level, but code run within IRB is running at a higher level from the perspective of the Ruby parser. To run this in IRB it is necessary to enclose using StabBits
and the code following in a module.
Upvotes: 1