Values that are used inside of functions come from an outer scope – if they are not defined in any enclosing local scopes, then they are global. In particular, function names are just global constants, so this behavior is really quite important. You wouldn't want to have to declare every function that you're going to call to be global before calling it.
On Sun, Dec 7, 2014 at 3:47 PM, <[email protected]> wrote: > Well indeed that was the problem. Thank you very much. I wasn't aware of > this behavior of Julia, and I didn't even see that n wasn't in the scope of > the function. Somehow I believed that if it were the case an error would be > raised. > > Is there situations where this behavior is wanted? Because I find not > counterintuitive (but maybe it's just me). I would be glad to know more > about the decisions that have lead to this design choice about Julia (or in > other language that could have the same feature). > > Best, > Rémi > > > > On Sunday, December 7, 2014 5:31:40 PM UTC+1, [email protected] wrote: >> >> >> >> Hey guys, >> >> I'm currently playing with some Eratosthenes sieving in Julia, and found >> a strange behavior of memory allocation. >> My naive sieve is as follows: >> >> #= >> Naive version of Erato sieve. >> * bitarray to store primes >> * only eliminate multiples of primes >> * separately eliminate even non-primes >> =# >> function erato1(n::Int) >> # Create bitarray to store primes >> primes_mask = trues(n) >> primes_mask[1] = false >> >> # Eliminate even numbers first >> for i = 4:2:n >> primes_mask[i] = false >> end >> >> # Eliminate odd non-primes numbers >> for i = 3:2:n >> if primes_mask[i] >> for j = (i + i):i:n >> primes_mask[j] = false >> end >> end >> end >> >> # Collect every primes in an array >> n_primes = countnz(primes_mask) >> primes_arr = Array(Int64, n_primes) >> collect1!(primes_mask, primes_arr) >> end >> >> >> With the collect1! function that takes a BitArray as argument and return >> an Array containing the primes numbers. >> >> function collect1!(primes_mask::BitArray{1}, primes_arr::Array{Int64, 1}) >> prime_index = 1 >> for i = 2:n >> if primes_mask[i] >> primes_arr[prime_index] = i >> prime_index += 1 >> end >> end >> return primes_arr >> end >> >> The codes works, but is slow because of a lot of memory allocation at the >> line: >> primes_arr[prime_index] = i >> >> Here is an extract of the memory allocation profile >> (--track-allocation=user): >> >> - function collect1!(primes_mask::BitArray{1}, primes_arr::Array{ >> Int64, 1}) >> 0 prime_index = 1 >> -84934576 for i = 2:n >> 0 if primes_mask[i] >> *184350208* primes_arr[prime_index] = i >> 0 prime_index += 1 >> - end >> - end >> 0 return primes_arr >> - end >> >> >> >> But, if I inline the definition of collect1! into the erato1, this is >> much faster and the allocation in the loop of collect disapears. Here is >> the code updated: >> >> function erato1(n::Int) >> # Create bitarray to store primes >> primes_mask = trues(n) >> primes_mask[1] = false >> >> # Eliminate even numbers first >> for i = 4:2:n >> primes_mask[i] = false >> end >> >> # Eliminate odd non-primes numbers >> for i = 3:2:n >> if primes_mask[i] >> for j = (i + i):i:n >> primes_mask[j] = false >> end >> end >> end >> >> # Collect every primes in an array >> n_primes = countnz(primes_mask) >> primes_arr = Array(Int64, n_primes) >> prime_index = 1 >> for i = 2:n >> if primes_mask[i] >> primes_arr[prime_index] = i >> prime_index += 1 >> end >> end >> return primes_arr >> end >> >> And the memory profile seems more reasonable: >> >> 0 n_primes = countnz(primes_mask) >> 92183392 primes_arr = Array(Int64, n_primes) >> 0 prime_index = 1 >> 0 for i = 2:n >> 0 if primes_mask[i] >> 0 primes_arr[prime_index] = i >> 0 prime_index += 1 >> - end >> - end >> >> >> So I'm wondering why the simple fact of inlining the code would remove >> the massive memory allocation when assigning to the array. >> >> Thank you for your help, >> Rémis >> >
