Julia中为何简单索引变量被Core.Box包裹?
Hey there! Let's tackle this type stability issue with your Sieve of Eratosthenes code. I've run into similar problems before, so I know exactly where to look.
First, let's recap your complete code (filling in the missing bits to make it functional):
function primesum(limit::T = 2_000_000) where T<:Integer # easy way: using Primes; sum(primes(limit)) sieve = trues(limit) sieve[1] = false psum = zero(T) for i in 2:limit if sieve[i] psum += i for j in i*i:i:limit sieve[j] = false end end end return psum end
When you run @code_warntype primesum(2_000_000), you'll see the i variable gets boxed into Core.Box, which messes up the type of psum and makes the entire function type-unstable. Here's why that happens and how to fix it:
The Root Cause
The issue stems from Julia's type inference struggling with the parameterized type T combined with the loop index i. While limit::T defines a UnitRange{T} for 2:limit, Julia can't always guarantee that i will stay strictly as type T during the loop (even if overflow isn't a risk here, inference uncertainty triggers boxing). This boxing propagates to psum since you're adding i to it, breaking type stability.
The Fixes
There are two straightforward ways to resolve this:
1. Explicitly Type the Loop Index
Add a type annotation to i in the outer loop to eliminate inference ambiguity. This is the cleanest solution:
function primesum(limit::T = 2_000_000) where T<:Integer sieve = trues(limit) sieve[1] = false psum = zero(T) for i::T in 2:limit # Explicit type annotation for i if sieve[i] psum += i for j in i*i:i:limit sieve[j] = false end end end return psum end
2. Explicitly Convert i to T When Adding to psum
If you prefer not to annotate the loop index, explicitly converting i to type T when updating psum will also fix the boxing issue:
function primesum(limit::T = 2_000_000) where T<:Integer sieve = trues(limit) sieve[1] = false psum = zero(T) for i in 2:limit if sieve[i] psum += convert(T, i) # Convert i to T explicitly for j in i*i:i:limit sieve[j] = false end end end return psum end
Verify the Fix
Run @code_warntype primesum(2_000_000) again, and you'll see Core.Box is gone—psum maintains its concrete type throughout the function, and the code will run faster without runtime type checks.
One quick side note: if you use smaller integer types like Int32 for limit, i*i might overflow. For the Project Euler problem, Int (64-bit on most systems) is totally safe, but if you need to support smaller types, cast i to a larger type for the inner loop.
内容的提问来源于stack exchange,提问作者Sundar R

