如何在Swift 2.2中为循环替换复杂的C样式



对于我开发的无符号整数类型库,我有一个专门的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
    }
}

最新更新