在Swift中将Double转换为Hex表示法

在Swift中将Double转换为Hex表示法

问题描述:

如何将大量数字转换为十六进制?

How do I convert a very large number into hex?

例如,十六进制的647751843213568900000是0x231d5cd577654ceab3.我可以轻松地从十六进制变为两倍:

For example, 647751843213568900000 in hex is 0x231d5cd577654ceab3. I'm able to easily go from hex to double with:

let hex: Double = 0x231d5cd577654ceab3

但是我不知道如何从Double返回到hex.我想念什么?

However I can't work out how to go from Double back to hex. What am I missing?

以下不起作用,因为当存储为'Int'时它会溢出:

The following does not work as it overflows when stored as an 'Int':

let hexConverted = String(647751843213568900000, radix: 16)

基本算法(Swift 4)如下:

The basic algorithm (Swift 4) is the following:

func representationOf<T: FixedWidthInteger>(_ number: T, base: T) -> String {
    var buffer: [Int] = []
    var n = number

    while n > 0 {
        buffer.append(Int(n % base))
        n /= base
    }

    return buffer
        .reversed()
        .map { String($0, radix: Int(base)) }
        .joined()
}

print(representationOf(647751843213568900, base: 16))

当然,这是String(_:radix:)的工作,因此我们不需要自己实现.

Of course, this is what String(_:radix:) is doing so there is no need for us to implement it by ourselves.

您真正的问题不是编码,而是大整数的表示形式.

Your real problem is not the encoding but the representation of big integers.

已经有多种实现,例如 https://github.com/mkrd /Swift-Big-Integer .其中一些已经具有十六进制编码的功能.

There are multiple implementations out there already, for example https://github.com/mkrd/Swift-Big-Integer. Some of them already have functions for hex encoding.

在Swift 4中,可以声明您自己的更高版本IntXXX的实现(符合FixedWidthInteger),问题将变得更加容易:

In Swift 4 it will be possible to declare your own implementation of higher IntXXX (conforming to FixedWidthInteger) and the problem will become a bit easier:

typealias Int128 = DoubleWidth<Int64>
typealias Int256 = DoubleWidth<Int128>

let longNumber = Int256("231d5cd577654ceab3", radix: 16)!
print(longNumber)
print(String(longNumber, radix: 16))

但是不幸的是,DoubleWidth尚未在Xcode 9 Beta 4中实现.

But unfortunately, the DoubleWidth is not implemented in Xcode 9 Beta 4 yet.

对于某些值,您还可以使用Decimal类型.使用上面写的算法:

For some values your can also use the Decimal type. Using the algorithm written above:

extension Decimal {
    func rounded(mode: NSDecimalNumber.RoundingMode) -> Decimal {
        var this = self
        var result = Decimal()
        NSDecimalRound(&result, &this, 0, mode)

        return result
    }

    func integerDivisionBy(_ operand: Decimal) -> Decimal{
        let result = (self / operand)
        return result.rounded(mode: result < 0 ? .up : .down)
    }

    func truncatingRemainder(dividingBy operand: Decimal) -> Decimal {
        return self - self.integerDivisionBy(operand) * operand
    }
}

extension Decimal {
    init(_ string: String, base: Int) {
        var decimal: Decimal = 0

        let digits = string.characters
            .map { String($0) }
            .map { Int($0, radix: base)! }

        for digit in digits {
            decimal *= Decimal(base)
            decimal += Decimal(digit)
        }

        self.init(string: decimal.description)!
    }
}

func representationOf(_ number: Decimal, base: Decimal) -> String {
    var buffer: [Int] = []
    var n = number

    while n > 0 {
        buffer.append((n.truncatingRemainder(dividingBy: base) as NSDecimalNumber).intValue)
        n = n.integerDivisionBy(base)
    }

    return buffer
        .reversed()
        .map { String($0, radix: (base as NSDecimalNumber).intValue ) }
        .joined()
}

let number = Decimal("231d5cd577654ceab3", base: 16)
print(number) // 647751843213568961203
print(representationOf(number, base: 16)) // 231d5cd577654ceab3

请注意,您的值在转换为Double时是如何被截断的.

Note how your value got truncated when converted to Double.