Numbers as Strings Multiplication Function in Swift

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
I was solving a problem 20, Factorial Digit Sum, on Project Euler.
Factorial Digits Sum
$n!$ means $n cdot (n â 1) cdot ldots cdot 3 cdot 2 cdot 1$
For example, $10! = 10 cdot 9 cdot ldots cdot 3 cdot 2 cdot 1 = 3628800$,
and the sum of the digits in the number $10!$ is $3 + 6 + 2 + 8 + 8 + 0 + 0 = 27$.
Find the sum of the digits in the number $100!$.
While doing this problem, I was working with really big numbers ($100!$ or $9.33 cdot 10^157$). So at first, I decided to try to use Float80 and format it properly.
Since I have no I idea and could not find anything to properly explain to me how to do this with Float80 and String(format:_:) or NumberFormatter, I decided to make a function takes in two String parameters and returns their values multiplied as a String. With my multiplyLong (_:_:) function, I can multiply two numbers of any size. I wrote this function using concepts and principals from long multiplication from elementary school.
I wanted to find out if there is a better way to make a function that can multiply numbers of any size. Also, although my multiplyLong(_:_:) function works perfectly, it is quite long and I would like dramatically refine it, shorten it, and make it more efficient.
Note: I am using Swift 4.1 and Xcode 9.4
My multiplyLong(_:_:) Function
func multiplyLong(_ x: String, _ y: String) -> String
precondition(!x.isEmpty && !y.isEmpty, "Error, valid numbers are required for multiplication")
var prefix = ""
var containsInvalidCharacters : Bool
switch (x, y)
case let (s1, s2) where s1.first! == "-" && s2.first! == "-":
return !((s1.dropFirst() + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s2.first! == "-":
prefix = "-"
return !((s1 + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s1.first! == "-":
prefix = "-"
return !((s1.dropFirst() + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2):
return !((s1 + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
precondition(containsInvalidCharacters, "Error, multiplicand contains invalid non-numeric characters")
let s1 = x.replacingOccurrences(of: "-", with: "").map Int(String($0))!
let s2 = y.replacingOccurrences(of: "-", with: "").map Int(String($0))!
var a = [Int]()
var b = [Int]()
switch (s1, s2)
case let (arr1, arr2) where arr1.count > arr2.count
var lines = [[Int]]()
for (bi, bn) in b.enumerated()
var line = Array(repeating: 0, count: bi)
var carriedNumber = 0
for an in a
let v = (bn * an) + carriedNumber
carriedNumber = (v - (v % 10)) / 10
line.insert(v % 10, at: 0)
if carriedNumber != 0
if carriedNumber >= 10
line.insert(carriedNumber % 10, at: 0)
line.insert((carriedNumber - (carriedNumber % 10)) / 10, at: 0)
else
line.insert(carriedNumber, at: 0)
lines.append(line)
let maxIndex = lines.max $0.count < $1.count !.count
var result = [Int]()
var addNum = 0
for i in 0...maxIndex
var v = addNum
for line in lines
v += line.indices.contains(i) ? line.reversed()[i] : 0
if v >= 10
addNum = Int("("(v)".dropLast())")!
result.insert(Int("("(v)".last!)")!, at: 0)
else
addNum = 0
result.insert(v, at: 0)
if addNum != 0
for i in "(addNum)".reversed()
result.insert(Int("(i)")!, at: 0)
result = Array(result.drop $0 == 0 )
let str = result.reduce("") $0 + "($1)"
return prefix + str
My Solution
func factorialDigitSum() -> Int
let f = Array(1...100).map String($0) .reduce("1",multiplyLong)
return f.map Int("($0)") ?? 0 .reduce(0, +)
print(factorialDigitSum()) //Prints "648"
Note: 648 is indeed the right answer.
performance programming-challenge functional-programming swift formatting
add a comment |Â
up vote
1
down vote
favorite
I was solving a problem 20, Factorial Digit Sum, on Project Euler.
Factorial Digits Sum
$n!$ means $n cdot (n â 1) cdot ldots cdot 3 cdot 2 cdot 1$
For example, $10! = 10 cdot 9 cdot ldots cdot 3 cdot 2 cdot 1 = 3628800$,
and the sum of the digits in the number $10!$ is $3 + 6 + 2 + 8 + 8 + 0 + 0 = 27$.
Find the sum of the digits in the number $100!$.
While doing this problem, I was working with really big numbers ($100!$ or $9.33 cdot 10^157$). So at first, I decided to try to use Float80 and format it properly.
Since I have no I idea and could not find anything to properly explain to me how to do this with Float80 and String(format:_:) or NumberFormatter, I decided to make a function takes in two String parameters and returns their values multiplied as a String. With my multiplyLong (_:_:) function, I can multiply two numbers of any size. I wrote this function using concepts and principals from long multiplication from elementary school.
I wanted to find out if there is a better way to make a function that can multiply numbers of any size. Also, although my multiplyLong(_:_:) function works perfectly, it is quite long and I would like dramatically refine it, shorten it, and make it more efficient.
Note: I am using Swift 4.1 and Xcode 9.4
My multiplyLong(_:_:) Function
func multiplyLong(_ x: String, _ y: String) -> String
precondition(!x.isEmpty && !y.isEmpty, "Error, valid numbers are required for multiplication")
var prefix = ""
var containsInvalidCharacters : Bool
switch (x, y)
case let (s1, s2) where s1.first! == "-" && s2.first! == "-":
return !((s1.dropFirst() + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s2.first! == "-":
prefix = "-"
return !((s1 + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s1.first! == "-":
prefix = "-"
return !((s1.dropFirst() + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2):
return !((s1 + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
precondition(containsInvalidCharacters, "Error, multiplicand contains invalid non-numeric characters")
let s1 = x.replacingOccurrences(of: "-", with: "").map Int(String($0))!
let s2 = y.replacingOccurrences(of: "-", with: "").map Int(String($0))!
var a = [Int]()
var b = [Int]()
switch (s1, s2)
case let (arr1, arr2) where arr1.count > arr2.count
var lines = [[Int]]()
for (bi, bn) in b.enumerated()
var line = Array(repeating: 0, count: bi)
var carriedNumber = 0
for an in a
let v = (bn * an) + carriedNumber
carriedNumber = (v - (v % 10)) / 10
line.insert(v % 10, at: 0)
if carriedNumber != 0
if carriedNumber >= 10
line.insert(carriedNumber % 10, at: 0)
line.insert((carriedNumber - (carriedNumber % 10)) / 10, at: 0)
else
line.insert(carriedNumber, at: 0)
lines.append(line)
let maxIndex = lines.max $0.count < $1.count !.count
var result = [Int]()
var addNum = 0
for i in 0...maxIndex
var v = addNum
for line in lines
v += line.indices.contains(i) ? line.reversed()[i] : 0
if v >= 10
addNum = Int("("(v)".dropLast())")!
result.insert(Int("("(v)".last!)")!, at: 0)
else
addNum = 0
result.insert(v, at: 0)
if addNum != 0
for i in "(addNum)".reversed()
result.insert(Int("(i)")!, at: 0)
result = Array(result.drop $0 == 0 )
let str = result.reduce("") $0 + "($1)"
return prefix + str
My Solution
func factorialDigitSum() -> Int
let f = Array(1...100).map String($0) .reduce("1",multiplyLong)
return f.map Int("($0)") ?? 0 .reduce(0, +)
print(factorialDigitSum()) //Prints "648"
Note: 648 is indeed the right answer.
performance programming-challenge functional-programming swift formatting
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I was solving a problem 20, Factorial Digit Sum, on Project Euler.
Factorial Digits Sum
$n!$ means $n cdot (n â 1) cdot ldots cdot 3 cdot 2 cdot 1$
For example, $10! = 10 cdot 9 cdot ldots cdot 3 cdot 2 cdot 1 = 3628800$,
and the sum of the digits in the number $10!$ is $3 + 6 + 2 + 8 + 8 + 0 + 0 = 27$.
Find the sum of the digits in the number $100!$.
While doing this problem, I was working with really big numbers ($100!$ or $9.33 cdot 10^157$). So at first, I decided to try to use Float80 and format it properly.
Since I have no I idea and could not find anything to properly explain to me how to do this with Float80 and String(format:_:) or NumberFormatter, I decided to make a function takes in two String parameters and returns their values multiplied as a String. With my multiplyLong (_:_:) function, I can multiply two numbers of any size. I wrote this function using concepts and principals from long multiplication from elementary school.
I wanted to find out if there is a better way to make a function that can multiply numbers of any size. Also, although my multiplyLong(_:_:) function works perfectly, it is quite long and I would like dramatically refine it, shorten it, and make it more efficient.
Note: I am using Swift 4.1 and Xcode 9.4
My multiplyLong(_:_:) Function
func multiplyLong(_ x: String, _ y: String) -> String
precondition(!x.isEmpty && !y.isEmpty, "Error, valid numbers are required for multiplication")
var prefix = ""
var containsInvalidCharacters : Bool
switch (x, y)
case let (s1, s2) where s1.first! == "-" && s2.first! == "-":
return !((s1.dropFirst() + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s2.first! == "-":
prefix = "-"
return !((s1 + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s1.first! == "-":
prefix = "-"
return !((s1.dropFirst() + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2):
return !((s1 + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
precondition(containsInvalidCharacters, "Error, multiplicand contains invalid non-numeric characters")
let s1 = x.replacingOccurrences(of: "-", with: "").map Int(String($0))!
let s2 = y.replacingOccurrences(of: "-", with: "").map Int(String($0))!
var a = [Int]()
var b = [Int]()
switch (s1, s2)
case let (arr1, arr2) where arr1.count > arr2.count
var lines = [[Int]]()
for (bi, bn) in b.enumerated()
var line = Array(repeating: 0, count: bi)
var carriedNumber = 0
for an in a
let v = (bn * an) + carriedNumber
carriedNumber = (v - (v % 10)) / 10
line.insert(v % 10, at: 0)
if carriedNumber != 0
if carriedNumber >= 10
line.insert(carriedNumber % 10, at: 0)
line.insert((carriedNumber - (carriedNumber % 10)) / 10, at: 0)
else
line.insert(carriedNumber, at: 0)
lines.append(line)
let maxIndex = lines.max $0.count < $1.count !.count
var result = [Int]()
var addNum = 0
for i in 0...maxIndex
var v = addNum
for line in lines
v += line.indices.contains(i) ? line.reversed()[i] : 0
if v >= 10
addNum = Int("("(v)".dropLast())")!
result.insert(Int("("(v)".last!)")!, at: 0)
else
addNum = 0
result.insert(v, at: 0)
if addNum != 0
for i in "(addNum)".reversed()
result.insert(Int("(i)")!, at: 0)
result = Array(result.drop $0 == 0 )
let str = result.reduce("") $0 + "($1)"
return prefix + str
My Solution
func factorialDigitSum() -> Int
let f = Array(1...100).map String($0) .reduce("1",multiplyLong)
return f.map Int("($0)") ?? 0 .reduce(0, +)
print(factorialDigitSum()) //Prints "648"
Note: 648 is indeed the right answer.
performance programming-challenge functional-programming swift formatting
I was solving a problem 20, Factorial Digit Sum, on Project Euler.
Factorial Digits Sum
$n!$ means $n cdot (n â 1) cdot ldots cdot 3 cdot 2 cdot 1$
For example, $10! = 10 cdot 9 cdot ldots cdot 3 cdot 2 cdot 1 = 3628800$,
and the sum of the digits in the number $10!$ is $3 + 6 + 2 + 8 + 8 + 0 + 0 = 27$.
Find the sum of the digits in the number $100!$.
While doing this problem, I was working with really big numbers ($100!$ or $9.33 cdot 10^157$). So at first, I decided to try to use Float80 and format it properly.
Since I have no I idea and could not find anything to properly explain to me how to do this with Float80 and String(format:_:) or NumberFormatter, I decided to make a function takes in two String parameters and returns their values multiplied as a String. With my multiplyLong (_:_:) function, I can multiply two numbers of any size. I wrote this function using concepts and principals from long multiplication from elementary school.
I wanted to find out if there is a better way to make a function that can multiply numbers of any size. Also, although my multiplyLong(_:_:) function works perfectly, it is quite long and I would like dramatically refine it, shorten it, and make it more efficient.
Note: I am using Swift 4.1 and Xcode 9.4
My multiplyLong(_:_:) Function
func multiplyLong(_ x: String, _ y: String) -> String
precondition(!x.isEmpty && !y.isEmpty, "Error, valid numbers are required for multiplication")
var prefix = ""
var containsInvalidCharacters : Bool
switch (x, y)
case let (s1, s2) where s1.first! == "-" && s2.first! == "-":
return !((s1.dropFirst() + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s2.first! == "-":
prefix = "-"
return !((s1 + s2.dropFirst()).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2) where s1.first! == "-":
prefix = "-"
return !((s1.dropFirst() + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
case let (s1, s2):
return !((s1 + s2).contains ["0","1","2","3","4","5","6","7","8","9"].contains($0) ? false : true )
precondition(containsInvalidCharacters, "Error, multiplicand contains invalid non-numeric characters")
let s1 = x.replacingOccurrences(of: "-", with: "").map Int(String($0))!
let s2 = y.replacingOccurrences(of: "-", with: "").map Int(String($0))!
var a = [Int]()
var b = [Int]()
switch (s1, s2)
case let (arr1, arr2) where arr1.count > arr2.count
var lines = [[Int]]()
for (bi, bn) in b.enumerated()
var line = Array(repeating: 0, count: bi)
var carriedNumber = 0
for an in a
let v = (bn * an) + carriedNumber
carriedNumber = (v - (v % 10)) / 10
line.insert(v % 10, at: 0)
if carriedNumber != 0
if carriedNumber >= 10
line.insert(carriedNumber % 10, at: 0)
line.insert((carriedNumber - (carriedNumber % 10)) / 10, at: 0)
else
line.insert(carriedNumber, at: 0)
lines.append(line)
let maxIndex = lines.max $0.count < $1.count !.count
var result = [Int]()
var addNum = 0
for i in 0...maxIndex
var v = addNum
for line in lines
v += line.indices.contains(i) ? line.reversed()[i] : 0
if v >= 10
addNum = Int("("(v)".dropLast())")!
result.insert(Int("("(v)".last!)")!, at: 0)
else
addNum = 0
result.insert(v, at: 0)
if addNum != 0
for i in "(addNum)".reversed()
result.insert(Int("(i)")!, at: 0)
result = Array(result.drop $0 == 0 )
let str = result.reduce("") $0 + "($1)"
return prefix + str
My Solution
func factorialDigitSum() -> Int
let f = Array(1...100).map String($0) .reduce("1",multiplyLong)
return f.map Int("($0)") ?? 0 .reduce(0, +)
print(factorialDigitSum()) //Prints "648"
Note: 648 is indeed the right answer.
performance programming-challenge functional-programming swift formatting
edited Jun 12 at 3:13
asked Jun 10 at 2:32
Noah Wilder
745
745
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
The main performance bottleneck of your solution is the representation of
big integers as a string. In each step of the factorial computation:
- The intermediate result is converted from a string to an integer array,
- the current factor is converted from
Intto a string to an integer array, - a âÂÂlong multiplicationâ is done on the two integer arrays, and finally,
- the resulting integer array is converted back to a string.
Also in every step, both input strings are validated to contain only
decimal digits (plus an optional minus sign).
This is not very efficient, and I'll address this point later.
Instead of validating each possible combination of input strings x and y,
it is more simple to define both strings separately, using a common utility function:
func multiplyLong(_ x: String, _ y: String) -> String
func isValidNumber(_ s: String) -> Bool
guard let first = s.first else
return false // String is empty
let rest = first == "-" ? s.dropFirst() : s[...]
return !rest.isEmpty && !rest.contains !"0123456789".contains($0)
precondition(isValidNumber(x) && isValidNumber(y), "Valid numbers are required for multiplication")
// ...
Note also how "0123456789" is used as a collection instead of ["0","1","2","3","4","5","6","7","8","9"], and that a conditional expression
<someCondition> ? false : true
can always be simplified to !<someCondition>.
The multiplication algorithm can also be improved. Instead of computing
separate results for the product of one big integer with a single digit
of the other big integer (your lines array), and âÂÂaddingâ those intermediate
results later, it is more efficient to accumulate all products into a single
array of result digits directly.
You also insert elements at the start each line array repeatedly, which
requires moving all existing elements. This could be avoided by reversing
the order of elements in line.
Finally note that the expression
(v - (v % 10)) / 10
which occurs at two places, can be simplified to v / 10.
A better representation
All the conversion from strings to integer arrays and back to strings can be
avoided if we represent a âÂÂbig integerâÂÂànot as a string, but as an integer
array directly. Let's start by defining a suitable type:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
digits holds the decimal digits of the big integer, starting with the
least-significant one. UInt8 is large enough to hold decimal digits
(and all intermediate results during the long multiplication). For reasons
that become apparent later, we use a type alias instead of hard-coding
the UInt8 type.
Now we define some initializers:
The first one takes an array of digits, which is truncated for a compact representation.
ThelastIndex(where:)method has been added in Swift 4.2, see
In Swift Array, is there a function that returns the last index based in where clause?
on Stack Overflow for a possible approach in earlier Swift versions.The second initializer takes an
Intand is based on the first one.We also add a
digitSumcomputed property for obvious reasons.
Then we have:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
init(digits: [Digit], negative: Bool = false)
if let idx = digits.lastIndex(where: $0 != 0 )
self.digits = Array(digits[...idx])
else
self.digits =
self.negative = negative
init(_ value: Int)
var digits: [Digit] =
var n = value.magnitude
while n > 0
digits.append(Digit(n % 10))
n /= 10
self.init(digits: digits, negative: value < 0)
var digitSum: Int
return digits.reduce(0) $0 + Int($1)
In order to print a big integer, we adopt the CustomStringConvertible
protocol:
extension BigInt: CustomStringConvertible
var description: String
if digits.isEmpty
return "0"
return (negative ? "-" : "") + digits.reversed().map String($0) .joined()
Now we can implement the multiplication. This is essentially your method
of long multiplication, but simplified to accumulate all digits into a
single result buffer (which is allocated only once):
extension BigInt
func multiplied(with other: BigInt) -> BigInt
var result = Array(repeating: Digit(0), count: digits.count + other.digits.count)
for (i, a) in digits.enumerated()
var carry: Digit = 0
for (j, b) in other.digits.enumerated()
let r = result[i + j] + a * b + carry
result[i + j] = r % 10
carry = r / 10
while carry > 0
let r = result[i + other.digits.count] + carry
result[i + other.digits.count] = r % 10
carry = r / 10
return BigInt(digits: result, negative: self.negative != other.negative)
static func *(lhs: BigInt, rhs: BigInt) -> BigInt
return lhs.multiplied(with: rhs)
Note how the init(digits:negative:) is used to compact the result array,
i.e. to remove unnecessary zero digits.
As a bonus, we implement the * method so that big integers can be multiplied
more naturally.
With all that, the digit sum of 100! is computed as
let sum = (1...100).reduce(BigInt(1), $0 * BigInt($1) ).digitSum
print(sum) // 648
In my tests on a 1.2 GHz Intel Core m5 MacBook, with the code compiled
in the Release configuration (i.e. with optimization on), the above code runs in approximately 0.5 milliseconds, compared to 30 milliseconds with your original code.
Further suggestions
Currently, the
digitsarray contains the base-10 digits of the big integer.
If we choose a largerDigittype and store more decimal digits in each
array element, then less multiplications are required, making the multiplication
more efficient.With
UInt64as theDigittype, one can perform multiplication of 9-digit
decimal numbers without overflow. This requires changing theDigit
type alias, and modifying all places in the code where base-10 arithmetic is done.Add a
init?(string: String)initializer so that a big integer can be created
withlet bn = BigInt(string: "713847891471894789471894789478917417439274")Adopt the
ExpressibleByIntegerLiteralprotocol, so that a big integer
can be created aslet bn: BigInt = 123Add addition and subtraction to the
BigInttype.If you feel courageous, add division and remainder calculation.
I don't understand what you mean, I've since changed theDigittype toUInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to theExpressibleByIntegerLiteralprotocol, it means that I can only declare small instances ofBigIntwithIntegerLiterals, but not large, yes? In my conformance extension I have:typealias IntegerLiteralType = Intandinit(integerLiteral value: IntegerLiteralType) self.init(value), is that correct? Thanks @MartinR for your help!
â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
The main performance bottleneck of your solution is the representation of
big integers as a string. In each step of the factorial computation:
- The intermediate result is converted from a string to an integer array,
- the current factor is converted from
Intto a string to an integer array, - a âÂÂlong multiplicationâ is done on the two integer arrays, and finally,
- the resulting integer array is converted back to a string.
Also in every step, both input strings are validated to contain only
decimal digits (plus an optional minus sign).
This is not very efficient, and I'll address this point later.
Instead of validating each possible combination of input strings x and y,
it is more simple to define both strings separately, using a common utility function:
func multiplyLong(_ x: String, _ y: String) -> String
func isValidNumber(_ s: String) -> Bool
guard let first = s.first else
return false // String is empty
let rest = first == "-" ? s.dropFirst() : s[...]
return !rest.isEmpty && !rest.contains !"0123456789".contains($0)
precondition(isValidNumber(x) && isValidNumber(y), "Valid numbers are required for multiplication")
// ...
Note also how "0123456789" is used as a collection instead of ["0","1","2","3","4","5","6","7","8","9"], and that a conditional expression
<someCondition> ? false : true
can always be simplified to !<someCondition>.
The multiplication algorithm can also be improved. Instead of computing
separate results for the product of one big integer with a single digit
of the other big integer (your lines array), and âÂÂaddingâ those intermediate
results later, it is more efficient to accumulate all products into a single
array of result digits directly.
You also insert elements at the start each line array repeatedly, which
requires moving all existing elements. This could be avoided by reversing
the order of elements in line.
Finally note that the expression
(v - (v % 10)) / 10
which occurs at two places, can be simplified to v / 10.
A better representation
All the conversion from strings to integer arrays and back to strings can be
avoided if we represent a âÂÂbig integerâÂÂànot as a string, but as an integer
array directly. Let's start by defining a suitable type:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
digits holds the decimal digits of the big integer, starting with the
least-significant one. UInt8 is large enough to hold decimal digits
(and all intermediate results during the long multiplication). For reasons
that become apparent later, we use a type alias instead of hard-coding
the UInt8 type.
Now we define some initializers:
The first one takes an array of digits, which is truncated for a compact representation.
ThelastIndex(where:)method has been added in Swift 4.2, see
In Swift Array, is there a function that returns the last index based in where clause?
on Stack Overflow for a possible approach in earlier Swift versions.The second initializer takes an
Intand is based on the first one.We also add a
digitSumcomputed property for obvious reasons.
Then we have:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
init(digits: [Digit], negative: Bool = false)
if let idx = digits.lastIndex(where: $0 != 0 )
self.digits = Array(digits[...idx])
else
self.digits =
self.negative = negative
init(_ value: Int)
var digits: [Digit] =
var n = value.magnitude
while n > 0
digits.append(Digit(n % 10))
n /= 10
self.init(digits: digits, negative: value < 0)
var digitSum: Int
return digits.reduce(0) $0 + Int($1)
In order to print a big integer, we adopt the CustomStringConvertible
protocol:
extension BigInt: CustomStringConvertible
var description: String
if digits.isEmpty
return "0"
return (negative ? "-" : "") + digits.reversed().map String($0) .joined()
Now we can implement the multiplication. This is essentially your method
of long multiplication, but simplified to accumulate all digits into a
single result buffer (which is allocated only once):
extension BigInt
func multiplied(with other: BigInt) -> BigInt
var result = Array(repeating: Digit(0), count: digits.count + other.digits.count)
for (i, a) in digits.enumerated()
var carry: Digit = 0
for (j, b) in other.digits.enumerated()
let r = result[i + j] + a * b + carry
result[i + j] = r % 10
carry = r / 10
while carry > 0
let r = result[i + other.digits.count] + carry
result[i + other.digits.count] = r % 10
carry = r / 10
return BigInt(digits: result, negative: self.negative != other.negative)
static func *(lhs: BigInt, rhs: BigInt) -> BigInt
return lhs.multiplied(with: rhs)
Note how the init(digits:negative:) is used to compact the result array,
i.e. to remove unnecessary zero digits.
As a bonus, we implement the * method so that big integers can be multiplied
more naturally.
With all that, the digit sum of 100! is computed as
let sum = (1...100).reduce(BigInt(1), $0 * BigInt($1) ).digitSum
print(sum) // 648
In my tests on a 1.2 GHz Intel Core m5 MacBook, with the code compiled
in the Release configuration (i.e. with optimization on), the above code runs in approximately 0.5 milliseconds, compared to 30 milliseconds with your original code.
Further suggestions
Currently, the
digitsarray contains the base-10 digits of the big integer.
If we choose a largerDigittype and store more decimal digits in each
array element, then less multiplications are required, making the multiplication
more efficient.With
UInt64as theDigittype, one can perform multiplication of 9-digit
decimal numbers without overflow. This requires changing theDigit
type alias, and modifying all places in the code where base-10 arithmetic is done.Add a
init?(string: String)initializer so that a big integer can be created
withlet bn = BigInt(string: "713847891471894789471894789478917417439274")Adopt the
ExpressibleByIntegerLiteralprotocol, so that a big integer
can be created aslet bn: BigInt = 123Add addition and subtraction to the
BigInttype.If you feel courageous, add division and remainder calculation.
I don't understand what you mean, I've since changed theDigittype toUInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to theExpressibleByIntegerLiteralprotocol, it means that I can only declare small instances ofBigIntwithIntegerLiterals, but not large, yes? In my conformance extension I have:typealias IntegerLiteralType = Intandinit(integerLiteral value: IntegerLiteralType) self.init(value), is that correct? Thanks @MartinR for your help!
â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
add a comment |Â
up vote
2
down vote
accepted
The main performance bottleneck of your solution is the representation of
big integers as a string. In each step of the factorial computation:
- The intermediate result is converted from a string to an integer array,
- the current factor is converted from
Intto a string to an integer array, - a âÂÂlong multiplicationâ is done on the two integer arrays, and finally,
- the resulting integer array is converted back to a string.
Also in every step, both input strings are validated to contain only
decimal digits (plus an optional minus sign).
This is not very efficient, and I'll address this point later.
Instead of validating each possible combination of input strings x and y,
it is more simple to define both strings separately, using a common utility function:
func multiplyLong(_ x: String, _ y: String) -> String
func isValidNumber(_ s: String) -> Bool
guard let first = s.first else
return false // String is empty
let rest = first == "-" ? s.dropFirst() : s[...]
return !rest.isEmpty && !rest.contains !"0123456789".contains($0)
precondition(isValidNumber(x) && isValidNumber(y), "Valid numbers are required for multiplication")
// ...
Note also how "0123456789" is used as a collection instead of ["0","1","2","3","4","5","6","7","8","9"], and that a conditional expression
<someCondition> ? false : true
can always be simplified to !<someCondition>.
The multiplication algorithm can also be improved. Instead of computing
separate results for the product of one big integer with a single digit
of the other big integer (your lines array), and âÂÂaddingâ those intermediate
results later, it is more efficient to accumulate all products into a single
array of result digits directly.
You also insert elements at the start each line array repeatedly, which
requires moving all existing elements. This could be avoided by reversing
the order of elements in line.
Finally note that the expression
(v - (v % 10)) / 10
which occurs at two places, can be simplified to v / 10.
A better representation
All the conversion from strings to integer arrays and back to strings can be
avoided if we represent a âÂÂbig integerâÂÂànot as a string, but as an integer
array directly. Let's start by defining a suitable type:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
digits holds the decimal digits of the big integer, starting with the
least-significant one. UInt8 is large enough to hold decimal digits
(and all intermediate results during the long multiplication). For reasons
that become apparent later, we use a type alias instead of hard-coding
the UInt8 type.
Now we define some initializers:
The first one takes an array of digits, which is truncated for a compact representation.
ThelastIndex(where:)method has been added in Swift 4.2, see
In Swift Array, is there a function that returns the last index based in where clause?
on Stack Overflow for a possible approach in earlier Swift versions.The second initializer takes an
Intand is based on the first one.We also add a
digitSumcomputed property for obvious reasons.
Then we have:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
init(digits: [Digit], negative: Bool = false)
if let idx = digits.lastIndex(where: $0 != 0 )
self.digits = Array(digits[...idx])
else
self.digits =
self.negative = negative
init(_ value: Int)
var digits: [Digit] =
var n = value.magnitude
while n > 0
digits.append(Digit(n % 10))
n /= 10
self.init(digits: digits, negative: value < 0)
var digitSum: Int
return digits.reduce(0) $0 + Int($1)
In order to print a big integer, we adopt the CustomStringConvertible
protocol:
extension BigInt: CustomStringConvertible
var description: String
if digits.isEmpty
return "0"
return (negative ? "-" : "") + digits.reversed().map String($0) .joined()
Now we can implement the multiplication. This is essentially your method
of long multiplication, but simplified to accumulate all digits into a
single result buffer (which is allocated only once):
extension BigInt
func multiplied(with other: BigInt) -> BigInt
var result = Array(repeating: Digit(0), count: digits.count + other.digits.count)
for (i, a) in digits.enumerated()
var carry: Digit = 0
for (j, b) in other.digits.enumerated()
let r = result[i + j] + a * b + carry
result[i + j] = r % 10
carry = r / 10
while carry > 0
let r = result[i + other.digits.count] + carry
result[i + other.digits.count] = r % 10
carry = r / 10
return BigInt(digits: result, negative: self.negative != other.negative)
static func *(lhs: BigInt, rhs: BigInt) -> BigInt
return lhs.multiplied(with: rhs)
Note how the init(digits:negative:) is used to compact the result array,
i.e. to remove unnecessary zero digits.
As a bonus, we implement the * method so that big integers can be multiplied
more naturally.
With all that, the digit sum of 100! is computed as
let sum = (1...100).reduce(BigInt(1), $0 * BigInt($1) ).digitSum
print(sum) // 648
In my tests on a 1.2 GHz Intel Core m5 MacBook, with the code compiled
in the Release configuration (i.e. with optimization on), the above code runs in approximately 0.5 milliseconds, compared to 30 milliseconds with your original code.
Further suggestions
Currently, the
digitsarray contains the base-10 digits of the big integer.
If we choose a largerDigittype and store more decimal digits in each
array element, then less multiplications are required, making the multiplication
more efficient.With
UInt64as theDigittype, one can perform multiplication of 9-digit
decimal numbers without overflow. This requires changing theDigit
type alias, and modifying all places in the code where base-10 arithmetic is done.Add a
init?(string: String)initializer so that a big integer can be created
withlet bn = BigInt(string: "713847891471894789471894789478917417439274")Adopt the
ExpressibleByIntegerLiteralprotocol, so that a big integer
can be created aslet bn: BigInt = 123Add addition and subtraction to the
BigInttype.If you feel courageous, add division and remainder calculation.
I don't understand what you mean, I've since changed theDigittype toUInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to theExpressibleByIntegerLiteralprotocol, it means that I can only declare small instances ofBigIntwithIntegerLiterals, but not large, yes? In my conformance extension I have:typealias IntegerLiteralType = Intandinit(integerLiteral value: IntegerLiteralType) self.init(value), is that correct? Thanks @MartinR for your help!
â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
The main performance bottleneck of your solution is the representation of
big integers as a string. In each step of the factorial computation:
- The intermediate result is converted from a string to an integer array,
- the current factor is converted from
Intto a string to an integer array, - a âÂÂlong multiplicationâ is done on the two integer arrays, and finally,
- the resulting integer array is converted back to a string.
Also in every step, both input strings are validated to contain only
decimal digits (plus an optional minus sign).
This is not very efficient, and I'll address this point later.
Instead of validating each possible combination of input strings x and y,
it is more simple to define both strings separately, using a common utility function:
func multiplyLong(_ x: String, _ y: String) -> String
func isValidNumber(_ s: String) -> Bool
guard let first = s.first else
return false // String is empty
let rest = first == "-" ? s.dropFirst() : s[...]
return !rest.isEmpty && !rest.contains !"0123456789".contains($0)
precondition(isValidNumber(x) && isValidNumber(y), "Valid numbers are required for multiplication")
// ...
Note also how "0123456789" is used as a collection instead of ["0","1","2","3","4","5","6","7","8","9"], and that a conditional expression
<someCondition> ? false : true
can always be simplified to !<someCondition>.
The multiplication algorithm can also be improved. Instead of computing
separate results for the product of one big integer with a single digit
of the other big integer (your lines array), and âÂÂaddingâ those intermediate
results later, it is more efficient to accumulate all products into a single
array of result digits directly.
You also insert elements at the start each line array repeatedly, which
requires moving all existing elements. This could be avoided by reversing
the order of elements in line.
Finally note that the expression
(v - (v % 10)) / 10
which occurs at two places, can be simplified to v / 10.
A better representation
All the conversion from strings to integer arrays and back to strings can be
avoided if we represent a âÂÂbig integerâÂÂànot as a string, but as an integer
array directly. Let's start by defining a suitable type:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
digits holds the decimal digits of the big integer, starting with the
least-significant one. UInt8 is large enough to hold decimal digits
(and all intermediate results during the long multiplication). For reasons
that become apparent later, we use a type alias instead of hard-coding
the UInt8 type.
Now we define some initializers:
The first one takes an array of digits, which is truncated for a compact representation.
ThelastIndex(where:)method has been added in Swift 4.2, see
In Swift Array, is there a function that returns the last index based in where clause?
on Stack Overflow for a possible approach in earlier Swift versions.The second initializer takes an
Intand is based on the first one.We also add a
digitSumcomputed property for obvious reasons.
Then we have:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
init(digits: [Digit], negative: Bool = false)
if let idx = digits.lastIndex(where: $0 != 0 )
self.digits = Array(digits[...idx])
else
self.digits =
self.negative = negative
init(_ value: Int)
var digits: [Digit] =
var n = value.magnitude
while n > 0
digits.append(Digit(n % 10))
n /= 10
self.init(digits: digits, negative: value < 0)
var digitSum: Int
return digits.reduce(0) $0 + Int($1)
In order to print a big integer, we adopt the CustomStringConvertible
protocol:
extension BigInt: CustomStringConvertible
var description: String
if digits.isEmpty
return "0"
return (negative ? "-" : "") + digits.reversed().map String($0) .joined()
Now we can implement the multiplication. This is essentially your method
of long multiplication, but simplified to accumulate all digits into a
single result buffer (which is allocated only once):
extension BigInt
func multiplied(with other: BigInt) -> BigInt
var result = Array(repeating: Digit(0), count: digits.count + other.digits.count)
for (i, a) in digits.enumerated()
var carry: Digit = 0
for (j, b) in other.digits.enumerated()
let r = result[i + j] + a * b + carry
result[i + j] = r % 10
carry = r / 10
while carry > 0
let r = result[i + other.digits.count] + carry
result[i + other.digits.count] = r % 10
carry = r / 10
return BigInt(digits: result, negative: self.negative != other.negative)
static func *(lhs: BigInt, rhs: BigInt) -> BigInt
return lhs.multiplied(with: rhs)
Note how the init(digits:negative:) is used to compact the result array,
i.e. to remove unnecessary zero digits.
As a bonus, we implement the * method so that big integers can be multiplied
more naturally.
With all that, the digit sum of 100! is computed as
let sum = (1...100).reduce(BigInt(1), $0 * BigInt($1) ).digitSum
print(sum) // 648
In my tests on a 1.2 GHz Intel Core m5 MacBook, with the code compiled
in the Release configuration (i.e. with optimization on), the above code runs in approximately 0.5 milliseconds, compared to 30 milliseconds with your original code.
Further suggestions
Currently, the
digitsarray contains the base-10 digits of the big integer.
If we choose a largerDigittype and store more decimal digits in each
array element, then less multiplications are required, making the multiplication
more efficient.With
UInt64as theDigittype, one can perform multiplication of 9-digit
decimal numbers without overflow. This requires changing theDigit
type alias, and modifying all places in the code where base-10 arithmetic is done.Add a
init?(string: String)initializer so that a big integer can be created
withlet bn = BigInt(string: "713847891471894789471894789478917417439274")Adopt the
ExpressibleByIntegerLiteralprotocol, so that a big integer
can be created aslet bn: BigInt = 123Add addition and subtraction to the
BigInttype.If you feel courageous, add division and remainder calculation.
The main performance bottleneck of your solution is the representation of
big integers as a string. In each step of the factorial computation:
- The intermediate result is converted from a string to an integer array,
- the current factor is converted from
Intto a string to an integer array, - a âÂÂlong multiplicationâ is done on the two integer arrays, and finally,
- the resulting integer array is converted back to a string.
Also in every step, both input strings are validated to contain only
decimal digits (plus an optional minus sign).
This is not very efficient, and I'll address this point later.
Instead of validating each possible combination of input strings x and y,
it is more simple to define both strings separately, using a common utility function:
func multiplyLong(_ x: String, _ y: String) -> String
func isValidNumber(_ s: String) -> Bool
guard let first = s.first else
return false // String is empty
let rest = first == "-" ? s.dropFirst() : s[...]
return !rest.isEmpty && !rest.contains !"0123456789".contains($0)
precondition(isValidNumber(x) && isValidNumber(y), "Valid numbers are required for multiplication")
// ...
Note also how "0123456789" is used as a collection instead of ["0","1","2","3","4","5","6","7","8","9"], and that a conditional expression
<someCondition> ? false : true
can always be simplified to !<someCondition>.
The multiplication algorithm can also be improved. Instead of computing
separate results for the product of one big integer with a single digit
of the other big integer (your lines array), and âÂÂaddingâ those intermediate
results later, it is more efficient to accumulate all products into a single
array of result digits directly.
You also insert elements at the start each line array repeatedly, which
requires moving all existing elements. This could be avoided by reversing
the order of elements in line.
Finally note that the expression
(v - (v % 10)) / 10
which occurs at two places, can be simplified to v / 10.
A better representation
All the conversion from strings to integer arrays and back to strings can be
avoided if we represent a âÂÂbig integerâÂÂànot as a string, but as an integer
array directly. Let's start by defining a suitable type:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
digits holds the decimal digits of the big integer, starting with the
least-significant one. UInt8 is large enough to hold decimal digits
(and all intermediate results during the long multiplication). For reasons
that become apparent later, we use a type alias instead of hard-coding
the UInt8 type.
Now we define some initializers:
The first one takes an array of digits, which is truncated for a compact representation.
ThelastIndex(where:)method has been added in Swift 4.2, see
In Swift Array, is there a function that returns the last index based in where clause?
on Stack Overflow for a possible approach in earlier Swift versions.The second initializer takes an
Intand is based on the first one.We also add a
digitSumcomputed property for obvious reasons.
Then we have:
struct BigInt
typealias Digit = UInt8
let digits: [Digit]
let negative: Bool
init(digits: [Digit], negative: Bool = false)
if let idx = digits.lastIndex(where: $0 != 0 )
self.digits = Array(digits[...idx])
else
self.digits =
self.negative = negative
init(_ value: Int)
var digits: [Digit] =
var n = value.magnitude
while n > 0
digits.append(Digit(n % 10))
n /= 10
self.init(digits: digits, negative: value < 0)
var digitSum: Int
return digits.reduce(0) $0 + Int($1)
In order to print a big integer, we adopt the CustomStringConvertible
protocol:
extension BigInt: CustomStringConvertible
var description: String
if digits.isEmpty
return "0"
return (negative ? "-" : "") + digits.reversed().map String($0) .joined()
Now we can implement the multiplication. This is essentially your method
of long multiplication, but simplified to accumulate all digits into a
single result buffer (which is allocated only once):
extension BigInt
func multiplied(with other: BigInt) -> BigInt
var result = Array(repeating: Digit(0), count: digits.count + other.digits.count)
for (i, a) in digits.enumerated()
var carry: Digit = 0
for (j, b) in other.digits.enumerated()
let r = result[i + j] + a * b + carry
result[i + j] = r % 10
carry = r / 10
while carry > 0
let r = result[i + other.digits.count] + carry
result[i + other.digits.count] = r % 10
carry = r / 10
return BigInt(digits: result, negative: self.negative != other.negative)
static func *(lhs: BigInt, rhs: BigInt) -> BigInt
return lhs.multiplied(with: rhs)
Note how the init(digits:negative:) is used to compact the result array,
i.e. to remove unnecessary zero digits.
As a bonus, we implement the * method so that big integers can be multiplied
more naturally.
With all that, the digit sum of 100! is computed as
let sum = (1...100).reduce(BigInt(1), $0 * BigInt($1) ).digitSum
print(sum) // 648
In my tests on a 1.2 GHz Intel Core m5 MacBook, with the code compiled
in the Release configuration (i.e. with optimization on), the above code runs in approximately 0.5 milliseconds, compared to 30 milliseconds with your original code.
Further suggestions
Currently, the
digitsarray contains the base-10 digits of the big integer.
If we choose a largerDigittype and store more decimal digits in each
array element, then less multiplications are required, making the multiplication
more efficient.With
UInt64as theDigittype, one can perform multiplication of 9-digit
decimal numbers without overflow. This requires changing theDigit
type alias, and modifying all places in the code where base-10 arithmetic is done.Add a
init?(string: String)initializer so that a big integer can be created
withlet bn = BigInt(string: "713847891471894789471894789478917417439274")Adopt the
ExpressibleByIntegerLiteralprotocol, so that a big integer
can be created aslet bn: BigInt = 123Add addition and subtraction to the
BigInttype.If you feel courageous, add division and remainder calculation.
edited Jun 10 at 12:28
answered Jun 10 at 12:07
Martin R
14k12157
14k12157
I don't understand what you mean, I've since changed theDigittype toUInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to theExpressibleByIntegerLiteralprotocol, it means that I can only declare small instances ofBigIntwithIntegerLiterals, but not large, yes? In my conformance extension I have:typealias IntegerLiteralType = Intandinit(integerLiteral value: IntegerLiteralType) self.init(value), is that correct? Thanks @MartinR for your help!
â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
add a comment |Â
I don't understand what you mean, I've since changed theDigittype toUInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to theExpressibleByIntegerLiteralprotocol, it means that I can only declare small instances ofBigIntwithIntegerLiterals, but not large, yes? In my conformance extension I have:typealias IntegerLiteralType = Intandinit(integerLiteral value: IntegerLiteralType) self.init(value), is that correct? Thanks @MartinR for your help!
â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
I don't understand what you mean, I've since changed the
Digit type to UInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to the ExpressibleByIntegerLiteral protocol, it means that I can only declare small instances of BigInt with IntegerLiterals, but not large, yes? In my conformance extension I have: typealias IntegerLiteralType = Int and init(integerLiteral value: IntegerLiteralType) self.init(value) , is that correct? Thanks @MartinR for your help!â Noah Wilder
Jun 12 at 5:21
I don't understand what you mean, I've since changed the
Digit type to UInt64, and it seems to work perfectly, so then what do I need to do in regards to: "modifying all places in the code where base-10 arithmetic is done"? Also, when conforming to the ExpressibleByIntegerLiteral protocol, it means that I can only declare small instances of BigInt with IntegerLiterals, but not large, yes? In my conformance extension I have: typealias IntegerLiteralType = Int and init(integerLiteral value: IntegerLiteralType) self.init(value) , is that correct? Thanks @MartinR for your help!â Noah Wilder
Jun 12 at 5:21
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
@NoahWilder: Changing UInt8 to UInt64 alone does not improve the efficiency. The idea is that every array element holds not values 0...9, but 0...999999999 (for example). â You are right with respect to ExpressibleByIntegerLiteral.
â Martin R
Jun 12 at 5:25
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f196204%2fnumbers-as-strings-multiplication-function-in-swift%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password