Before we start it definitely needs to be noted that Swift has binary literals:
(Note: a similar approach to my string handling function, but one using pattern matching can be found here.)
0b11011111 // 223And also that you can convert a binary String to a decimal using the C standard library:
strtoul("11011111", nil, 2) // 223
Bool array as a binary representation
But why should this stop the fun. So first let's begin with a Bool Array, which I've typealiased to Bit for clarity. I begin with Bool because it prevents anything but 0 and 1 (or rather true and false) being used.typealias Bit = Bool let B1 = true let B0 = false func binaryToDecimal(binary:[Bit]) -> Int { var bitValue = 1, total = 0 for b in binary.reverse() { if b == true { total += bitValue } bitValue *= 2 } return total } binaryToDecimal([B1,B1,B0,B1,B1,B1,B1,B1]) // 223
Swift 3, Xcode 8
typealias Bit = Bool let B1 = true let B0 = false func binaryToDecimal(binary:[Bit]) -> Int { var bitValue = 1, total = 0 for b in binary.reversed() { if b == true { total += bitValue } bitValue *= 2 } return total } binaryToDecimal(binary: [B1,B1,B0,B1,B1,B1,B1,B1]) // 223An enum could substitute the alias but this looks nicer when implemented.
Binary string
If we had a binary string instead then we'd probably end with something like this:enum BinaryStringError:ErrorType { case InvalidCharacter } func binaryToDecimal(str:String) throws -> Int { var bitValue = 1, total = 0 for b in str.characters.reverse() { if b == "1" { total += bitValue } else if b != "0" { throw BinaryStringError.InvalidCharacter } bitValue *= 2 } return total } do { try binaryToDecimal("11011111") // 223 } catch BinaryStringError.InvalidCharacter { print("not a valid binary string") }
Swift 3, Xcode 8
enum BinaryStringError:Error { case InvalidCharacter } func binaryToDecimal(str:String) throws -> Int { var bitValue = 1, total = 0 for b in str.characters.reversed() { if b == "1" { total += bitValue } else if b != "0" { throw BinaryStringError.InvalidCharacter } bitValue *= 2 } return total } do { try binaryToDecimal(str: "11011111") // 223 } catch BinaryStringError.InvalidCharacter { print("not a valid binary string") }Now we are having to handle errors, or alternatively we'd need some quiet fail.
(Note: a similar approach to my string handling function, but one using pattern matching can be found here.)
A note on C
It's worth noting here that strtoul() treats any character other than 1 as zero. This isn't necessarily what you'd expect if you're used to working with Bool() where any number higher than 0 will return true. So you need to account for this, most likely searching the string for values other than 1 or 0 beforehand. Something like this:if let _ = str.rangeOfString("[^0^1]", options: .RegularExpressionSearch) { throw BinaryStringError.InvalidCharacter }which can either throw (as shown here) or return nil depending on the demands of the app.
Swift 3, Xcode 8
enum BinaryStringError:ErrorType { case InvalidCharacter } func binaryToDecimal(str:String)throws -> UInt { if let _ = str.range(of: "[^0^1]", options: .regularExpression) { throw BinaryStringError.InvalidCharacter } else { return strtoul("11011111", nil, 2) // 223 } } do { try binaryToDecimal(str: str) }
Comments
Post a Comment