Max
Max

Reputation: 877

Modify variables inside a for loop within a function

In the following function

function foo(g)
    a = [g * sqrt(i) for i in 1:4]
    b = [g * i ^ 2 for i in 1:4]
    for j in [a, b]
        j /= sum(j)
        println(j)
    end
    
    return a, b
end

foo(2)

I expect the printed values to agree with the returned values. Instead, the returned values do not reflect the division performed in line 5. The result is

[0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504]
[0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333]
([2.0, 2.8284271247461903, 3.4641016151377544, 4.0], [2, 8, 18, 32])

I saw a discussion on the Julia forum where a user was having similar issues in a REPL session. But the suggested solution was to either wrap the for loop in a function, which I have already done, or to write the equivalent of global j \= sum(j) in place of line 5, which doesn't change the result.

Similar suggestions appear in this SE question: Changing variable in loop [Julia]

How can I batch modify a and b before returning them?

Upvotes: 2

Views: 83

Answers (1)

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42254

You need to vectorize the division and use a Float64 arg:

function foo(g)
    a = [g * sqrt(i) for i in 1:4]
    b = [g * i ^ 2 for i in 1:4]
    for j in [a, b]
         j ./= sum(j)
         println(j)
         end
    return a, b
end

And now:

julia> foo(2.0)
[0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504]
[0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333]
([0.16270045344786252, 0.2300931878702196, 0.2818054517861928, 0.32540090689572504], [0.03333333333333333, 0.13333333333333333, 0.3, 0.5333333333333333])

Now the tricky explanation

  • when you pass an Int argument than in your code a is a Vector of Float64s and b is a Vector of Ints. Look what happens when you combine them:
    julia> [[1.0,2.0],[1,2]]
     2-element Array{Array{Float64,1},1}:
     [1.0, 2.0]
     [1.0, 2.0]
    
    Julia brings all data to common Float64 and in your case you loose the reference information!
  • j =/ sum(j) is a linear algebra division and it allocates a new object. You want to have an element wise operation so you needed to vectorize.

Upvotes: 1

Related Questions