What happens in the stack during the recursive function operation?I am having a lot of trouble understanding the branching of the stack during these function calls.Someone breaking it down will really help me
Whenever a function call is encountered, the program will create a new stack frame, allocating space for local (automatic) variables.
So in this case, to evaluate f(n-1) + f(n-2), the program will first increment the stack pointer to make space for the f(n-1) call, and then call the function. Inside that function, it will find another f(n-1), and will evaluate f((n-1)-1), and so on until it reaches the base case. After returning from the base case, it will then evaluate f((((n-1)-1)...-2) (the second term in f(n-1)+f(n-2) etc.
So for example, the sequence of calls will be
f(4)
f(3)
f(2)
f(1) (base case, return)
f(0) (base case for f(n-2), return to evalutation of f(2))
return from f(2) to f(3), having computed f(1) + f(0)
f(3 - 2 = 1) again from the call to f(3). Return immediately because f(1) is a base case.
f(4 - 2 = 2) from f(4)
f(1) from f(2) (again)
f(0) from f(2) (again)
return from f(2)
return from f(4)
You will have noticed this isn't very efficient.
As #SMA said, look into using a debugger such as pdb in Python or gdb in C - it will give you a great insight into what happens to the stack.
Related
I'm trying to make sense of this Caml function to calculate the n-th power of a number.
let rec iterate n f d =
if n = 0 then d
else iterate (n-1) f (f d)
let power i n =
let i_times a = a * i in
iterate n i_times 1
I understand what it does conceptually, but I am having trouble understanding the i_times bit.
Per my understanding, i_times takes a value a and returns a*i, whre i is passed onto power upon calling it. In the expression where i_times is defined, it's followed by 1, so wouldn't this mean that i_times 1, all together, is evaluated to 1*i?
In this case, I fail to see how 3 parameters are being passed to iterate. Why doesn't it just end up being 2, that is n and i_times 1?
I know this is a pretty basic function, but I'm just getting started with functional programming and I want to make sense of it.
Basically you're asking how OCaml parses a series of juxtaposed values.
This expression:
f a b c
is iterpreted as a call to a function f that passes 3 separate parameters. It is not parsed like this:
f a (b c)
which would be passing 2 parameters to f.
So indeed, three parameters are being passed to iterate. There are no subexpressions in the list of parameters, just three separate parameters.
Why didn't you figure that the subexpression n i_times would be evaluated before calling iterate? The reason (I suspect) is that you know that n isn't a function. But the parsing of the language doesn't depend on the types of things. If you wrote (n i_times) (with parentheses) it would be parsed as a call to n as a function. (This would, of course, be an error.)
I have the following code that I'm using as part of an attempt to implement the most accurate equation of state for water in Julia 0.6.
struct parameterizedeos
Tc::Float64
ρc::Float64
R::Float64
#parameters for ideal gas portion
n₀::Vector{Float64}
γ₀::Vector{Float64}
end
h2o_n₀ = [-8.3204464837497, 6.6832105275932, 3.00632, 0.012436, 0.97315, 1.27950,
0.96956, 0.24873]
h2o_γ₀ = [1.28728967, 3.53734222, 7.74073708, 9.24437796, 27.5075105]
function Σ(expr)
return sum(eval(#. expr))
end
function ig(eos, δ, τ)
end_ = Σ(eos.n₀[4:8]*log(1-exp(-eos.γ₀)*τ))
return log(δ) + eos.n₀[1] + eos.n₀[2]*τ + eos.n₀[3]*log(τ) + end_
end
Tc = 647.096
ρc = 322
R = 0.46151805
eos = parameterizedeos(Tc,ρc,R,h2o_n₀,h2o_γ₀)
δ₁ = 838.025/ρc
τ₁ = Tc/500
print(ig(eos,δ₁,τ₁))
Σ is supposed to be a simple form of the corresponding operator from math, while δ and τ use the nomenclature from the linked reference (dimensionless density and temperature respectively). I get LoadError: DimensionMismatch("Cannot multiply two vectors").
I've played around with all sorts of subexamples in the Julia REPL and they all seem to work just as I'd expect. Σ(log(1-exp(-h2o_γ₀)*τ)) vectorizes and sums the elements as expected. Heck, eval(#. h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ) happily returns a 5-element vector. But calling Σ(h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ)) breaks.
I'm a noob at Julia and at arcane things like macros, so anyone could help me figure out what's going on here, that would be great.
Try this (using .* and log. and exp. instead)
function ig(eos, δ, τ)
end_ = Σ(eos.n₀[4:8] .* log.(1-exp.(-eos.γ₀)*τ))
return log(δ) + eos.n₀[1] + eos.n₀[2]*τ + eos.n₀[3]*log(τ) + end_
end
The error you get: DimensionMismatch("Cannot multiply two vectors") happens inside the function ig when eos.n₀[4:8]*log(1-exp(-eos.γ₀)*τ) is evaluated, before the result is supposed to be passed to Σ.
Furthermore: #. is expanded at parse time in global scope, it adds dots to function calls and operators. expr is just a variable, not an operator, not a function call, so therefore #. does nothing. eval also does nothing, so sum(eval(#. expr)) is identical to just plain sum(expr). But since the program fails before that point, this is not your problem.
(Edit: Actually eval does more than nothing. It does some work; the results are identical, but the extra work is completely wasted.)
Solution: Delete the function Σ, you don't need it. Re-write the function ig as follows:
function ig(eos, δ, τ)
end_ = sum(#. eos.n₀[4:8] * log(1 - exp(-eos.γ₀) * τ))
return log(δ) + eos.n₀[1] + eos.n₀[2]*τ + eos.n₀[3]*log(τ) + end_
end
Edit:
I've played around with all sorts of subexamples in the Julia REPL and
they all seem to work just as I'd expect. Σ(log(1-exp(-h2o_γ₀)*τ))
vectorizes and sums the elements as expected. Heck, eval(#. h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ) happily returns a 5-element vector.
But calling Σ(h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ)) breaks.
Everything here works as expected. log and exp vectorize automatically, for now, but that behaviour is deprecated. In version 1.0 calling log or exp (or sin or sqrt, etc.) on a vector will be an error.
eval(#. h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ) vectorizes this expression as expected. (But remove the eval, you're just calling it on a value, which it makes no sense to eval.)
And Σ(h2o_n₀[4:8]*log(1-exp(-h2o_γ₀)*τ)) fails because you're trying to multiply two vectors, something that has never worked (you can take the dot-product (using e.g. '* or dot), or do element-wise multiplication, though.) The fact that you later try to pass the result of this into Σis irrelevant.
This snippet is from the implementation of Rational Numbers in Julia:
# Rational.jl
# ...
Rational{T<:Integer}(n::T, d::T) = Rational{T}(n,d)
Rational(n::Integer, d::Integer) = Rational(promote(n,d)...)
Rational(n::Integer) = Rational(n,one(n))
//(x::Rational, y::Integer) = x.num // (x.den*y) <--- HERE!
# ...
See how the // function is implemented and then used with infix notation? How does this actually return a value?
When I saw this code I interpreted it like this:
The // function is called with a Rational and an Integer.
But then it makes a recursive call with no other arguments.
#2 is the one that really confuses me. Where does the recursion within data structure end? How does // return a value if it is constantly evaluating nothing?
Please help me understand this.
This works because of one of the most fundamental features of Julia: multiple dispatch. In Julia, functions can have many methods which apply to various combinations of argument types, and when you call a function, Julia invokes the most specific method which matches the type of all the arguments that you called it with. The // call in the method definition you posted defines rational-integer // in terms of integer-integer // – so it isn't actually recursive because the method doesn't call itself, it calls a different method that is part of the same "generic function".
To understand how multiple dispatch works in this case, let's consider the evaluation of the expression (3//4)//6. We'll use the #which macro to see which method each function call invokes.
julia> #which (3//4)//6
//(x::Rational{T<:Integer}, y::Integer) at rational.jl:25
Since 3//4 is a Rational{Int} <: Rational and 6 is an Int <: Integer, and no other more specific methods apply, this method is called:
//(x::Rational, y::Integer) = x.num // (x.den*y)
The current version of the method is actually slightly more complicated than what you posted because it's been modified to check for integer overflow – but it's essentially the same, and it's easier to understand the older, simpler version, so I'll use that. Let's assign x and y to the arguments and see what method the definition calls:
julia> x, y = (3//4), 6
(3//4,6)
julia> x.num
3
julia> x.den*y
24
julia> x.num // (x.den*y)
1//8
julia> #which x.num // (x.den*y)
//(n::Integer, d::Integer) at rational.jl:22
As you can see, this expression doesn't call the same method, it calls a different method:
//(n::Integer, d::Integer) = Rational(n,d)
This method simply calls the Rational constructor which puts the ratio of n and d into lowest terms and creates a Rational number object.
It is quite common to define one method of a function in terms of another method of the same function, in Julia. This is how argument defaults work, for example. Consider this definition:
julia> f(x, y=1) = 2x^y
f (generic function with 2 methods)
julia> methods(f)
# 2 methods for generic function "f":
f(x) at none:1
f(x, y) at none:1
julia> f(1)
2
julia> f(2)
4
julia> f(2,2)
8
The default argument syntax simply generates a second method with only onee argument, which calls the two-argument form with the default value. So f(x, y=1) = 2x^y is exactly equivalent to defining two methods, where the unary method just calls the binary method, supplying a default value for the second argument:
julia> f(x, y) = 2x^y
f (generic function with 1 method)
julia> f(x) = f(x, 1)
f (generic function with 2 methods)
I have an application in which I need to define a piecewise function, IE, f(x) = g(x) for [x in some range], f(x)=h(x) for [x in some other range], ... etc.
Is there a nice way to do this in Julia? I'd rather not use if-else because it seems that I'd have to check every range for large values of x. The way that I was thinking was to construct an array of functions and an array of bounds/ranges, then when f(x) is called, do a binary search on the ranges to find the appropriate index and use the corresponding function (IE, h(x), g(x), etc.
It seems as though such a mathematically friendly language might have some functionality for this, but the documentation doesn't mention piecewise in this manner. Hopefully someone else has given this some thought, thanks!
with a Heaviside function you can do a interval function:
function heaviside(t)
0.5 * (sign(t) + 1)
end
and
function interval(t, a, b)
heaviside(t-a) - heaviside(t-b)
end
function piecewise(t)
sinc(t) .* interval(t,-3,3) + cos(t) .* interval(t, 4,7)
end
and I think it could also implement a subtype Interval, it would be much more elegant
I tried to implement a piecewise function for Julia, and this is the result:
function piecewise(x::Symbol,c::Expr,f::Expr)
n=length(f.args)
#assert n==length(c.args)
#assert c.head==:vect
#assert f.head==:vect
vf=Vector{Function}(n)
for i in 1:n
vf[i]=#eval $x->$(f.args[i])
end
return #eval ($x)->($(vf)[findfirst($c)])($x)
end
pf=piecewise(:x,:([x>0, x==0, x<0]),:([2*x,-1,-x]))
pf(1) # => 2
pf(-2) # => 2
pf(0) # => -1
Why not something like this?
function piecewise(x::Float64, breakpts::Vector{Float64}, f::Vector{Function})
#assert(issorted(breakpts))
#assert(length(breakpts) == length(f)+1)
b = searchsortedfirst(breakpts, x)
return f[b](x)
end
piecewise(X::Vector{Float64}, bpts, f) = [ piecewise(x,bpts,f) for x in X ]
Here you have a list of (sorted) breakpoints, and you can use the optimized searchsortedfirst to find the first breakpoint b greater than x. The edge case when no breakpoint is greater than x is also handled appropriately since length(breakpts)+1 is returned, so b is the correct index into the vector of functions f.
We all know the program for this
int fact(int n)
{
if(n==0)
return(1);
return(n*fact(n-1));
}
But what is not clear to me is how the inner thing is happening?
How is it calculating 5*4*3*2*1 (if n is 5)
Please give a clear explanation on this.
Thanks.....
Mathematically, the recursive definition of factorial can be expressed recursively like so (from Wikipedia):
Consider how this works for n = 3, using == to mean equivalence:
3! == 2! * 3 == (1! * 2) * 3 == ((1) * 2) * 3
This can be derived purely symbolically by repeatedly applying the recursive rule.
What this definition does is first expand out a given factorial into an equivalent series of multiplications. It then performs the actual multiplications. The C code you have performs the exact same way.
What might help to understand it, is that when you are recursively calling the function, the new "cycle" will use N-1, not N.
This way, once you get to N==0, the last function you called will return a 1. At this point all the stack of functions are waiting for the return of the nested function. That is how now you exactly multiply the results of each of the functions on the stack.
In other words, you factorize the number given as input.