I am trying to calculate results for each sub problem using @tailrec
similar to how normal recursive solutions can produce solutions for each sub problem.
Following is the example I worked on.
@tailrec
def collatz(
n: BigInt,
acc: BigInt,
fn: (BigInt, BigInt) => Unit
): BigInt = {
fn(n, acc)
if (n == 1) {
acc
} else if (n % 2 == 0) {
collatz(n / 2, acc + 1, fn)
} else {
collatz(3 * n + 1, acc + 1, fn)
}
}
Here I am calculating the count of a number when it reaches 1
using Collatz Conjecture
. Just for an example let us assume it for number 32
val n = BigInt("32")
val c = collatz(n, 0, (num, acc) => {
println("Num -> " + num + " " + " " + "Acc -> " + acc)
})
I am getting the following output.
Num -> 32 Acc -> 0
Num -> 16 Acc -> 1
Num -> 8 Acc -> 2
Num -> 4 Acc -> 3
Num -> 2 Acc -> 4
Num -> 1 Acc -> 5
Normal recursive solution will return exact count for each number. For instance number 2
reaches 1
in 1
step. Thus each sub problem has exact solution but in a tailrec
method only final result is computed correctly. The variable acc
behaves exactly like a loop variable as expected.
How can I change the code that is tail call optimized at the same time I can get exact value to the each sub problem. In simple words, how can I attain Stack
type of behavior for acc
variable.
Also, one related question how large will be the overhead of lambda function fn
for large values of n
assuming println
statement will not be used.
I am adding a recursive solution that can produce correct solution for the sub problem.
def collatz2(
n: BigInt,
fn: (BigInt, BigInt) => Unit
): BigInt = {
val c: BigInt = if (n == 1) {
0
} else if (n % 2 == 0) {
collatz2(n / 2, fn) + 1
} else {
collatz2(3 * n + 1, fn) + 1
}
fn(n, c)
c
}
It produces the following output.
Num -> 1 Acc -> 0
Num -> 2 Acc -> 1
Num -> 4 Acc -> 2
Num -> 8 Acc -> 3
Num -> 16 Acc -> 4
Num -> 32 Acc -> 5