JuliaSIMD / JuliaSIMD/LoopVectorization.jl

`@turbo` gives wrong output with `%()` (in some cases) but correct with `mod()`

Open
#542 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Julia
Stars
789
Forks
73
PR merge metrics
No merged PRs in 30d

Description

Hi,

I've run into a weird issue with some modulo operations in ***some*** loops using `@turbo`.

The loop is essentially this:
```Julia
@turbo for kk in eachindex(results)
results[kk] = (results[kk] * bases[kk]) % m
end
```

It works most of the time (and with most inputs) but not always. Here's a script below with some test cases:

```Julia
using LoopVectorization
using Test

function test!(f!::Function, results::AbstractVector{UInt32})
bases = copy(results)
results .= UInt32(1)
e, m = 437, 6059

for ii in 1 : Int(ceil(log(Float64(e)) / log(2)))
if (e >> (ii - 1)) & 1 == 1
f!(results, bases, m)
end

# For some loop in this loop @turbo works fine, even if it also has mod(x, m)
@turbo for jj in eachindex(bases)
v = bases[jj]
bases[jj] = (v * v) % m
end
end

return results
end
function f1!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] = (results[kk] * bases[kk]) % m
end
end
function f2!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] *= bases[kk]
end
@turbo for kk in eachindex(results)
results[kk] %= m
end
end
function f3!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] *= bases[kk]
end

# Somehow adding @turbo to this loop makes it give wrong result
for kk in eachindex(results)
results[kk] %= m
end
end
function f4!(results::AbstractVector{UInt32}, bases::AbstractVector{UInt32}, m::Integer)
@turbo for kk in eachindex(results)
results[kk] = mod(results[kk] * bases[kk], m) # !!! using mod() instead of % gives correct result
end
end

@testset "tests" begin
@test powermod(82, 437, 6059) == 5394 # Validation

@test Int.(test!(f1!, UInt32.([82]))) == [5394] # <- Wrong
@test Int.(test!(f2!, UInt32.([82]))) == [5394] # <- Still wrong

@test Int.(test!(f3!, UInt32.([82]))) == [5394] # This one is correct
@test Int.(test!(f4!, UInt32.([82]))) == [5394] # !!!Somehow this is also correct

# Below (different input) is correct for all
@test powermod(80, 437, 6059) == 3667 # Validation
@test Int.(test!(f1!, UInt32.([80]))) == [3667]
@test Int.(test!(f2!, UInt32.([80]))) == [3667]
@test Int.(test!(f3!, UInt32.([80]))) == [3667]
@test Int.(test!(f4!, UInt32.([80]))) == [3667]
end
```

- In the `test!` function there's 2 loops doing similar operations (just different inputs), I haven't found an issue with the 2nd loop yet
- I've separated operations into separate loops to track down (`f2!` and `f3!`) - the issue seems to come from modulo operation
- Wrong result seems to be rare (most inputs are ok) but they do happen
- Using `mod()` instead of `%()` fixes the issue

Results on my laptop below (although I see the same on 2 different machines - different CPUs, both on windows)
```Julia
tests: Test Failed at c:\Users\titas\Code\AeroMap.jl\WIP\test.jl:66
Expression: Int.(test!(f1!, UInt32.([82]))) == [5394]
Evaluated: [2068] == [5394]

tests: Test Failed at c:\Users\titas\Code\AeroMap.jl\WIP\test.jl:67
Expression: Int.(test!(f2!, UInt32.([82]))) == [5394]
Evaluated: [2068] == [5394]

Test Summary: | Pass Fail Total Time
tests | 8 2 10 0.4s
ERROR: Some tests did not pass: 8 passed, 2 failed, 0 errored, 0 broken.
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.