【问题标题】:Same function in javascript and php, but different outputsjavascript 和 php 中的相同功能,但输出不同
【发布时间】:2013-07-16 13:12:03
【问题描述】:

我在 javascript 中有这个功能 - 工作正常

// javascript
    function myhash(str) {
      var hash = 0;
      if (str.length == 0) return hash;
      for (var i = 0; i < str.length; i++) {
        oneChar = str.charCodeAt(i);
        hash = ((hash << 5) - hash) + oneChar;
        hash &= hash;
      }
      return hash;
    }

我正在尝试将此函数重写为 PHP,但是对于相同的输入,输出与来自 JS 的输出不同。

// php
      function myhash($str) {
        $hash = 0;
        if (strlen($str) == 0) return $hash;
        for ($i = 0; $i < strlen($str); $i++) {
          $oneChar = ord($str[$i]);
          $hash = (($hash << 5) - $hash) + $oneChar;
          $hash &= $hash;
        }
        return $hash;
      }

输入和输出示例:

console.log(myhash("example")); // output: -1322970774
echo myhash("example"); // output: 93166309738

有谁知道,问题可能出在哪里?它们看起来一样,但显然不是。

【问题讨论】:

  • 你能举个例子吗?可能有助于确定问题
  • @Ian 不过,很高兴知道有什么不同。如果我遇到这种情况,我会开始在整个代码中添加echos 之类的东西,看看差异首先出现在哪里
  • 别忘了把例子改成使用myhash
  • 有 2 个很好的工具可以显示您的问题 - phpfiddle.org 和 jsfiddle.net 可以让我们进行测试和帮助调试
  • 在 JavaScript 中,在使用字符串“example”的第 6 次迭代中,$hash &lt;&lt; 5 的结果是一个负数(96947249 &lt;&lt; 5 -> -1192655328)。我不确定为什么。在 PHP 中,它是 3102311968

标签: php javascript hash


【解决方案1】:

hash() 是我用 hash1 测试的 php 的保留函数,两者都提供相同的结果

使用测试:

PHP 结果:3556498

Javascript:3556498

【讨论】:

  • 这两个函数的实名都不同于“hash”,我写“hash”就是为了这个。我的错,对不起。
【解决方案2】:

在 JavaScript 中,在使用字符串“example”的第 6 次迭代中,$hash &lt;&lt; 5 的结果是一个负数(96947249 &lt;&lt; 5 -> -1192655328)。在 PHP 中,它是 3102311968。

问题在于,在 JavaScript 中,&lt;&lt; 运算符会导致操作数在内部转换为有符号的 32 位整数。带符号的 32 位整数的最大值为 2147483647。循环中该点的操作超过了该阈值,导致溢出。

在 PHP 中,最大值在 32 位系统中似乎相同 (2147483647),但在 64 位系统中要大得多。 http://php.net/manual/en/language.types.integer.php(接近底部)

演示: http://phpfiddle.org/main/code/mga-i8b 和 http://jsfiddle.net/YJRA4/

关于按位运算符和整数的大量信息(希望能更好地解释我的意思):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators

【讨论】:

  • 这不是JS中整数的最大值。它是使用按位运算符处理的数字的最大值。如果您坚持使用普通的数学运算符,您可以使用 96947249 * 32 并获得“正确”的值。
  • @Alnitak MDN 文档说The operands of all bitwise operators are converted to signed 32-bit integers。然后继续说The numbers -2147483648 and 2147483647 are the minimum and the maximum integers representable throught a 32bit signed number. 您指的是具有该操作的Number,这是不同的。但是您的观点是正确的;我会更新我的答案
  • 有点 - Number 仍然可以准确地表示高达 2^52 的任何整数。位运算符去除前 32 位之外的所有位,但结果值 仍然是 Number。
  • @Alnitak 我明白你的意思,我想我只是在拐弯抹角——关键是操作数被转换为有符号的 32 位整数。否则,Number 操作最多可以占到Number.MAX_VALUE。顺便说一句,有一个很好的答案:)
【解决方案3】:

Javascript 中的 &lt;&lt; 运算符将数字参数转换为 32 位有符号整数,而不是 IEEE 754 双精度数。

要修复您的 PHP 代码,您将(至少)需要先屏蔽 &lt;&lt; 操作的结果,然后再对它进行任何其他操作。

下面的代码产生与在(64 位)MacOS X 10.8.4 上使用 PHP 5.3.15 输入“示例”的 JS 代码相同的结果。它可能不适用于其他测试用例或 32 位版本的 PHP:

function myhash($str) {
  $hash = 0;
  if (strlen($str) == 0) return $hash;
  for ($i = 0; $i < strlen($str); $i++) {
    $oneChar = ord($str[$i]);
    $tmp = ($hash << 5) & 0xffffffff;
    $hash = ($tmp - $hash) + $oneChar;
  }
  return $hash;
}

注意:$hash &amp;= $hash 行是空操作。与自身“与”的数字将产生相同的数字。

【讨论】:

  • 确认,它甚至适用于我测试的其他输入......非常感谢大家。
  • 我觉得它应该在 32 位版本的 PHP 上工作,因为你将它“限制”为 32 位......不是吗?对不起,如果我误解了你的代码
  • @Sylar 我发现 some 不一致,因为我的 &amp; 运算符未正确设置符号位。如果您将&amp; 0x7fffffff 添加到最终的return(在两个版本中)以确保结果是无符号的,效果会更好。
  • 所以返回部分应该是“return ($hash & 0x7fffffff)”?但是这个“$tmp = ($hash
  • @Sylar 是的,没错。当然,这也会改变你现有的 JS 哈希码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多