How do I convert a very large number into hex?
For example, 647751843213568900000 in hex is 0x231d5cd577654ceab3. I'm able to easily go from hex to double with:
let hex: Double = 0x231d5cd577654ceab3
However I can't work out how to go from Double back to hex. What am I missing?
The following does not work as it overflows when stored as an 'Int':
let hexConverted = String(647751843213568900000, radix: 16)
The basic algorithm (Swift 5) 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))
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.
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.
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))
But unfortunately, the DoubleWidth
is not implemented in Xcode 9 Beta 4 yet.
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 = Array(string)
.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
Note how your value got truncated when converted to Double
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With