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 >>>> >>> >>
