I need to convert the follow 4 byte integer to signed integer, like:
input 65535 value -1
input 65534 value -2
input 65533 value -3
and so on...
I tried the follow:
puts (65533).to_s(16) #=> fffd
puts (65533).to_s(16).unpack('s') #=> doesn't work properly... return 26214
Can someone help me with code above?
Best Regards
You could pack it as as an unsigned integer and then unpack it as a signed integer:
[65535, 65534, 65533].pack('S*').unpack('s*')
#=> [-1, -2, -3]
S / s denote 16-bit integers, you can also use L / l for 32-bit or Q / q for 64-bit.
Related
I'm converting arrays consisting of four byte values to 32bit numbers by executing the following code:
a = [0, 16, 82, 0]
i = a.map { |e| "%02x" % e }.join.to_i(16)
# => 1069568
It works as intended, but I wonder if there's a more elegant way to perform this task. Maybe not utilizing strings.
Using pack and unpack1:
a = [0, 16, 82, 0]
a.pack('C4').unpack1('L>')
#=> 1069568
C4 means 8-bit unsigned (4 times) and L> means 32-bit unsigned (big endian).
However, pack returns a binary string, so this is not string-free.
If you have one byte, that would be the result as is. If you add one byte to the right side, that would make the original result move two positions to the left (which means multiplying by 0x100, or 16 ** 2 = 256), and add the new byte. You can repeat this as many times as there are bytes.
a.inject{|acc, byte| acc * 0x100 + byte}
# => 1069568
I want to convert a number, say 1, into a 32 bit binary number:
00000000000000000000000000000001
how can I do this to ensure the full string is of length 32, no matter how small the number might be?
I had a sprintf working for 8 bit binary, but not sure how to make it 32.
Use String#rjust:
1.to_s(2).rjust(32, '0')
#⇒ "00000000000000000000000000000001"
String#% (via sprintf):
'%032b' % 7
=> "00000000000000000000000000000111"
Using pack and unpack1:
[1].pack('L>').unpack1('B*')
#=> "00000000000000000000000000000001"
L indicates 32-bit unsigned integer, > denotes big endian. B indicates bit string, * outputs all available bits.
This will wrap around when exceeding the 32-bit unsigned integer range:
[4_294_967_294].pack('L>').unpack1('B*') #=> "11111111111111111111111111111110"
[4_294_967_295].pack('L>').unpack1('B*') #=> "11111111111111111111111111111111"
[4_294_967_296].pack('L>').unpack1('B*') #=> "00000000000000000000000000000000"
[4_294_967_297].pack('L>').unpack1('B*') #=> "00000000000000000000000000000001"
I tried SecureRandom.random_number(9**6) but it sometimes returns 5 and sometimes 6 numbers. I'd want it to be a length of 6 consistently. I would also prefer it in the format like SecureRandom.random_number(9**6) without using syntax like 6.times.map so that it's easier to be stubbed in my controller test.
You can do it with math:
(SecureRandom.random_number(9e5) + 1e5).to_i
Then verify:
100000.times.map do
(SecureRandom.random_number(9e5) + 1e5).to_i
end.map { |v| v.to_s.length }.uniq
# => [6]
This produces values in the range 100000..999999:
10000000.times.map do
(SecureRandom.random_number(9e5) + 1e5).to_i
end.minmax
# => [100000, 999999]
If you need this in a more concise format, just roll it into a method:
def six_digit_rand
(SecureRandom.random_number(9e5) + 1e5).to_i
end
To generate a random, 6-digit string:
# This generates a 6-digit string, where the
# minimum possible value is "000000", and the
# maximum possible value is "999999"
SecureRandom.random_number(10**6).to_s.rjust(6, '0')
Here's more detail of what's happening, shown by breaking the single line into multiple lines with explaining variables:
# Calculate the upper bound for the random number generator
# upper_bound = 1,000,000
upper_bound = 10**6
# n will be an integer with a minimum possible value of 0,
# and a maximum possible value of 999,999
n = SecureRandom.random_number(upper_bound)
# Convert the integer n to a string
# unpadded_str will be "0" if n == 0
# unpadded_str will be "999999" if n == 999999
unpadded_str = n.to_s
# Pad the string with leading zeroes if it is less than
# 6 digits long.
# "0" would be padded to "000000"
# "123" would be padded to "000123"
# "999999" would not be padded, and remains unchanged as "999999"
padded_str = unpadded_str.rjust(6, '0')
Docs to Ruby SecureRand, lot of cool tricks here.
Specific to this question I would say: (SecureRandom.random_number * 1000000).to_i
Docs: random_number(n=0)
If 0 is given or an argument is not given, ::random_number returns a float: 0.0 <= ::random_number < 1.0.
Then multiply by 6 decimal places (* 1000000) and truncate the decimals (.to_i)
If letters are okay, I prefer .hex:
SecureRandom.hex(3) #=> "e15b05"
Docs:
hex(n=nil)
::hex generates a random hexadecimal string.
The argument n specifies the length, in bytes, of the random number to
be generated. The length of the resulting hexadecimal string is twice
n.
If n is not specified or is nil, 16 is assumed. It may be larger in
future.
The result may contain 0-9 and a-f.
Other options:
SecureRandom.uuid #=> "3f780c86-6897-457e-9d0b-ef3963fbc0a8"
SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
For Rails apps creating a barcode or uid with an object you can do something like this in the object model file:
before_create :generate_barcode
def generate_barcode
begin
return if self.barcode.present?
self.barcode = SecureRandom.hex.upcase
end while self.class.exists?(barcode: barcode)
end
SecureRandom.random_number(n) gives a random value between 0 to n. You can achieve it using rand function.
2.3.1 :025 > rand(10**5..10**6-1)
=> 742840
rand(a..b) gives a random number between a and b. Here, you always get a 6 digit random number between 10^5 and 10^6-1.
If I have a float like 3.75, how can I split it into the integer 3 and the float 0.75?
Do I have to convert the float into a string, and then split the string by ".", and then convert the parts into integers and floats again, or is there a more elegant or "right" way to do this?
You can use Numeric#divmod with argument 1 for this:
Returns an array containing the quotient and modulus obtained by dividing num by numeric.
a.divmod 1
=> [3, 0.75]
If you want to get precise value, this method is available for BigDecimal as well:
3.456.divmod 1
=> [3, 0.45599999999999996]
require 'bigdecimal'
div_mod = BigDecimal("3.456").divmod 1
[div_mod[0].to_i, div_mod[1].to_f]
=> [3, 0.456]
As mentioned you can use 3.75.to_i to get the integer.
An alternate way to get the remainder is using the % operator eg.
3.75 % 1
puts "frac = #{(3.456).to_s.split(".").last.prepend("0.").to_f}"
puts "Integer part = #{(3.456).truncate}"
As the title says, I'm a little lost on how to accomplish this in Ruby...there are number of topics on how to do this in C or C++. Any ruby experts out there that can chime in on this?
The same syntax you'd use in C works in ruby, just drop the typecasts:
n = 0xFFFFFFFFEEEEEEEE
x = (n & 0xFFFFFFFF00000000) >> 32
y = n & 0xFFFFFFFF
puts x.to_s(16)
# => "ffffffff"
puts y.to_s(16)
# => "eeeeeeee"
v = x << 32 | y
puts v.to_s(16)
# => "ffffffffeeeeeeee"
If you need the values to be in chunks of exactly 32 bits (i.e. you need to speak binary to some external data file or program), then you'll want to use Array#pack and String#unpack to get the right bits.
one 64bit integer is not equal to two 32bit integers.
http://en.wikipedia.org/wiki/Integer_(computer_science)