On Monday, December 8, 2014 6:15:37 PM UTC+10, [email protected] wrote:
>
> Thank you for the explanation Stefan.
> But isn't it possible to just consider the scopes declared inside of a 
> function + the global scope while looking for a variable definition? I find 
> the fact that the variable can come from the scope in which the function is 
> called strange.
>

It can come from the scope in which the function is defined, not the scope 
in which it is called, 
see 
http://docs.julialang.org/en/latest/manual/variables-and-scoping/#scope-of-variables

Cheers
Lex
 

>
>
> Le dimanche 7 décembre 2014 22:03:59 UTC+1, Stefan Karpinski a écrit :
>>
>> 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
>>>>
>>>
>>

Reply via email to