I am confused with the following recursive example. The place where recursion happens, the local variable needs to be updated every time. I wonder then how it could store the base result? And let variable is not mutable, how it updates?
The question is as follows for the following solution:
Implement a recursive function named digits that takes a positive
integer number and return an array containing it’s digits in order.
Function call:
digits(123)
Function output:
[1, 2, 3]
func digits(_ number:Int) -> [Int]
{
if number >= 10 {
// confusion in the following line
let firstDigits = digits(number / 10)
let lastDigit = number % 10
return firstDigits + [lastDigit]
} else {
return [number]
}
}
I would rather approach the problems as follows. I wonder what is the advantages of having the above solution.
func digits(_ number:Int) -> [Int]
{
if number >= 10 {
let lastDigit = number % 10
return digits(number / 10) + [lastDigit]
} else {
return [number]
}
}
I wonder then how it could store the base result? And let variable is not mutable, how it updates?
firstDigits never changes, it is only set once in each invocation of digits. Each invocation of digits has it's own variables.
Example Execution
In the following example I show how the execute proceeds as a series of substitutions.
digits(123) ->
digits(123 / 10) + [123 % 10] ->
digits(12) + [3] ->
digits(12 / 10) + [12 % 10] + [3] ->
digits(1) + [2] + [3] ->
[1] + [2] + [3] ->
[1, 2, 3]
Another way to write it that may be more clear
func digits(_ number:Int) -> [Int]
{
if number >= 10 {
return digits(number / 10) + [number % 10]
} else {
return [number]
}
}
Related
This might be rather stupid question. I would like to know if different nuances/extent of randomness would be possible using arc4random_uniform in Swift. Here's an example:
let number = arc4random_uniform(10) + 1
print(number)
In this case, a number will be printed randomly from 1 to 10. But is there a way that I can repeat the random result, 2 to 3 times? The result would be something like this:
1, 1, 6, 6, 6, 3, 3, 8, 8, 9, 9, 9 ...
// 1) Randomly selected and 2) repeated 2 to 3 times randomly.
Perhaps I might use two arc4random_uniform functions together, but cannot express them properly. Would be much appreciated if you could give me some suggestions. <3
In order to do this, you will need to generate two values: your random value and a repeatCount. Also, you'll need to remember both of those values so that you can repeat the value. You can do this with a custom class:
class RandomWithRepeats {
var range: ClosedRange<Int>
var repeatRange: ClosedRange<Int>
var repeatCount = 0
var value = 0
init(range: ClosedRange<Int>, repeatRange: ClosedRange<Int>) {
self.range = range
self.repeatRange = repeatRange
}
// generate a random number in a range
// Just use Int.random(in:) with Swift 4.2 and later
func random(in range: ClosedRange<Int>) -> Int {
return Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound + 1))) + range.lowerBound
}
func nextValue() -> Int {
// if repeatCount is 0, its time to generate a new value and
// a new repeatCount
if repeatCount == 0 {
// For Swift 4.2, just use Int.random(in:) instead
value = self.random(in: range)
repeatCount = self.random(in: repeatRange)
}
repeatCount -= 1
return value
}
}
Example:
let rand = RandomWithRepeats(range: 1...10, repeatRange: 2...3)
// generate 20 random repeated numbers
for _ in 1...20
{
print(rand.nextValue(), terminator: " ")
}
6 6 6 8 8 8 10 10 10 2 2 9 9 5 5 8 8 8 5 5
With regards to the nuances of random number generators: have a look at GKRandomSource.
What you're doing here is not really making something less random, or modifying the parameters in the random number generator. You're simply applying an operation (with one random parameter) to a collection of random integers.
extension Collection {
func duplicateItemsRandomly(range: CountableClosedRange<Int>) -> [Element] {
return self.reduce(into: [Element](), { (acc, element) in
let distance = UInt32(range.upperBound - range.lowerBound + 1)
let count = Int(arc4random_uniform(distance) + UInt32(range.lowerBound))
let result = Array.init(repeating: element, count: count)
acc.append(contentsOf: result)
})
}
}
let sequence = [1, 6, 3, 8, 9]
sequence.duplicateItemsRandomly(range: 2...3)
// [1, 1, 6, 6, 6, 3, 3, 3, 8, 8, 8, 9, 9, 9]
P.S: If you're writing this code in Swift 4.2, please use Int.random(in:).
I'd suggest a custom Sequence:
class RepeatingRandomSequence : Sequence {
let rangeLow, rangeSpan : UInt32
let repeatLow, repeatSpan : UInt32
init(range:Range<UInt32>, count:Range<UInt32>) {
rangeLow = range.lowerBound
rangeSpan = range.upperBound - range.lowerBound + 1
repeatLow = count.lowerBound
repeatSpan = count.upperBound - count.lowerBound + 1
}
func makeIterator() -> AnyIterator<UInt32> {
var count : UInt32 = 0
var value : UInt32 = 0
return AnyIterator {
if(count <= 0) {
count = arc4random_uniform(self.repeatSpan) + self.repeatLow
value = arc4random_uniform(self.rangeSpan) + self.rangeLow
}
defer { count = count - 1 }
return value
}
}
}
let sequence = RepeatingRandomSequence(range: 0..<10, count: 2..<3)
let randoms = sequence.makeIterator()
Note that the iterator, randoms now generates an endless sequence of random numbers using randoms.next() Since the sequence is endless, many things aren't particularly useful, like sort, map, etc. You could however use it like:
for value in random {
print(value)
if(value == 9) { // or any other termination condition
break
}
}
Or more conventionally, as:
(0..<10).forEach { _ in
print(String(describing: random.next()))
}
I have written this function to return the factorial of a given number
func factorial(_ n: Int) -> Int {
if n == 0 {
return 1
}
else {
return n * factorial(n - 1)
}
}
print( factorial(20) ) // 2432902008176640000
Works as it should, as long the given number does not exceed 20, because then the result becomes too high!
How can I circumvent this limit and thus calculate the factorial of higher numbers?
I have searched around and found some bignum libraries for Swift. I'm doing this to learn and be familiar with Swift, therefore I want to figure this out on my own.
Here's an approach that will let you find very large factorials.
Represent large numbers as an array of digits. For instance 987 would be [9, 8, 7]. Multiplying that number by an integer n would require two steps.
Multiply each value in that array by n.
Perform a carry operation to return a result that is again single digits.
For example 987 * 2:
let arr = [9, 8, 7]
let arr2 = arr.map { $0 * 2 }
print(arr2) // [18, 16, 14]
Now, perform the carry operation. Starting at the one's digit, 14 is too big, so keep the 4 and carry the 1. Add the 1 to 16 to get 17.
[18, 17, 4]
Repeat with the ten's place:
[19, 7, 4]
And then with the hundred's place:
[1, 9, 7, 4]
Finally, for printing, you could convert this back to a string:
let arr = [1, 9, 7, 4]
print(arr.map(String.init).joined())
1974
Applying that technique, here is a carryAll function that performs the carry operation, and a factorial that uses it to calculate very large factorials:
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
func factorial(_ n: Int) -> String {
var result = [1]
for i in 2...n {
result = result.map { $0 * i }
result = carryAll(result)
}
return result.map(String.init).joined()
}
print(factorial(1000))
402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
You can use this library:
BigInt
Install it using CocoaPods:
pod 'BigInt'
Then you can use it like this:
import BigInt
func factorial(_ n: Int) -> BigInt {
if n == 0 {
return 1
}
else {
return BigInt(n) * factorial(n - 1)
}
}
print( factorial(50) ) // 30414093201713378043612608166064768844377641568960512000000000000
How do I write the following in Swift3?
for (f = first; f <= last; f += interval)
{
n += 1
}
This is my own attempt
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
Swift 2.2 -> 3.0: Strideable:s stride(...) replaced by global stride(...) functions
In Swift 2.2, we can (as you've tried in your own attempt) make use of the blueprinted (and default-implemented) functions stride(through:by:) and stride(to:by:) from the protocol Strideable
/* Swift 2.2: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in from.stride(through, by: by) { } // from ... through (steps: 'by')
for _ in from.stride(to, by: by) { } // from ..< to (steps: 'by')
Whereas in Swift 3.0, these two functions has been removed from Strideable in favour of the global functions stride(from:through:by:) and stride(from:to:by:); hence the equivalent Swift 3.0 version of the above follows as
/* Swift 3.0: stride example usage */
let from = 0
let to = 10
let through = 10
let by = 1
for _ in stride(from: from, through: through, by: by) { }
for _ in stride(from: from, to: to, by: by) { }
In your example you want to use the closed interval stride alternative stride(from:through:by:), since the invariant in your for loop uses comparison to less or equal to (<=). I.e.
/* example values of your parameters 'first', 'last' and 'interval' */
let first = 0
let last = 10
let interval = 2
var n = 0
for f in stride(from: first, through: last, by: interval) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
Where, naturally, we use your for loop only as an example of the passage from for loop to stride, as you can naturally, for your specific example, just compute n without the need of a loop (n=1+(last-first)/interval).
Swift 3.0: An alternative to stride for more complex iterate increment logic
With the implementation of evolution proposal SE-0094, Swift 3.0 introduced the global sequence functions:
sequence(first:next:),
sequence(state:next:),
which can be an appropriate alternative to stride for cases with a more complex iterate increment relation (which is not the case in this example).
Declaration(s)
func sequence<T>(first: T, next: #escaping (T) -> T?) ->
UnfoldSequence<T, (T?, Bool)>
func sequence<T, State>(state: State,
next: #escaping (inout State) -> T?) ->
UnfoldSequence<T, State>
We'll briefly look at the first of these two functions. The next arguments takes a closure that applies some logic to lazily construct next sequence element given the current one (starting with first). The sequence is terminated when next returns nil, or infinite, if a next never returns nil.
Applied to the simple constant-stride example above, the sequence method is a bit verbose and overkill w.r.t. the fit-for-this-purpose stride solution:
let first = 0
let last = 10
let interval = 2
var n = 0
for f in sequence(first: first,
next: { $0 + interval <= last ? $0 + interval : nil }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
The sequence functions become very useful for cases with non-constant stride, however, e.g. as in the example covered in the following Q&A:
Express for loops in swift with dynamic range
Just take care to terminate the sequence with an eventual nil return (if not: "infinite" element generation), or, when Swift 3.1 arrives, make use of its lazy generation in combination with the prefix(while:) method for sequences, as described in evolution proposal SE-0045. The latter applied to the running example of this answer makes the sequence approach less verbose, clearly including the termination criteria of the element generation.
/* for Swift 3.1 */
// ... as above
for f in sequence(first: first, next: { $0 + interval })
.prefix(while: { $0 <= last }) {
print(f)
n += 1
} // 0 2 4 6 8 10
print(n) // 6
With Swift 5, you may choose one of the 5 following examples in order to solve your problem.
#1. Using stride(from:to:by:) function
let first = 0
let last = 10
let interval = 2
let sequence = stride(from: first, to: last, by: interval)
for element in sequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#2. Using sequence(first:next:) function
let first = 0
let last = 10
let interval = 2
let unfoldSequence = sequence(first: first, next: {
$0 + interval < last ? $0 + interval : nil
})
for element in unfoldSequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#3. Using AnySequence init(_:) initializer
let anySequence = AnySequence<Int>({ () -> AnyIterator<Int> in
let first = 0
let last = 10
let interval = 2
var value = first
return AnyIterator<Int> {
defer { value += interval }
return value < last ? value : nil
}
})
for element in anySequence {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#4. Using CountableRange filter(_:) method
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.filter({ $0 % interval == 0 })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
#5. Using CountableRange flatMap(_:) method
let first = 0
let last = 10
let interval = 2
let range = first ..< last
let lazyCollection = range.lazy.compactMap({ $0 % interval == 0 ? $0 : nil })
for element in lazyCollection {
print(element)
}
/*
prints:
0
2
4
6
8
*/
Simply, working code for Swift 3.0:
let (first, last, interval) = (0, 100, 1)
var n = 0
for _ in stride(from: first, to: last, by: interval) {
n += 1
}
We can also use while loop as alternative way
while first <= last {
first += interval
}
for _ in 0.stride(to: last, by: interval)
{
n += 1
}
I'm using vDSP_conv to perform autocorrelation. Mostly it works just fine but every so often it's filling the output array with NaNs.
The code:
func corr_test() {
var pass = 0
var x = [Float]()
for i in 0..<2000 {
x.append(Float(i))
}
while true {
print("pass \(pass)")
let corr = autocorr(x)
if corr[1].isNaN {
print("!!!")
}
pass += 1
}
}
func autocorr(a: [Float]) -> [Float] {
let resultLen = a.count * 2 + 1
let padding = [Float].init(count: a.count, repeatedValue: 0.0)
let a_pad = padding + a + padding
var result = [Float].init(count: resultLen, repeatedValue: 0.0)
vDSP_conv(a_pad, 1, a_pad, 1, &result, 1, UInt(resultLen), UInt(a_pad.count))
return result
}
The output:
pass ...
pass 169
pass 170
pass 171
(lldb) p corr
([Float]) $R0 = 4001 values {
[0] = 2.66466637E+9
[1] = NaN
[2] = NaN
[3] = NaN
[4] = NaN
...
I'm not sure what's going on here. I think I'm handling the 0 padding correctly since if I weren't I don't think I'd be getting correct results 99% of the time.
Ideas? Gracias.
Figured it out. The key was this comment from https://developer.apple.com/library/mac/samplecode/vDSPExamples/Listings/DemonstrateConvolution_c.html :
// “The signal length is padded a bit. This length is not actually passed to the vDSP_conv routine; it is the number of elements
// that the signal array must contain. The SignalLength defined below is used to allocate space, and it is the filter length
// rounded up to a multiple of four elements and added to the result length. The extra elements give the vDSP_conv routine
// leeway to perform vector-load instructions, which load multiple elements even if they are not all used. If the caller did not
// guarantee that memory beyond the values used in the signal array were accessible, a memory access violation might result.”
“Padded a bit.” Thanks for being so specific. Anyway here's the final working product:
func autocorr(a: [Float]) -> [Float] {
let filterLen = a.count
let resultLen = filterLen * 2 - 1
let signalLen = ((filterLen + 3) & 0xFFFFFFFC) + resultLen
let padding1 = [Float].init(count: a.count - 1, repeatedValue: 0.0)
let padding2 = [Float].init(count: (signalLen - padding1.count - a.count), repeatedValue: 0.0)
let signal = padding1 + a + padding2
var result = [Float].init(count: resultLen, repeatedValue: 0.0)
vDSP_conv(signal, 1, a, 1, &result, 1, UInt(resultLen), UInt(filterLen))
// Remove the first n-1 values which are just mirrored from the end so that [0] always has the autocorrelation.
result.removeFirst(filterLen - 1)
return result
}
Note that the results here aren't normalized.
I am trying to solve the second problem on Project Euler. The problem is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I think I've written a solution, but when I try to run my code it crashes my Swift playground and gives me this error message:
Playground execution aborted: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
var prev = 0
var next = 1
var num = 0
var sum = 0
for var i = 1; i < 400; i++ {
num = prev + next
if next % 2 == 0 {
sum += next
}
prev = next
next = num
}
print(sum)
The weird thing is, if I set the counter on my loop to less than 93, it works fine. Explicitly setting the variable names to Double does not help. Anyone know what's going on here?
There is nothing weird about this at all. Do you know how large the 400 fibonacci number is?
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Swift Int64 or UInt64 simply cannot handle that large of a number. The later can go up to 18446744073709551615 at max - not even close.
If you change your variables to be doubles it works but will be inaccurate:
var prev : Double = 0
var next : Double = 1
var num : Double = 0
var sum : Double = 0
will yield
2.84812298108489e+83
which is kind of close to the actual value of
1.76e+83
Luckily you do not need to get values that big. I would recommend not writing a for loop but a while loop that calculates the next fibonacci number until the break condition is met whose values do not exceed four million.
The Fibonacci numbers become very large quickly. To compute large Fibonacci numbers, you need to implement some kind of BigNum. Here is a version the makes a BigNum that is implemented internally as an array of digits. For example, 12345 is implemented internally as [1, 2, 3, 4, 5]. This makes it easy to represent arbitrarily large numbers.
Addition is implemented by making the two arrays the same size, then map is used to add the elements, finally the carryAll function restores the array to single digits.
For example 12345 + 67:
[1, 2, 3, 4, 5] + [6, 7] // numbers represented as arrays
[1, 2, 3, 4, 5] + [0, 0, 0, 6, 7] // pad the shorter array with 0's
[1, 2, 3, 10, 12] // add the arrays element-wise
[1, 2, 4, 1, 2] // perform carry operation
Here is the implementation of BigNum. It is also CustomStringConvertible which makes it possible to print the result as a String.
struct BigNum: CustomStringConvertible {
var arr = [Int]()
// Return BigNum value as a String so it can be printed
var description: String { return arr.map(String.init).joined() }
init(_ arr: [Int]) {
self.arr = carryAll(arr)
}
// Allow BigNum to be initialized with an `Int`
init(_ i: Int = 0) {
self.init([i])
}
// Perform the carry operation to restore the array to single
// digits
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
// Enable two BigNums to be added with +
static func +(_ lhs: BigNum, _ rhs: BigNum) -> BigNum {
var arr1 = lhs.arr
var arr2 = rhs.arr
let diff = arr1.count - arr2.count
// Pad the arrays to the same length
if diff < 0 {
arr1 = Array(repeating: 0, count: -diff) + arr1
} else if diff > 0 {
arr2 = Array(repeating: 0, count: diff) + arr2
}
return BigNum(zip(arr1, arr2).map { $0 + $1 })
}
}
// This function is based upon this question:
// https://stackoverflow.com/q/52975875/1630618
func fibonacci(to n: Int) {
guard n >= 2 else { return }
var array = [BigNum(0), BigNum(1)]
for i in 2...n {
array.append(BigNum())
array[i] = array[i - 1] + array[i - 2]
print(array[i])
}
}
fibonacci(to: 400)
Output:
1
2
3
5
8
...
67235063181538321178464953103361505925388677826679492786974790147181418684399715449
108788617463475645289761992289049744844995705477812699099751202749393926359816304226
176023680645013966468226945392411250770384383304492191886725992896575345044216019675