在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
.