6

在Ruby中计算一个字节是否具有奇偶校验的最佳方法是什么?我有一个版本工作:

result = "AB".to_i(16).to_s(2).count('1').odd?
=> true

将数字转换为字符串并计算“1”似乎是一种计算奇偶校验的糟糕方法。有更好的方法吗?

我希望能够计算 3DES 密钥的奇偶性。最终,我想将偶数字节转换为奇数字节。

谢谢,丹

4

6 回答 6

7

除非你所拥有的不够快,否则保持它。它清晰简洁,它的性能比你想象的要好。

我们将针对数组查找对所有内容进行基准测试,这是我测试过的最快的方法:

ODD_PARITY = [
  false,
  true,
  true,
  ...
  true,
  false,
]

def odd_parity?(hex_string)
  ODD_PARITY[hex_string.to_i(16)]
end
  • 数组查找以每秒 640,000 字节的速率计算奇偶校验。
  • Bowsersenior 的 C 代码以每秒 640,000 字节的速率计算奇偶校验。
  • 您的代码以每秒 284,000 字节的速率计算奇偶校验。
  • Bowsersenior 的本机代码以每秒 171,000 字节的速率计算奇偶校验。
  • Theo 的缩短代码以每秒 128,000 字节的速率计算奇偶校验。
于 2010-12-19T14:31:08.007 回答
4

看过 RubyDES 库吗?这可能会消除编写您自己的实现的需要。

要计算奇偶校验,您可以使用以下内容:

require 'rubygems'
require 'inline'  # RubyInline (install with `gem install RubyInline`)

class Fixnum
  # native ruby version: simpler but slow
  # algorithm from: 
  #   http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel      
  def parity_native
    (((self * 0x0101010101010101) & 0x8040201008040201) % 0x1FF) & 1
  end

  class << self
    # inline c version using RubyInline to create c extension
    # 4-5 times faster than native version
    # use as class method: 
    #   Fixnum.parity(0xAB)
    inline :C do |builder|
      builder.c <<-EOC
      int parity_c(int num) {  
        return (
            ((num * 0x0101010101010101ULL) & 0x8040201008040201ULL) % 0x1FF
          ) & 1;
      }
      EOC
    end
  end

  def parity
    self.class.parity_c(self)
  end

  def parity_odd?
    1 == parity
  end
  def parity_even?
    0 == parity
  end
end

0xAB.parity        # => 1 
0xAB.parity_odd?   # => true 
0xAB.parity_even?  # => false
(0xAB + 1).parity  # => 0

根据简单的基准测试,内联 c 版本比原生 ruby​​ 版本快 3-4 倍

require 'benchmark'
n = 10000
Benchmark.bm do |x|
  x.report("inline c") do
    n.times do 
      (0..255).map{|num| num.parity}
    end
  end

  x.report("native ruby") do
    n.times do 
      (0..255).map{|num| num.parity_native}
    end
  end
end
# inline c     1.982326s
# native ruby  7.044330s
于 2010-12-19T07:25:41.317 回答
3

具有 255 个条目的 Array 查找表可能是最快的“In Ruby”解决方案。

在 CI 中会屏蔽和转移。或者,如果我有 SSE4,我会将 POPCNT 指令与内联汇编程序一起使用。如果您需要高性能,请在 C 中编写一个本机扩展,它可以执行上述任一操作。

http://en.wikipedia.org/wiki/SSE4

于 2010-12-19T07:00:09.657 回答
2

将您的原始解决方案与 memoization 一起使用怎么样?这只会为每个整数值计算一次。

class Fixnum
  # Using a class variable for simplicity, and because subclasses of
  # Fixnum—while very uncommon—would likely want to share it. 
  @@parity = ::Hash.new{ |h,i| h[i] = i.to_s(2).count('1').odd? }
  def odd_parity?
    @@parity[self]
  end
  def even_parity?
    !@@parity[self]
  end
end

"AB".to_i(16).odd_parity?
#=> true
于 2010-12-19T17:22:38.493 回答
1
x = 'AB'.to_i(16)
p = 0
until x == 0
  p += x & 1
  x = x >> 1
end
puts p # => 5

可以缩短为

x = 'AB'.to_i(16)
p = x & 1
p += x & 1 until (x >>= 1) == 0

如果你想要一些不可读的东西☺</p>

于 2010-12-19T10:19:40.293 回答
1

我将构建一个包含 16 个条目的表(作为 16 个字符的表),对应于一个字节的每个半字节(一半)。条目是 0,1,1,2,1,2,....4

要测试你的字节,

掩盖左半字节并进行查找,记住数字。做。向右移动 4 并进行第二次查找,将结果编号添加到前一个结果编号以提供总和。

然后从总和中测试低位。如果为 1,则字节为奇数,如果为 0,则字节为偶数。如果结果是偶数,则使用 xor 指令翻转高位。这种查找方法比通过单次移位将字节中的位相加要快得多。

发邮件给我一个简单的函数来做 8 个字节的奇偶校验。3DES 使用 3 组 8 字节。

于 2012-08-18T20:01:37.213 回答