Issue 1:
After I extracted the child_loop() inner function (aka "closure") from the first program (which had two pieces of duplicate code) it makes the code much slower: from under 3seconds to over a minute). This code is a solution I wrote to one of the Project Euler problems and it is pure/core Julia. I am using x86-64 mageia 8 Linux, but the issue happens also on Fedora 32 x86-64.

The code before the change (without the slowdown):

const CHECK = false
function brute_my_calc(start_, end_, x0)
sum_ = 0
count_ = 0
for n in (start_:end_)
count_ += 1
prev = x0
next_ = ((prev + cld(n, prev)) >> 1)
while prev != next_
sum_ += 1
prev = next_
next_ = ((prev + cld(n, prev)) >> 1)
end
end
return sum_, count_
end

function check(start_, end_, x0, have_sum, have_count)
if CHECK
gs, gc = brute_my_calc(start_, end_, x0)
@assert (have_sum, have_count) == (gs, gc)
end
end

function my_calc(start_, end_, x0)
@assert start_ <= end_
count_ = end_ - start_ + 1
sum_ = Int64(0)
sofar_ = Int64(0)

x0inv = cld(start_, x0)
next_x0inv = x0inv * x0
identity_n_low = x0*x0 - x0 + 1
identity_n = x0*x0 + x0
twice_first_next = x0 + x0inv
first_next = twice_first_next >> 1
limit = max(start_-1, min(identity_n_low-1, end_))
if (first_next == x0 && end_ < next_x0inv)
sum_ = 0
check(start_, end_, x0, sum_, count_)
return sum_, count_
end
@assert identity_n_low <= identity_n

function calc_child_sum(n, end_next, first_next)
@assert end_next >= n
subsum_, subcount_ = my_calc(n, end_next, first_next)
@assert subcount_ == end_next-n+1
@assert subsum_ >= 0
subsum_ += subcount_
check(n, end_next, x0, subsum_, subcount_)
return subsum_, subcount_
end

n = start_
while n <= limit
if next_x0inv < n
next_x0inv += x0
twice_first_next += 1
first_next = twice_first_next >> 1
@assert next_x0inv >= n
if twice_first_next & 0b1 == 0
twice_first_next += 1
next_x0inv += x0
end
end

end_next = next_x0inv
if end_next > limit
end_next = limit
end

subsum_, subcount_ = calc_child_sum(n, end_next, first_next)
sum_ += subsum_
sofar_ += subcount_
check(start_, end_next, x0, sum_, sofar_)
n = end_next + 1
end

check(start_, limit, x0, sum_, sofar_)
@assert n == limit + 1
start2 = max(start_, min(end_, limit + 1))
limit2 = max(start_, min(end_, identity_n))
if limit2 >= start2 && start2 >= n
diff = limit2 - start2 + 1
sofar_ += diff
@assert sofar_ == limit2 - start_ + 1
check(start_, limit2, x0, sum_, sofar_)
end
if limit2 != end_
start3 = limit2 + 1
while start3 > next_x0inv
next_x0inv += x0
twice_first_next += 1
end
first_next = twice_first_next >> 1
initsofar_ = sofar_

n = start3
while n <= end_
if next_x0inv < n
next_x0inv += x0
twice_first_next += 1
first_next = twice_first_next >> 1
@assert next_x0inv >= n
if twice_first_next & 0b1 == 0
twice_first_next += 1
next_x0inv += x0
end
end

end_next = next_x0inv
if end_next > end_
end_next = end_
end

subsum_, subcount_ = calc_child_sum(n, end_next, first_next)
sum_ += subsum_
sofar_ += subcount_
check(start_, end_next, x0, sum_, sofar_)
n = end_next + 1
end
end

@assert sum_ >= 0
@assert count_ == sofar_
check(start_, end_, x0, sum_, sofar_)
return sum_, count_
end

function digit_wrapper(dd)
d = Int64(0+dd)
start_ = Int64(10^(d-1))
end_ = Int64(10*start_-1)
if d % 2 == 0
x0 = 7 * (10^((d-2)>>1))
else
x0 = 2 * (10^((d-1)>>1))
end
x0 = Int64(x0)
sum_, count_ = my_calc(start_, end_, x0)
sum_+=count_
@assert count_ == end_ - start_ + 1
return sum_, count_
end

function digit_average(dd)
sum_, count_ = digit_wrapper(dd)
@show dd, sum_, count_
return sum_ / count_
end
ret = digit_average(5)
@show ret
@assert abs(ret - 3.2102888889) < 0.0000001
if true
ret = digit_average(14)
@show ret
end

