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.


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] <javascript:>> 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