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

时间:2017-07-12 12:13:26

标签: swift hex

如何将非常大的数字转换为十六进制?

例如,164751843213568900000(十六进制)为0x231d5cd577654ceab3。我可以轻松地从十六进制变为双精度:

let hex: Double = 0x231d5cd577654ceab3

但是我无法弄清楚如何从双回到十六进制。我错过了什么?

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

let hexConverted = String(647751843213568900000, radix: 16)

2 个答案:

答案 0 :(得分:4)

基本算法(Swift 4)如下:

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:)正在做的事情,所以我们不需要自己实施。

你真正的问题不是编码,而是大整数的表示。

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

在Swift 4中,可以声明自己的更高IntXXX的实现(符合FixedWidthInteger),问题会变得容易一些:

<击>
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中实现。

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

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后,您的值是如何被截断的。

答案 1 :(得分:1)

这是我的解决方案:

func toHex(number : Double) -> String
{
    var n = number;
    var reminders : [Double] = [];
    while true
    {
        let reminder = n % 16;
        n = floor(n/16.0);

        reminders.append(reminder);

        if(n == 0.0)
        {
            break;
        }
    }


    var hex = "";        
    var i = reminders.count-1;
    while(i > -1)
    {
        hex = hex + hexChar(reminders[i]);
        i = i-1;
    }

    return hex;
}


func hexChar(n : Double) -> String
{
    switch n
    {
    case 15: return "F";
    case 14: return "E";
    case 13: return "D";
    case 12: return "C";
    case 11: return "B";
    case 10: return "A";
    default: return String(Int(n))
    }
}
toHex(647751843213568900000.0); //231D5CD577654C0000