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]) // 223
An 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