【问题标题】:How to compare two 64 bit numbers如何比较两个 64 位数字
【发布时间】:2011-07-24 16:11:22
【问题描述】:

在 PHP 中,我有一个 64 位数字,表示必须完成的任务。第二个 64 位数字代表已完成的任务:

$pack_code = 1001111100100000000000000011111101001111100100000000000000011111
$veri_code = 0000000000000000000000000001110000000000000000000000000000111110

我需要比较两者并提供完成任务的百分比数字。我可以遍历两者并找到设置了多少位,但我不知道这是否是最快的方法?

【问题讨论】:

  • 这些实际上是数字,还是包含 1 和 0 的字符串?
  • 这些实际上是作为 HEX 从数据库中提取的

标签: php


【解决方案1】:
$a = 11111;
echo sprintf('%032b',$a)."\n";
$b = 12345;
echo sprintf('%032b',$b)."\n";

$c = $a & $b;
echo sprintf('%032b',$c)."\n";

$n=0;
while($c)
{
    $n += $c & 1;

    $c = $c >> 1;
}

echo $n."\n";

输出:

00000000000000000010101101100111
00000000000000000011000000111001
00000000000000000010000000100001
3

鉴于您的 PHP-setuo 可以处理 64 位,因此可以轻松扩展。

如果没有,您可以使用 GNU Multiple Precision 避开此限制

您也可以拆分 HEx-Representation,然后对那些对应的部分进行操作。因为您只需要 1 或 0 的本地事实,而不需要实际代表的数字!我认为这将最好地解决您的问题。

例如:

0xF1A35C 和 0xD546C1

你只是比较二进制版本的 F 和 D,1 和 5,A 和 4,...

【讨论】:

    【解决方案2】:

    此代码使用了 PHP 支持的 GNU Multi Precision 库,并且由于它是用 C 实现的,因此应该足够快,并且支持任意精度。

    $pack_code = gmp_init("1001111100100000000000000011111101001111100100000000000000011111", 2);
    $veri_code = gmp_init("0000000000000000000000000001110000000000000000000000000000111110", 2);
    
    $number_of_different_bits = gmp_popcount(gmp_xor($pack_code, $veri_code));
    

    【讨论】:

    • 啊哈,所以就是他们所说的 GMP 中的 count-the-bits 函数。
    【解决方案3】:

    因为你得到的数字是十六进制字符串而不是一和零,你需要做一些额外的工作。

    PHP 不可靠地支持超过 32 位的整数作为整数。 64 位支持需要在 64 位机器上编译和运行。这意味着表示 64 位整数的尝试可能会失败,具体取决于您的环境。因此,确保 PHP 只将这些数字作为 字符串 处理是很重要的。这并不难,因为来自数据库的十六进制字符串将是字符串,而不是整数。

    这里有几个选项。第一个是using the GMP extensiongmp_xor 函数,它对两个数字执行按位异或运算。当两个数字在该位置具有相反的位时,结果数字的位将打开,当两个数字在该位置具有相同的位时,将关闭。然后只需计算位数即可获得剩余任务数。

    另一种选择是将数字作为字符串转换为一串一和零,正如您在问题中所表示的那样。如果您有 GMP,您可以使用gmp_init 将其读取为 base-16 数字,并使用 gmp_strval 将其作为 base-2 数字返回。

    如果您没有有 GMP,this function provided in another answer(滚动到“步骤 2”)可以准确地将字符串作为数字转换为 base-2 到 36 之间的任何内容。它将是比使用 GMP 慢。

    在这两种情况下,您最终都会得到一串 1 和 0,并且可以使用 @Mark Ba​​ker 发布的代码来获得差异。

    【讨论】:

      【解决方案4】:

      假设这些实际上是字符串,可能类似于:

      $pack_code = '1001111100100000000000000011111101001111100100000000000000011111';
      $veri_code = '0000000000000000000000000001110000000000000000000000000000111110';
      
      $matches = array_intersect_assoc(str_split($pack_code),str_split($veri_code));
      $finished_matches = array_intersect($matches,array(1));
      
      $percentage = (count($finished_matches) / 64) * 100
      

      【讨论】:

      • 这很聪明!请注意$finished_matches 如何成为标记为已完成的所有匹配项的索引的散列。这可能很方便。
      • @Charles - 这当然是该方法的副产品,可能对识别已完成的实际任务很有用。
      【解决方案5】:

      这种情况下的优化不值得考虑。我 100% 确定您并不真正关心您的脚本是否会在 0.00000014 秒内生成。更快,对吗? 只需遍历该数字的每一位,将其与另一个进行比较即可完成。

      记住 Donald Knuth 的话:

      我们应该忘记小的效率,比如大约 97% 的时间:过早优化是万恶之源。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        • 2011-01-22
        • 2011-04-25
        相关资源
        最近更新 更多