Swift和Javascript不同的Bitwise计算结果
Swift and Javascript different Bitwise calculation results
我正在尝试将 Javascript 散列函数移植到 Swift:
在Javascript中:
68207947269 ^ 51
= -511529418
其中与 Swift 5
中的计算相同
68207947269 ^ 51
= 68207947318
它们有何不同?
编辑,添加了 JS 哈希函数
function hash(str) {
var hash = 5381,
i = str.length;
while(i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
/* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
* integers. Since we want the results to be always positive, convert the
* signed int to an unsigned by doing an unsigned bitshift. */
return hash >>> 0;
}
编辑 2,添加电流损坏 Swift:
extension String {
subscript(i: Int) -> String {
return String(self[index(startIndex, offsetBy: i)])
}
}
extension Character {
func unicodeScalarCodePoint() -> UInt32 {
let characterString = String(self)
let scalars = characterString.unicodeScalars
return scalars[scalars.startIndex].value
}
}
func hashString(_ string: String) -> UInt32 {
var hash: Int32 = 5381
var i = string.count - 1
while(i >= 0) {
let char = Int32(Character(string[i]).unicodeScalarCodePoint())
// Crash here with error: `Swift runtime failure: arithmetic overflow`
let hashMultiply = Int32(truncating: NSNumber(value: hash * 33))
hash = hashMultiply ^ char
i -= 1
}
return UInt32(bitPattern: hash)
}
hashString("0x8f1083db77b5F556E46Ac46A29DE86e01031Bb14")
注意 in JavaScript:
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Swift 中的整数文字默认为 Int
类型,这是您的体系结构的字宽。如果您在任何最新的 Apple 设备上尝试过此操作,它将是 64 位的。
因此,要模仿 JavaScript 行为,您需要转换为 Int32:
Int32(truncatingIfNeeded: 68207947269) ^ Int32(51)
这给出了想要的结果 -511529418
。
请注意,您的 JavaScript 代码丢弃了整数 68207947269 的位,因为它不能表示为 32 位整数。
根据here,JavaScript中的位运算符使用32位操作数。 68207947269太大,无法用32位表示,先自动截断,再进行按位运算
Swift 整数字面值默认为 Int
类型,Int
的大小取决于平台。它很可能是 64 位的,这就是产生不同结果的原因。
要生成与 JavaScript 代码相同的结果,首先通过截断将其转换为 Int32
:
Int32(truncatingIfNeeded: 68207947269) ^ 51
请注意,结果是 Int32
。稍后您可能需要进行更多类型转换。
关于您的 Swift 翻译,我发现有两个主要问题。
首先,hash * 33
会溢出导致崩溃。 JavaScript 版本不需要担心这一点,因为结果会简单地在 JavaScript 中“回绕”。幸运的是,如果 Swift 中的结果溢出(而不是崩溃),还有一个 operator 也会“回绕”。所以你可以这样做:
hash &* 33
其次,您处理字符串的方式与 JavaScript 版本不同。在 JavaScript、charCodeAt
returns 中是一个 UTF-16 代码单元,但是您的 Swift 代码获取的是 unicode 标量。
要获得相同的行为,您应该这样做:
extension String.UTF16View {
subscript(i: Int) -> Element {
return self[index(startIndex, offsetBy: i)]
}
}
...
Int32(string.utf16[i])
我正在尝试将 Javascript 散列函数移植到 Swift:
在Javascript中:
68207947269 ^ 51
= -511529418
其中与 Swift 5
中的计算相同68207947269 ^ 51
= 68207947318
它们有何不同?
编辑,添加了 JS 哈希函数
function hash(str) {
var hash = 5381,
i = str.length;
while(i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
/* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
* integers. Since we want the results to be always positive, convert the
* signed int to an unsigned by doing an unsigned bitshift. */
return hash >>> 0;
}
编辑 2,添加电流损坏 Swift:
extension String {
subscript(i: Int) -> String {
return String(self[index(startIndex, offsetBy: i)])
}
}
extension Character {
func unicodeScalarCodePoint() -> UInt32 {
let characterString = String(self)
let scalars = characterString.unicodeScalars
return scalars[scalars.startIndex].value
}
}
func hashString(_ string: String) -> UInt32 {
var hash: Int32 = 5381
var i = string.count - 1
while(i >= 0) {
let char = Int32(Character(string[i]).unicodeScalarCodePoint())
// Crash here with error: `Swift runtime failure: arithmetic overflow`
let hashMultiply = Int32(truncating: NSNumber(value: hash * 33))
hash = hashMultiply ^ char
i -= 1
}
return UInt32(bitPattern: hash)
}
hashString("0x8f1083db77b5F556E46Ac46A29DE86e01031Bb14")
注意 in JavaScript:
The operands are converted to 32-bit integers and expressed by a series of bits (zeroes and ones). Numbers with more than 32 bits get their most significant bits discarded.
Swift 中的整数文字默认为 Int
类型,这是您的体系结构的字宽。如果您在任何最新的 Apple 设备上尝试过此操作,它将是 64 位的。
因此,要模仿 JavaScript 行为,您需要转换为 Int32:
Int32(truncatingIfNeeded: 68207947269) ^ Int32(51)
这给出了想要的结果 -511529418
。
请注意,您的 JavaScript 代码丢弃了整数 68207947269 的位,因为它不能表示为 32 位整数。
根据here,JavaScript中的位运算符使用32位操作数。 68207947269太大,无法用32位表示,先自动截断,再进行按位运算
Swift 整数字面值默认为 Int
类型,Int
的大小取决于平台。它很可能是 64 位的,这就是产生不同结果的原因。
要生成与 JavaScript 代码相同的结果,首先通过截断将其转换为 Int32
:
Int32(truncatingIfNeeded: 68207947269) ^ 51
请注意,结果是 Int32
。稍后您可能需要进行更多类型转换。
关于您的 Swift 翻译,我发现有两个主要问题。
首先,hash * 33
会溢出导致崩溃。 JavaScript 版本不需要担心这一点,因为结果会简单地在 JavaScript 中“回绕”。幸运的是,如果 Swift 中的结果溢出(而不是崩溃),还有一个 operator 也会“回绕”。所以你可以这样做:
hash &* 33
其次,您处理字符串的方式与 JavaScript 版本不同。在 JavaScript、charCodeAt
returns 中是一个 UTF-16 代码单元,但是您的 Swift 代码获取的是 unicode 标量。
要获得相同的行为,您应该这样做:
extension String.UTF16View {
subscript(i: Int) -> Element {
return self[index(startIndex, offsetBy: i)]
}
}
...
Int32(string.utf16[i])