Swift 中的无符号右移运算符 '>>>' 是什么?

4

你如何在Swift中实现与Java的无符号右移操作符相当的功能?

根据Java文档,无符号右移操作符">>>"将0移入最左边的位置,而">>"后的最左边位置则取决于符号扩展。

例如,

    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 << 63)的操作会导致Int64溢出并崩溃。因此,我将其写成了Int64.max + negativeNumber - 1,而不是在更大的数据类型中执行((1 << 63) - 1 + negativeNumber)。
然后,使用常规逻辑移位对该正数进行移位,并在符号后的第一个左位上与符号位的位进行OR运算。
    let shifted = (lsb >> bits) | 0x4000000000000000

然而,这并没有给我期望的结果。
    ((Int64.max - 7 + 1) >> 16) | 0x4000000000000000 // = 4611826755915743231

不确定我做错了什么... 还有,能否将此运算符命名为“>>>”并扩展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初始化程序来避免溢出异常。在Swift中,描述这里的函数“next”变成了这样:

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)
}
2个回答

6

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

infix operator >>> : BitwiseShiftPrecedence

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

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

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

如果您想按照自己的方式进行操作,在按位或缺失符号位时,它不能是常量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

如果需要无符号移位操作,使用无符号整数类型似乎更容易。


太完美了!谢谢!你还让我意识到,在截断时为了避免溢出,我可以使用这个初始化方法:Int32(truncatingBitPattern:)。我之所以关注这个问题,是因为我正在按照Java文档中的规定实现Java Random。我会将它添加到描述中。 - endavid

4

Swift有无符号整数类型,因此不需要单独的无符号右移运算符。这是Java中的一种选择,由于决定不使用无符号类型而导致。


确切地说,这解决了Java存在的一个问题。Swift没有等价物,因为它没有同样的问题。 - Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接