Skip to content

Commit 4c6c642

Browse files
committed
Widening depend on modulus
1 parent cfd46ed commit 4c6c642

File tree

4 files changed

+111
-9
lines changed

4 files changed

+111
-9
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Mods"
22
uuid = "7475f97c-0381-53b1-977b-4c60186c8d62"
33
author = ["Edward Scheinerman <[email protected]>"]
4-
version = "2.2.2"
4+
version = "2.2.3"
55

66
[compat]
77
julia = "1"

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,25 @@ likely to give incorrect results, version 1 of this module was buggy.
3434

3535
Users who require *smaller* integer (e.g., `Int8`) types should use the latest version 1 of `Mods`.
3636

37-
> **NEW!** For `Int8` moduli (between 2 and 127) see the [MiniMods](https://github.com/scheinerman/MiniMods.jl) module.
37+
> **NEW!** For small moduli (between 2 and 255) see the [MiniMods](https://github.com/scheinerman/MiniMods.jl) module.
3838
3939
In addition, some functionality has been moved to the `extras` folder.
4040
See the `README` there.
4141

42+
### New in 2.2.3
43+
44+
The values of `Mod` number is held in 64-bit integers. If the moduli and values are
45+
large enough, integer arithmetic might overlow and yield incorrect results. To deal
46+
with this, integer values are expanded to 128 bits in order to ensure correctness,
47+
and then reduced by the modulus.
48+
49+
In prior versions, we always expanded values to 128 bits before arithmetic.
50+
51+
Starting in version 2.2.3, expansion to 128 bits only happens for moduli above
52+
`typemax(Int32)` which equals `2^31 - 1 = 2,147,483,647`. This results in a
53+
roughly 4 or 5 times speed compared to prior versions.
54+
55+
4256

4357
## Quick Overview
4458
This module supports modular values and arithmetic. The moduli are integers (at least 2)

src/arithmetic.jl

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
1-
(+)(a::Mod{N}, b::Mod{N}) where {N} = Mod{N}(widen(value(a)) + widen(value(b)))
2-
(+)(a::GaussMod{N}, b::GaussMod{N}) where {N} = Mod{N}(widen(value(a)) + widen(value(b)))
1+
# (+)(a::Mod{N}, b::Mod{N}) where {N} = Mod{N}(widen(a.val) + widen(b.val))
2+
# (+)(a::GaussMod{N}, b::GaussMod{N}) where {N} = Mod{N}(widen(a.val) + widen(b.val))
33

4-
(-)(a::Mod{N}) where {N} = Mod{N}(-value(a))
5-
(-)(a::GaussMod{N}) where {N} = GaussMod{N}(-value(a))
4+
function (+)(a::Mod{N}, b::Mod{N}) where {N}
5+
N <= typemax(Int32) ? Mod{N}(a.val + b.val) : Mod{N}(widen(a.val) + widen(b.val))
6+
end
7+
function (+)(a::GaussMod{N}, b::GaussMod{N}) where {N}
8+
N <= typemax(Int32) ? Mod{N}((a.val) + (b.val)) :
9+
GaussMod{N}(widen(a.val) + widen(b.val))
10+
end
11+
12+
13+
14+
(-)(a::Mod{N}) where {N} = Mod{N}(N - a.val)
15+
(-)(a::GaussMod{N}) where {N} = GaussMod{N}(N - a.val)
616

717
(-)(a::AbstractMod, b::AbstractMod) = a + (-b)
818

9-
(*)(a::Mod{N}, b::Mod{N}) where {N} = Mod{N}(widen(value(a)) * widen(value(b)))
10-
(*)(a::GaussMod{N}, b::GaussMod{N}) where {N} =
11-
GaussMod{N}(widen(value(a)) * widen(value(b)))
19+
# (*)(a::Mod{N}, b::Mod{N}) where {N} = Mod{N}(widemul(a.val, b.val))
20+
# (*)(a::GaussMod{N}, b::GaussMod{N}) where {N} = GaussMod{N}(widemul(a.val, b.val))
21+
22+
23+
function (*)(a::Mod{N}, b::Mod{N}) where {N}
24+
N <= typemax(Int32) ? Mod{N}(a.val * b.val) : Mod{N}(widemul(a.val, b.val))
25+
end
26+
function (*)(a::GaussMod{N}, b::GaussMod{N}) where {N}
27+
N <= typemax(Int32) ? GaussMod{N}(a.val * b.val) : GaussMod{N}(widemul(a.val, b.val))
28+
end
1229

1330
"""
1431
is_invertible(a::AbstractMod)::Bool

test/speed_test.jl

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Mods, BenchmarkTools, LinearAlgebra, LinearAlgebraX
2+
3+
# m = typemax(Int32) - 18 # this is a big prime but < 2^31 - 1
4+
# d = 500
5+
6+
function speed_test(m, d)
7+
8+
A = rand(Mod{m}, d, d)
9+
10+
@info "modulus = $m, matrix size = $d"
11+
12+
@info "Determinant"
13+
@btime det(A)
14+
15+
@info "Rank"
16+
@btime rankx(A)
17+
18+
@info "Inverse"
19+
@btime inv(A)
20+
21+
@info "Multiplication"
22+
@btime A * A * A
23+
24+
AA = value.(A)
25+
@show A^3 == AA^3 # this should be false if big enough
26+
nothing
27+
end
28+
29+
## RESULT WITH NO CHANGE IN CODE
30+
# [ Info: modulus = 2147483629, matrix size = 500
31+
# [ Info: Determinant
32+
# 1.260 s (4 allocations: 1.91 MiB)
33+
# [ Info: Rank
34+
# 1.685 s (256007 allocations: 1001.13 MiB)
35+
# [ Info: Inverse
36+
# 6.202 s (8 allocations: 5.73 MiB)
37+
# [ Info: Multiplication
38+
# 5.557 s (12 allocations: 3.87 MiB)
39+
40+
## RESULTS WITH REMOVING widemul and widen
41+
# [ Info: modulus = 2147483629, matrix size = 500
42+
# [ Info: Determinant
43+
# 156.085 ms (4 allocations: 1.91 MiB)
44+
# [ Info: Rank
45+
# 329.689 ms (256007 allocations: 1001.13 MiB)
46+
# [ Info: Inverse
47+
# 1.444 s (8 allocations: 5.73 MiB)
48+
# [ Info: Multiplication
49+
# 1.215 s (12 allocations: 3.87 MiB)
50+
51+
## RESULTS WITH NEW CONTINGENT CODE
52+
# [ Info: modulus = 2147483629, matrix size = 500 <-- mod is < 2^31
53+
# [ Info: Determinant
54+
# 11.625 μs (3 allocations: 3.48 KiB)
55+
# [ Info: Rank
56+
# 30.292 μs (594 allocations: 103.02 KiB)
57+
# [ Info: Inverse
58+
# 128.041 μs (5 allocations: 10.19 KiB)
59+
# [ Info: Multiplication
60+
# 61.791 μs (8 allocations: 47.53 KiB)
61+
62+
# [ Info: modulus = 8589934609, matrix size = 500 <-- mod is > 2^32
63+
# [ Info: Determinant
64+
# 71.791 μs (3 allocations: 3.48 KiB)
65+
# [ Info: Rank
66+
# 125.250 μs (594 allocations: 103.02 KiB)
67+
# [ Info: Inverse
68+
# 409.250 μs (5 allocations: 10.19 KiB)
69+
# [ Info: Multiplication
70+
# 359.625 μs (8 allocations: 47.53 KiB)
71+
# A ^ 3 == AA ^ 3 = false

0 commit comments

Comments
 (0)