无符号右移运营商'>>>'在斯威夫特

时间:2016-12-17 19:12:45

标签: swift bit-manipulation

你如何在Swift中实现Java的无符号右移运算符?

根据Java's documentation,无符号右移运算符">>>"将零移动到最左边的位置,而在">>"之后的最左边的位置取决于符号扩展。

所以,例如,

    long s1 = (-7L >>> 16); // result is 281474976710655L
    long s2 = (-7L >> 16); // result is -1

为了在Swift中实现这一点,我会通过执行类似的操作来获取除符号位之外的所有位:

    let lsb = Int64.max + negativeNumber + 1

请注意,该数字必须为负数!如果你溢出移位操作符,应用程序会崩溃EXC_BAD_INSTRUCTION,这不是很好...... 另外,我故意使用Int64。因为没有更大的数据类型,所以执行类似(1&lt;&lt; 63)的操作会溢出Int64并且也会崩溃。因此,不是在更大的数据类型中执行((1 <&lt;&lt;&lt; 63) - 1 + negativeNumber),而是将其写为Int64.max + negativeNumber - 1.

然后,用正常的逻辑移位移动该正数,并在符号后的第一个左位的符号中移位该位。

    let shifted = (lsb >> bits) | 0x4000000000000000

然而,这并没有给我预期的结果,

    ((Int64.max - 7 + 1) >> 16) | 0x4000000000000000 // = 4611826755915743231

不确定我做错了什么...... 此外,是否可以将此运营商命名为&#39;&gt;&gt;&gt;&#39;并扩展Int64?

编辑: 在这里添加来自OOper的解决方案,

infix operator >>> : BitwiseShiftPrecedence

func >>> (lhs: Int64, rhs: Int64) -> Int64 {
  return Int64(bitPattern: UInt64(bitPattern: lhs) >> UInt64(rhs))
}

我在Swift中实现了Java Random类,它还涉及将64位整数截断为32位。感谢OOper我刚才意识到我可以使用truncatingBitPattern初始化程序来避免溢出异常。功能&#39; next&#39;正如所描述的here在Swift中成为了这个,

var seed: Int64 = 0
private func next(_ bits: Int32) -> Int32 {
    seed = (seed &* 0x5DEECE66D &+ 0xB) & ((1 << 48) - 1)
    let shifted : Int64 = seed >>> (48 - Int64(bits))
    return Int32(truncatingBitPattern: shifted)
}

3 个答案:

答案 0 :(得分:6)

一种可靠的方法是使用无符号整数类型的无符号移位操作:

infix operator >>> : BitwiseShiftPrecedence

func >>> (lhs: Int64, rhs: Int64) -> Int64 {
    return Int64(bitPattern: UInt64(bitPattern: lhs) >> UInt64(rhs))
}

print(-7 >>> 16) //->281474976710655

(使用-7进行位计数16测试似乎不是一个好例子,它会丢失16位右移的所有有效位。)

如果您想以自己的方式执行此操作,则按位ORed缺失符号位不能是常量0x4000000000000000。当位计数== 0时,它需要为0x8000_0000_0000_0000(此常量在Swift Int64中溢出),并且需要使用相同的位进行逻辑移位。

所以,你需要写这样的东西:

infix operator >>>> : BitwiseShiftPrecedence

func >>>> (lhs: Int64, rhs: Int64) -> Int64 {
    if lhs >= 0 {
        return lhs >> rhs
    } else {
        return (Int64.max + lhs + 1) >> rhs | (1 << (63-rhs))
    }
}

print(-7 >>>> 16) //->281474976710655

当您需要无符号移位操作时,使用无符号整数类型似乎要容易得多。

答案 1 :(得分:2)

Swift有无符号整数类型,因此不需要单独的无符号右移运算符。在决定不使用无符号类型之后,这是Java的一个选择。

答案 2 :(得分:0)

这个表达式对我有用:

((Int64.max - 7L + 1) >> 15)

无掩码,减少1位。

免责声明:无法在Swift中查看此内容。