The program after the change (with the slowdown):

const CHECK = false
function brute_my_calc(start_, end_, x0)
sum_ = 0
count_ = 0
for n in (start_:end_)
count_ += 1
prev = x0
next_ = ((prev + cld(n, prev)) >> 1)
while prev != next_
sum_ += 1
prev = next_
next_ = ((prev + cld(n, prev)) >> 1)
end
end
return sum_, count_
end

function check(start_, end_, x0, have_sum, have_count)
if CHECK
gs, gc = brute_my_calc(start_, end_, x0)
@assert (have_sum, have_count) == (gs, gc)
end
end

function my_calc(start_, end_, x0)
@assert start_ <= end_
count_ = end_ - start_ + 1
sum_ = Int64(0)
sofar_ = Int64(0)

x0inv = cld(start_, x0)
next_x0inv = x0inv * x0
identity_n_low = x0*x0 - x0 + 1
identity_n = x0*x0 + x0
twice_first_next = x0 + x0inv
first_next = twice_first_next >> 1
limit = max(start_-1, min(identity_n_low-1, end_))
if (first_next == x0 && end_ < next_x0inv)
sum_ = 0
check(start_, end_, x0, sum_, count_)
return sum_, count_
end
@assert identity_n_low <= identity_n

function calc_child_sum(n, end_next, first_next)
@assert end_next >= n
subsum_, subcount_ = my_calc(n, end_next, first_next)
@assert subcount_ == end_next-n+1
@assert subsum_ >= 0
subsum_ += subcount_
check(n, end_next, x0, subsum_, subcount_)
return subsum_, subcount_
end

n = start_
function child_loop(start3, limit3)
# @show start3, limit3
n = start3
while n <= limit3
if next_x0inv < n
next_x0inv += x0
twice_first_next += 1
first_next = twice_first_next >> 1
@assert next_x0inv >= n
if twice_first_next & 0b1 == 0
twice_first_next += 1
next_x0inv += x0
end
end

end_next = next_x0inv
if end_next > limit3
end_next = limit3
end

subsum_, subcount_ = calc_child_sum(n, end_next, first_next)
sum_ += subsum_
sofar_ += subcount_
check(start_, end_next, x0, sum_, sofar_)
n = end_next + 1
end
end

child_loop(start_, limit)

check(start_, limit, x0, sum_, sofar_)
start2 = max(start_, min(end_, limit + 1))
limit2 = max(start_, min(end_, identity_n))
if limit2 >= start2 && start2 >= limit + 1
diff = limit2 - start2 + 1
sofar_ += diff
@assert sofar_ == limit2 - start_ + 1
check(start_, limit2, x0, sum_, sofar_)
end
if limit2 != end_
start3 = limit2 + 1
while start3 > next_x0inv
next_x0inv += x0
twice_first_next += 1
end
first_next = twice_first_next >> 1
initsofar_ = sofar_

child_loop(start3, end_)
end

@assert sum_ >= 0
@assert count_ == sofar_
check(start_, end_, x0, sum_, sofar_)
return sum_, count_
end

function digit_wrapper(dd)
d = Int64(0+dd)
start_ = Int64(10^(d-1))
end_ = Int64(10*start_-1)
if d % 2 == 0
x0 = 7 * (10^((d-2)>>1))
else
x0 = 2 * (10^((d-1)>>1))
end
x0 = Int64(x0)
sum_, count_ = my_calc(start_, end_, x0)
sum_+=count_
@assert count_ == end_ - start_ + 1
return sum_, count_
end

function digit_average(dd)
sum_, count_ = digit_wrapper(dd)
@show dd, sum_, count_
return sum_ / count_
end
ret = digit_average(5)
@show ret
@assert abs(ret - 3.2102888889) < 0.0000001
if true
ret = digit_average(14)
@show ret
end

I tried running both codes several times in succession (and got similar results).

Thanks for any help or insights and let me know if I can prove of any further help.

Julia seems useful and nice so far, so thanks for your past and future work.

Issue 2:
In Julia 0.6 I get:

julia> digits(0,2,0)
0-element Array{Int64,1}

julia> digits(0,3,0)
1-element Array{Int64,1}:
0

I think both should return a vector of length 0. This is the behavior in Julia 0.5 for all bases and in Julia 0.6 for the special cases where the base is 2, 8, 10, and 16. The source code for the digits function did not change between Julia 0.5 and 0.6, but the code for the ndigits0z function did change.