-3

How to solve this example in Ruby

Do rotating left shift and print the value.

  • Example with x = 0x12345678
  • n = 4 → 0x23456781
  • n = 20 → 0x67812345
  • n = 2 → 0x048D159E
  • rotate_left(unsigned int x, unsigned char n) ...
  • 5
    Explain the output, please. Why does "rotating left shift" `x` by `4` result in `0x23456781`? Where does `0x048D159E` come from? – Stefan Apr 21 '17 at 14:10
  • 1
    @Stefan there are two puzzles in one: we should determine an algorithm in the first place. – Aleksei Matiushkin Apr 21 '17 at 15:21
  • Help us and then we can help you. – Sagar Pandya Apr 21 '17 at 15:48
  • Please read "[ask]" including the linked pages, "[mcve]" and "[How much research effort is expected of Stack Overflow users?](http://meta.stackoverflow.com/questions/261592)". We'd like to see evidence of your effort. What did you try? Did you search and not find anything? Did you find stuff but it didn't help? Did you try writing code? If not, why? If so, what is the smallest code example that shows what you tried and why didn't it work? Without that it looks like you didn't try and want us to write it for you. – the Tin Man Apr 21 '17 at 20:26

2 Answers2

2

This will perform the wrap-around shift by converting the number to a binary string. Disclaimer: it's horribly inefficient.

def rotate_left x, n
  b = x.to_s(2).rjust(32, '0')
  "#{b[n...b.length]}#{b[0...n]}".to_i(2)
end

# >  "0x" + rotate_left(0x12345678), 4).to_s(16)
# => "0x23456781"
#
# >  "0x" + rotate_left(0x12345678), 20).to_s(16)
# => "0x67812345"
#
# >  "0x" + rotate_left(0x12345678), 20).to_s(16)
# => "0x48d159e0"
eiko
  • 5,110
  • 6
  • 17
  • 35
1

It wasn't easy to understand what you wanted to achieve.

A naive approach is to convert the number to a binary string, pad it to 32 length, rotate it and convert it back to a number :

def rotate_left(x, n)
  x.to_s(2).rjust(32, '0').each_char.to_a.rotate(n).join.to_i(2)
end

A much more efficient alternative is to apply bitwise operations only:

  • left-shift x by n
    • if it's bigger than 2**32-1, truncate it with & 0xFFFFFFFF
  • right-shift x by 32 - n
  • apply bitwise OR between those 2 numbers

def rotate_left(x, n)
  ((x << n) & (2**32 - 1)) | (x >> (32 - n))
end

For both methods:

[4, 20, 2].each do |l|
  p rotate_left(0x12345678, l).to_s(16)
end
# "23456781"
# "67812345"
# "48d159e0"

Note that the last output is "48d159e0" and not "48d159e". Without more information, it's hard to know if it's the desired result.

Community
  • 1
  • 1
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124