Converting a number to different base(s)

Hi. I'm trying to convert numbers between decimal, binary, octal and hex.

I've made a little Playground to explore.

Code is this:

Code Block
let myNumber = "12345"
let myBinary = (UInt8(myNumber, radix: 2) != nil)
print(myBinary)
let myOctal = Int(myNumber, radix: 8)
print(myOctal!)
let myHex = Int(myNumber, radix: 16)
print(myHex!)
let h2 = "27"
let d4 = Int(h2, radix: 2)!
print(d4)






















I seem to be getting garbage responses, including this crash:

Code Block
false
5349
74565
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file __lldb_expr_60/Playground4.playground, line 16
Playground execution failed:
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been left at the point where it was interrupted, use "thread return -x" to return to the state before expression evaluation.


People can play with this code. Please let me know or what to do.


Many thanks

Replies

The line numbers from the error don’t line up with your code, but the problem here is that, on line 22, you can’t convert "27" to a binary number because neither 2 nor 7 are valid binary digits. Thus the Int initialiser returns nil, and that causes the force unwrap to trap.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
As already noted, Int.init(_:radix:) will return nil, when the input String is not a valid number based on radix.

You should better learn how to work with Optionals in some safer ways. Avoid using forced unwrapping (!).

In your case conditional binding seems to be a good way.
Code Block
let myNumber = "12345"
let myBinary = (UInt8(myNumber, radix: 2) != nil)
print(myBinary)
if let myOctal = Int(myNumber, radix: 8) {
print(myOctal) //<- No forced unwrapping
} else {
print("Bad input as octal: \(myNumber)")
}
if let myHex = Int(myNumber, radix: 16) {
print(myHex) //<- No forced unwrapping
} else {
print("Bad input as hexadecimal: \(myNumber)")
}
let h2 = "27"
if let d4 = Int(h2, radix: 2) { //<- No forced unwrapping
print(d4)
} else {
print("Bad input as binary: \(h2)")
}


Outputs:
Code Block
false
5349
74565
Bad input as binary: 27


Thank you both for your responses. I do need to bone up on how to use optionals. Point taken.

One question regarding converting to binary. Would you explain more why I cannot convert "27" . Is there a method to convert integers to binary. Thanks for your help.

And I really like the new forums.xc

why I cannot convert "27"

Because 27 is not a binary.

But it will work with 11 for instance.
I found this to work, but is it the best method?

Code Block
let myNewNumber = 12345
if let myBinary = Int(String(myNewNumber, radix: 2)) {
    print(myBinary)
} else {
    print("Bad input as binary: \(myNumber)")
}

Yes that works, but 12345 is not a binary, so what do you want to propose to user ?
  • ask to input a binary and convert to decimal ?

ask to input decimal and convert to binary ?

What is the expected result if you enter 11 ?
  • 1011

  • 3

Hi again. I'm confused by the following:

Code Block
let myNumber = 12345
if let myHex = Double(String(myNumber, radix: 16)) {
    print(myHex)
} else {
    print("Bad input as hexadecimal: \(myNumber)")
}

That works well. However, if I change myNumber to 1234, I get the Bad Input message.


That works well. However, if I change myNumber to 1234, I get the Bad Input message. 

Because number should be hex:
Code Block
let myNumber = 0x1234

works.

I don't see why it works for more than 5 digits even without 0x prefix.
@davidd 

Would you explain more why I cannot convert "27"

Seems you do not understand what you are doing with your code.

Int(h2, radix: 2) converts String to Int, with interpreting the String as binary.
As already noted by @eskimo, neither "2" nor "7" is a valid binary digit.


I found this to work, but is it the best method?

Depends on what you really want to do.


Hi again. I'm confused by the following

Sorry, but using Double has no meaning here and your code does not explain what you really want to do.


I'm trying to convert numbers between decimal, binary, octal and hex.

If you really want to convert between decimal, binary, octal and hex. You need to specify from and to.
For example:
Code Block
func convertRadix(_ inNumber: String, from inRadix: Int, to outRadix: Int) -> String? {
guard let value = Int(inNumber, radix: inRadix) else {
return nil
}
return String(value, radix: outRadix)
}
var myNumber = "12345"
if let myBinary = convertRadix(myNumber, from: 2, to: 10) { //Convert binary to decimal
print(myBinary)
} else {
print("Bad input as binary: \(myNumber)")
}
if let myOctal = convertRadix(myNumber, from: 8, to: 10) { //Convert octal to decimal
print(myOctal)
} else {
print("Bad input as octal: \(myNumber)")
}
if let myHex = convertRadix(myNumber, from: 16, to: 10) { //Convert hexadecimal to decimal
print(myHex)
} else {
print("Bad input as hexadecimal: \(myNumber)")
}
myNumber = "27"
if let myBinary = convertRadix(myNumber, from: 2, to: 10) { //Convert binary to decimal
print(myBinary)
} else {
print("Bad input as binary: \(myNumber)")
}
if let myBinary = convertRadix(myNumber, from: 10, to: 2) { //Convert decimal to binary
print(myBinary)
} else {
print("Bad input as decimal: \(myNumber)")
}