对于我开发的无符号整数类型库,我有一个专门的C样式循环,用于计算存储数值中的有效位。一段时间以来,我一直在纠结如何将其转换为Swift 2.2+风格的循环。这是有问题的代码:
/// Counts up the significant bits in stored data.
public var significantBits: UInt128 {
// Will turn into final result.
var significantBitCount: UInt128 = 0
// The bits to crawl in loop.
var bitsToWalk: UInt64 = 0
if self.value.upperBits > 0 {
bitsToWalk = self.value.upperBits
// When upperBits > 0, lowerBits are all significant.
significantBitCount += 64
} else if self.value.lowerBits > 0 {
bitsToWalk = self.value.lowerBits
}
if bitsToWalk > 0 {
// Walk significant bits by shifting right until all bits are equal to 0.
for var bitsLeft = bitsToWalk; bitsLeft > 0; bitsLeft >>= 1 {
significantBitCount += 1
}
}
return significantBitCount
}
我相信有多种方法可以处理这一问题,我可以想出一些更详细的方法来处理这一情况,但我感兴趣的是找到一种简洁的方式来处理这种情况,我可以重新应用于类似的情况。我发现我很少在循环中使用C风格,但当我这样做时,它适用于像这样的奇怪场景,这是处理问题的最简洁的方法。
最简单的解决方案是只使用while
循环:
替换此代码:
if bitsToWalk > 0 { // Walk significant bits by shifting right until all bits are equal to 0. for var bitsLeft = bitsToWalk; bitsLeft > 0; bitsLeft >>= 1 { significantBitCount += 1 } }
使用以下while
循环:
while bitsToWalk > 0 {
significantBitCount += 1
bitsToWalk >>= 1
}
一个选项是使用内置的处理器功能:
看跌:
#import <x86intrin.h>
到您的Obj-C桥接头,然后在Swift中:
let number: UInt64 = 111
let mostSignificantBit = _lzcnt_u64(number)
print(mostSignificantBit)
(当然,您必须使用正确的体系结构,此函数仅在x86上定义。这种解决方案的可移植性并不完全好)。
此函数应计算UInt64
值中的有效位数:
import Foundation
func significantBits(n: UInt64) -> Int {
return Int(ceil(log2(Double(n))))
}
let n: UInt64 = 0xFFFFFFFFFFFFFFFF // 64 significant bits
let m: UInt64 = 0b11011 // 5 significant bits
print("n has (significantBits(n)) significant bits.")
print("m has (significantBits(m)) significant bits.")
和输出:
n has 64 significant bits.
m has 5 significant bits.
你可能会用类似的东西来替换你的代码:
private func calcSigBits(n: UInt64) -> Int {
return Int(ceil(log2(Double(n))))
}
public var significantBits: Int {
if self.value.upperBits > 0 {
return calcSigBits(self.value.upperBits) + 64
}
else {
return calcSigBits(self.value.lowerBits)
}
}
如果你不想使用log2
,你可以使用nhgrif答案中的循环,但重构它仍然很好,因为它是一个概念上独立的操作,并且使你自己的代码更简单。您甚至可以将其添加为UInt64
:的扩展
extension UInt64 {
public var significantBits: Int {
var sb = 0
var value = self
while value > 0 {
sb += 1
value >>= 1
}
return sb
}
}
// Rest of your class definition...
public var significantBits: Int {
if self.value.upperBits > 0 {
return self.value.upperBits.significantBits + 64
}
else {
return self.value.lowerBits.significantBits
}
}