Julia messes up integer exponents?

fyi SafeInt32 is type stable, as are all the SaferInteger types

julia> using SaferIntegers

julia> safe32 = SafeInt32(31); safe32 += 1; safe32, typeof(safe32)
(32, SafeInt32)

or just 10.0^N

If you mean to check arithmetic operations syntactically present in user’s code, I guess it can be done already with a module exporting checked version of these operations? You can put using CheckedArithmetics (say) in the beginning of the module (maybe with if ENV["CHECK_ARITHMETICS"] == "true" ... end so that it’s easier to turn on/off). I used the same trick to change the associativity of *.

That’s probably not an unreasonable comment. Maybe that adding a note about integer overflow to common Julia 101 tutorials would be useful. I’ve just made a PR to learn x in y minutes for this.

2 Likes

As a couple tests, first a dead-simple function to vectorize (dot product):

julia> using SaferIntegers, BenchmarkTools

julia> function my_dot(x, y)
           out = zero(promote_type(eltype(x), eltype(y)))
           @inbounds @simd ivdep for i in eachindex(x, y)
               out += x[i] * y[i]
           end
           out
       end
my_dot (generic function with 1 method)

julia> function my_dot_safeint(x, y)
           out = zero(promote_type(eltype(x), eltype(y)))
           N = SafeInt64(min(length(x),length(y)))
           @inbounds @simd ivdep for i in 1:N
               out += x[i] * y[i]
           end
           out
       end
my_dot_safeint (generic function with 1 method)

julia> x = rand(Float32, 512);

julia> y = rand(Float32, 512);

julia> @btime $x' * $y
  24.058 ns (0 allocations: 0 bytes)
125.47223f0

julia> @btime my_dot($x, $y)
  13.664 ns (0 allocations: 0 bytes)
125.47223f0

julia> @btime my_dot_safeint($x, $y)
  14.930 ns (0 allocations: 0 bytes)
125.47223f0

And the compiler can still vectorize.
Make things just a little more complicated:

julia> using SLEEF #I am currently on the SIMDPirates branch

julia> function my_exp!(x, y)
           @inbounds for i in eachindex(x, y)
               x[i] = SLEEF.exp(y[i])
           end
       end
my_exp! (generic function with 1 method)

julia> function my_exp_safeint!(x, y)
           N = SafeInt64(min(length(x),length(y)))
           @inbounds for i in 1:N
               x[i] = SLEEF.exp(y[i])
           end
       end
my_exp_safeint! (generic function with 1 method)

julia> @btime my_exp!($x, $y)
  146.227 ns (0 allocations: 0 bytes)

julia> all(x .≈ exp.(y))
true

julia> @btime my_exp_safeint!($x, $y)
  1.953 μs (0 allocations: 0 bytes)

julia> all(x .≈ exp.(y))
true

julia> 1.953 / 146.227 * 1e3
13.355946576213695

and it does not, and we see an > 13-fold regression.
The computer I tested on has avx512, which means 16 Float32 per SIMD unit.

1 Like

Did you file an issue? Please link it!

https://github.com/JuliaLang/julia/issues/31143

1 Like