【问题标题】:Converting Integers to Binary in Ruby在 Ruby 中将整数转换为二进制
【发布时间】:2015-09-21 14:33:31
【问题描述】:

我正在编写代码战 kata,但遇到了 2 个失败的测试用例。

kata 的描述是: 将整数转换为二进制就这么简单。你会得到一个整数作为参数,你必须返回它的二进制形式。要了解如何将十进制数转换为二进制数,请访问此处。

注意:负数应作为二进制补码处理;假设所有数字都是以任何语言使用 4 个字节(或 32 位)存储的整数。

我的代码:

def to_binary(n)
  temp_array = []
  if n == 0
    temp_array << 0
  elsif n < 0
    n = n % 256
    while n > 0 do
      temp_array << (n % 2)
      n = (n / 2)
    end
    while temp_array.length < 32 do
      temp_array << 1
    end
  else
    while n > 0 do
      temp_array << (n % 2)
      n = (n / 2)
    end
  end
  binary = temp_array.reverse.join
end

测试用例是:

Test Passed: Value == "10"
Test Passed: Value == "11"
Test Passed: Value == "100"
Test Passed: Value == "101"
Test Passed: Value == "111"
Test Passed: Value == "1010"
Test Passed: Value == "11111111111111111111111111111101"
Test Passed: Value == "0"
Test Passed: Value == "1111101000"
Test Passed: Value == "11111111111111111111111111110001"
Expected: "11111111111111111111110000011000", instead got: "11111111111111111111111111111000"
Expected: "11111111111100001011110111000001", instead got: "11111111111111111111111111000001"
Test Passed: Value == "11110100001000111111"

我怀疑失败的测试是负整数,因为第一个失败的测试的预期输出是11111111111111111111110000011000,这意味着正参数值是4294966296,或者是负数。如果我运行to_binary(4294966296),我会得到预期的输出。

【问题讨论】:

  • 我假设你想编写算法,即使 ruby​​ 有一个内置的转换 `10.to_s(2) => "1010"'
  • @500_error 除了(-10).to_s(2) =&gt; "-1010"
  • @lurker 考虑到负二进制值实际上并不存在,这是一个合理的解释。表示这些的常用符号是Two's Notation,但这并不是唯一的方法。
  • @tadman 当然,但我是说它不能解决 OP 寻找 32 位 2 的补码结果的问题。
  • 啊刚看到那部分。通过一些操作来抵消to_s(2) 之前的值,没有什么是您无法解决的。

标签: ruby binary integer


【解决方案1】:

我不喜欢这种方法,因为我确信有一种更聪明和/或更紧凑的 Ruby 风格的方式来完成它。但是使用您将二进制数字加载到数组中然后加入的方法,您可以以更直接的方式完成:

def to_binary(n)
  return "0" if n == 0

  r = []

  32.times do
    if (n & (1 << 31)) != 0
      r << 1
    else
      (r << 0) if r.size > 0
    end
    n <<= 1
  end

  r.join
end

或者,使用@500_error 的建议:

def to_binary(n)
  if n >= 0
    n.to_s(2)
  else
    31.downto(0).map { |b| n[b] }.join
  end
end

不过,处理负数与非负数的不对称有点烦人。你可以这样做:

def to_binary(n)
  31.downto(0).map { |b| n[b] }.join.sub(/^0*/, "")
end

【讨论】:

  • 32.downto(0).map { |n| -4294966296[n] }.join => "100000000000000000000001111101000"
  • @500_error 是的,这很好。唯一剩下的问题是,例如,32.downto(0).map { |n| 2[n] }.join =&gt; "00000000000000000000000000000010" 但 OP 期望“10”。
  • 是的,这很聪明,但不确定它是否适合 OP 的用例。应该有一些位移,以便理解转换。
  • 谢谢@lurker 和@500_error,这需要一个小的改动:ruby def to_binary(n) if n &gt;= 0 n.to_s(2) else 31.downto(0).map { |b| n[b] }.join end end 最初的方法是允许该方法最多返回 33 位而不是 32 位。这种方法也比我所拥有的。我还是 ruby​​ 的新手,我将剖析这种方法以更好地理解它。 :) 谢谢!
【解决方案2】:

这不是生成 2 的补码的传统算法,因此我不确定它是否有助于您理解二进制转换,但您可以在 ruby​​ 中执行此操作以帮助检查您的答案。

注意:这仅适用于负数。

32.downto(0).map { |n| -4294966296[n] }.join
=> "100000000000000000000001111101000"

对于 2 的补码计算,最好使用 C 等较低级别的语言来实现,以了解算法。聪明的方法掩盖了步骤,只是给你一个答案。

假设我们使用 8 位(为简单起见)并假设我们想找出 -28 将如何以二进制补码表示法表示。

  1. 首先我们以二进制形式写出 28。 00011100

  2. 然后我们反转数字。 0变成1,1变成0。 11100011

  3. 然后我们加 1。 11100100

【讨论】:

  • +1 为那个漂亮的表达。 32.downto(0).map { |n| 2[n] }.join =&gt; "00000000000000000000000000000010" 产生 ""00000000000000000000000000000010" 而不是 "10"。也许这个好方法有一个小修改来修复它。
  • @lurker 您可以将其转换为整数以压缩前导零...x = 2; 32.downto(0).map { |n| x[n] }.join.to_i 如果您坚持结果是字符串,只需将其转换回x = 2; 32.downto(0).map { |n| x[n] }.join.to_i.to_s
  • @SteveTurczyn 是的,完全正确。我假设 OP 需要一个字符串输出(因为他们希望输出作为“二进制”表示)。
猜你喜欢
  • 2016-10-31
  • 2012-04-10
  • 1970-01-01
  • 2021-11-03
  • 2012-05-11
  • 2017-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多