Packing a long binary integer in Ruby - ruby

I'm trying to send a very long binary integer over UDP (on the order of 200 bits). When I try to use Array's pack method, it complains the string I'm trying to convert is too large.
Am I going about this the wrong way?
ruby-1.8.7-p352 :003 > [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
RangeError: bignum too big to convert into `unsigned long'
from (irb):3:in `pack'
from (irb):3
This number is supposed to represent a DNS query packet (this is for a homework assignment; we're not allowed to use any DNS libraries).

You need to break apart your number into smaller pieces. Probably best is to encode 32 bits at a time:
> num = 0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101
=> 17502556204775004286774747314501014869
> low_1 = num & 0xFFFFFFFF
=> 2864534869
> low_2 = (num >> 32) & 0xFFFFFFFF
=> 625650362
> low_3 = (num >> 64) & 0xFFFFFFFF
=> 1297454421
> low_4 = (num >> 96) & 0xFFFFFFFF
=> 220913317
> (low_4 << 96) + (low_3 << 64) + (low_2 << 32) + low_1
=> 17502556204775004286774747314501014869
> msg = [low_4, low_3, low_2, low_1].pack("NNNN")
=> "\r*\336\245MU\225U%J\252\272\252\275UU"
> msg.unpack("NNNN").inject {|sum, elem| (sum << 32) + elem}
=> 17502556204775004286774747314501014869
I prefer 32 bits here because you pack these in Network Byte Order, which makes interopation with other platforms much easier. The pack() method doesn't provide a network byte order 64-bit integer. (Which isn't too surprising, since POSIX doesn't provide a 64-bit routine.)

Ruby 1.9.3 works normally.
irb(main):001:0> [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i')
=> "UU\xBD\xAA"

Related

How do I split an integer into 2 byte binary in Ruby?

Have ready C# code to split integer into 2 bytes as you can see below, Needs to re-write same in Ruby-
int seat2 = 65000;
// Split into two bytes
byte seats = (byte)(seat2 & 0xFF); // lower byte
byte options = (byte)((seat2 >> 8) & 0xFF); // upper byte
Below is the output above
Output Seats => 232
options => 253
// Merge back into integer
seat2 = (options << 8) | seats;
Please suggest anyone has any solution to rewrite the above in Ruby
The code you wrote would work well in Ruby with very few modifications.
You could simply try:
seat2 = 65000
seat2 & 0xFF
# => 232
(seat2 >> 8) & 0xFF
# => 253
An alternative would be to use pack and unpack:
[65000].pack('S').unpack('CC')
# => [232, 253]
[232, 253].pack('CC').unpack('S')
# => [65000]
I believe the most idiomatic way for binary transformations in Ruby is Array#pack and String#unpack (like in Eric's answer).
Also you have an option to use Numeric#divmod with 256(2^8, byte size):
> upper, lower = 65000.divmod(256)
# => [253, 232]
> upper
# => 253
> lower
# => 232
In this case, to have correct bytes, your Integer should not exceed 65535 (2^16-1).
Another one:
lower, upper = 65000.digits(256)

Converting a floating point to its corresponding bit-segments

Given a Ruby Float value, e.g.,
f = 12.125
I'd like to wind up a 3-element array containing the floating-point number's sign (1 bit), exponent (11 bits), and fraction (52 bits). (Ruby's floats are the IEEE 754 double-precision 64-bit representation.)
What's the best way to do that? Bit-level manipulation doesn't seem to be Ruby's strong point.
Note that I want the bits, not the numerical values they correspond to. For instance, getting [0, -127, 1] for the floating-point value of 1.0 is not what I'm after -- I want the actual bits in string form or an equivalent representation, like ["0", "0ff", "000 0000 0000"].
The bit data can be exposed via Arrays pack as Float doesn't provide functions internally.
str = [12.125].pack('D').bytes.reverse.map{|n| "%08b" %n }.join
=> "0100000000101000010000000000000000000000000000000000000000000000"
[ str[0], str[1..11], str[12..63] ]
=> ["0", "10000000010", "1000010000000000000000000000000000000000000000000000"]
This is a bit 'around about the houses' to pull it out from a string representation. I'm sure there is a more efficient way to pull the data from the original bytes...
Edit The bit level manipulation tweaked my interest so I had a poke around. To use the operations in Ruby you need to have an Integer so the float requires some more unpacking to convert into a 64 bit int. The big endian/ieee754 documented representation is fairly trivial. The little endian representation I'm not so sure about. It's a little odd, as you are not on complete byte boundaries with an 11 bit exponent and 52 bit mantissa. It's becomes fiddly to pull the bits out and swap them about to get what resembles little endian, and not sure if it's right as I haven't seen any reference to the layout. So the 64 bit value is little endian, I'm not too sure how that applies to the components of the 64bit value until you store them somewhere else, like a 16bit int for the mantissa.
As an example for an 11 bit value from little > big, The kind of thing I was doing was to shift the most significant byte left 3 to the front, then OR with the least significant 3 bits.
v = 0x4F2
((v & 0xFF) << 3) | ( v >> 8 ))
Here it is anyway, hopefully its of some use.
class Float
Float::LITTLE_ENDIAN = [1.0].pack("E") == [1.0].pack("D")
# Returns a sign, exponent and mantissa as integers
def ieee745_binary64
# Build a big end int representation so we can use bit operations
tb = [self].pack('D').unpack('Q>').first
# Check what we are
if Float::LITTLE_ENDIAN
ieee745_binary64_little_endian tb
else
ieee745_binary64_big_endian tb
end
end
# Force a little end calc
def ieee745_binary64_little
ieee745_binary64_little_endian [self].pack('E').unpack('Q>').first
end
# Force a big end calc
def ieee745_binary64_big
ieee745_binary64_big_endian [self].pack('G').unpack('Q>').first
end
# Little
def ieee745_binary64_little_endian big_end_int
#puts "big #{big_end_int.to_s(2)}"
sign = ( big_end_int & 0x80 ) >> 7
exp_a = ( big_end_int & 0x7F ) << 1 # get the last 7 bits, make it more significant
exp_b = ( big_end_int & 0x8000 ) >> 15 # get the 9th bit, to fill the sign gap
exp_c = ( big_end_int & 0x7000 ) >> 4 # get the 10-12th bit to stick on the front
exponent = exp_a | exp_b | exp_c
mant_a = ( big_end_int & 0xFFFFFFFFFFFF0000 ) >> 12 # F000 was taken above
mant_b = ( big_end_int & 0x0000000000000F00 ) >> 8 # F00 was left over
mantissa = mant_a | mant_b
[ sign, exponent, mantissa ]
end
# Big
def ieee745_binary64_big_endian big_end_int
sign = ( big_end_int & 0x8000000000000000 ) >> 63
exponent = ( big_end_int & 0x7FF0000000000000 ) >> 52
mantissa = ( big_end_int & 0x000FFFFFFFFFFFFF ) >> 0
[ sign, exponent, mantissa ]
end
end
and testing...
def printer val, vals
printf "%-15s sign|%01b|\n", val, vals[0]
printf " hex e|%3x| m|%013x|\n", vals[1], vals[2]
printf " bin e|%011b| m|%052b|\n\n", vals[1], vals[2]
end
floats = [ 12.125, -12.125, 1.0/3, -1.0/3, 1.0, -1.0, 1.131313131313, -1.131313131313 ]
floats.each do |v|
printer v, v.ieee745_binary64
printer v, v.ieee745_binary64_big
end
TIL my brain is big endian! You'll note the ints being worked with are both big endian. I failed at bit shifting the other way.
Use frexp from the Math module. From the doc:
fraction, exponent = Math.frexp(1234) #=> [0.6025390625, 11]
fraction * 2**exponent #=> 1234.0
The sign bit is easy to find on its own.

Ensuring variable size for bitwise operations in Ruby

I have a group of hex values that describe an object in ruby and I want to string them all together into a single bit bucket. In C++ I would do the following:
int descriptor = 0 // or uint64_t to be safe
descriptor += (firstHexValue << 60)
descriptor += (secondHex << 56)
descriptor += (thirdHex << 52)
// ... etc
descriptor += (sixteenthHex << 0)
I want to do the same thing in Ruby, but as Ruby is untyped, I am worried about overflow. If I try and do the same thing in Ruby, is there a way to ensure that descriptor contains 64 bits? Once the descriptors are set, I don't want to suddenly find that only 32 bits are represented and I've lost half of it! How can I safely achieve the same result as above?
Note: Working on OS X 64bit if that is relevant.
Ruby has unlimited integers, so don't worry about that. You won't lose a single bit.
a = 0
a |= (1 << 200)
a # => 1606938044258990275541962092341162602522202993782792835301376

math calculations in ruby

I have a standard formula for calculating loan amortization schedule.
Here is the formula:
(Px(i/12))/(1-(1+i/12)^-n)
Here is what I have in ruby:
p = BigDecimal('1000.0')
n = BigDecimal('12')
i = BigDecimal('3')
m = (p * (i/12))/(1-(1+i/12) ** -n)
I'm getting a following error: in `**': wrong argument type BigDecimal (expected Fixnum) (TypeError)
I'm having hard time trying to play with Fixnun, Float and BigDecimal in ruby.
n must be an integer per definition if you want to use ** aka BigDecimal#power(n)
PS: I just looked up your formula on wikipedia. Since n is the number of payments, it will be an integer by nature so just use a Fixnum for n - you won't get any troubles :)
Using floats :
>> p = 1000.0
=> 1000.0
>> n = 12.0
=> 12.0
>> i = 3.0
=> 3.0
>> (p*(i/12))/(1-(1+i/12)**-n)
=> 268.447577024146
Using BigDecimal :
>> p = BigDecimal('1000.0')
=> #<BigDecimal:1082c4760,'0.1E4',4(12)>
>> n = BigDecimal('12')
=> #<BigDecimal:1082c14c0,'0.12E2',4(8)>
>> i = BigDecimal('3')
=> #<BigDecimal:1082be2e8,'0.3E1',4(8)>
>> m = (p * (i/12))/(1-(1+i/12) ** -n.to_i)
=> #<BigDecimal:1082b4950,'0.2684475770 2414639639 7495957671 887300036E3',40(48)>
>> m.to_i
=> 268
It seems that the BigDecimal ** only takes a FixNum as the power part...
By putting the .0 at the end of the numbers it makes them all into floats. Works for me.

Ruby max integer

I need to be able to determine a systems maximum integer in Ruby. Anybody know how, or if it's possible?
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
FIXNUM_MIN = -(2**(0.size * 8 -2))
Ruby automatically converts integers to a large integer class when they overflow, so there's (practically) no limit to how big they can be.
If you are looking for the machine's size, i.e. 64- or 32-bit, I found this trick at ruby-forum.com:
machine_bytes = ['foo'].pack('p').size
machine_bits = machine_bytes * 8
machine_max_signed = 2**(machine_bits-1) - 1
machine_max_unsigned = 2**machine_bits - 1
If you are looking for the size of Fixnum objects (integers small enough to store in a single machine word), you can call 0.size to get the number of bytes. I would guess it should be 4 on 32-bit builds, but I can't test that right now. Also, the largest Fixnum is apparently 2**30 - 1 (or 2**62 - 1), because one bit is used to mark it as an integer instead of an object reference.
Reading the friendly manual? Who'd want to do that?
start = Time.now
largest_known_fixnum = 1
smallest_known_bignum = nil
until smallest_known_bignum == largest_known_fixnum + 1
if smallest_known_bignum.nil?
next_number_to_try = largest_known_fixnum * 1000
else
next_number_to_try = (smallest_known_bignum + largest_known_fixnum) / 2 # Geometric mean would be more efficient, but more risky
end
if next_number_to_try <= largest_known_fixnum ||
smallest_known_bignum && next_number_to_try >= smallest_known_bignum
raise "Can't happen case"
end
case next_number_to_try
when Bignum then smallest_known_bignum = next_number_to_try
when Fixnum then largest_known_fixnum = next_number_to_try
else raise "Can't happen case"
end
end
finish = Time.now
puts "The largest fixnum is #{largest_known_fixnum}"
puts "The smallest bignum is #{smallest_known_bignum}"
puts "Calculation took #{finish - start} seconds"
In ruby Fixnums are automatically converted to Bignums.
To find the highest possible Fixnum you could do something like this:
class Fixnum
N_BYTES = [42].pack('i').size
N_BITS = N_BYTES * 8
MAX = 2 ** (N_BITS - 2) - 1
MIN = -MAX - 1
end
p(Fixnum::MAX)
Shamelessly ripped from a ruby-talk discussion. Look there for more details.
There is no maximum since Ruby 2.4, as Bignum and Fixnum got unified into Integer. see Feature #12005
> (2 << 1000).is_a? Fixnum
(irb):322: warning: constant ::Fixnum is deprecated
=> true
> 1.is_a? Bignum
(irb):314: warning: constant ::Bignum is deprecated
=> true
> (2 << 1000).class
=> Integer
There won't be any overflow, what would happen is an out of memory.
as #Jörg W Mittag pointed out: in jruby, fix num size is always 8 bytes long. This code snippet shows the truth:
fmax = ->{
if RUBY_PLATFORM == 'java'
2**63 - 1
else
2**(0.size * 8 - 2) - 1
end
}.call
p fmax.class # Fixnum
fmax = fmax + 1
p fmax.class #Bignum

Resources