-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make factor work for Int128, UInt128, BigInt #1951
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,6 +1,6 @@ | ||||||
############################################################################### | ||||||
# | ||||||
# Flint factor(s) functiosn | ||||||
# Flint factor(s) functions | ||||||
# | ||||||
############################################################################### | ||||||
|
||||||
|
@@ -17,20 +17,39 @@ function _factor(a::ZZRingElem) | |||||
return res, canonical_unit(a) | ||||||
end | ||||||
|
||||||
# Just to give a helpful error message if someone tries to factor a boolean | ||||||
function factor(b::Bool) | ||||||
throw(DomainError("Cannot factorize a boolean")); | ||||||
end | ||||||
|
||||||
# This function handles machine integer types (up to 64 bits) | ||||||
function factor(a::T) where T <: Union{Int, UInt} | ||||||
iszero(a) && throw(ArgumentError("Argument must be non-zero")) | ||||||
u = sign(a) | ||||||
a = u < 0 ? -a : a | ||||||
F = n_factor() | ||||||
@ccall libflint.n_factor(F::Ref{n_factor}, a::UInt)::Nothing | ||||||
res = Dict{T, Int}() | ||||||
res = Dict{T, Int}() # factor-multiplicity pairs | ||||||
for i in 1:F.num | ||||||
z = F.p[i] | ||||||
res[z] = F.exp[i] | ||||||
end | ||||||
return Fac(u, res) | ||||||
end | ||||||
|
||||||
# This is supposed to be called only for T in [Int128, UInt128, BigInt] | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really understand this comment. The code clearly can also be called for e.g. |
||||||
function factor(a::T) where T <: Integer | ||||||
iszero(a) && throw(ArgumentError("Argument must be non-zero")) | ||||||
u = sign(a) | ||||||
F = factor(ZZ(abs(a))) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing you could try in a follow-up PR: if
Suggested change
Check out the docstring for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the hint. Note that |
||||||
res = Dict{T, Int}() # factor-multiplicity pairs | ||||||
for (fac,exp) in F.fac | ||||||
res[T(fac)] = exp | ||||||
end | ||||||
return Fac(u, res) | ||||||
end | ||||||
|
||||||
|
||||||
################################################################################ | ||||||
# | ||||||
# ECM | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,59 @@ | ||||||
|
||||||
@testset "Integer factorization" begin | ||||||
|
||||||
@test_throws ArgumentError factor(0) | ||||||
@test_throws ArgumentError factor(Int128(0)) | ||||||
@test_throws ArgumentError factor(UInt128(0)) | ||||||
@test_throws ArgumentError factor(BigInt(0)) | ||||||
@test_throws ArgumentError factor(ZZ(0)) | ||||||
|
||||||
|
||||||
@test_throws DomainError factor(true) | ||||||
@test_throws DomainError factor(false) | ||||||
|
||||||
|
||||||
# trivial case: input is 1 | ||||||
F1 = factor(1) | ||||||
F1_ZZ = factor(ZZ(1)) | ||||||
@test length(F1.fac) == 0 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
this should work There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, thanks for the suggested clean up. I have just checked in the relevant changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JohnAAbbott Maybe you checked them in but did not push them? They don't appear to be in the merged code. Perhaps send a follow-up PR to clean that up? |
||||||
@test length(F1_ZZ.fac) == 0 | ||||||
@test unit(F1) == 1 | ||||||
@test unit(F1_ZZ) == 1 | ||||||
|
||||||
|
||||||
# Test different integer types | ||||||
F = factor(123456789) | ||||||
F_Int128 = factor(Int128(123456789)) | ||||||
F_UInt128 = factor(UInt128(123456789)) | ||||||
F_BigInt = factor(BigInt(123456789)) | ||||||
F_ZZ = factor(ZZ(123456789)) | ||||||
|
||||||
@test length(F.fac) == 3 | ||||||
@test length(F_Int128.fac) == 3 | ||||||
@test length(F_UInt128.fac) == 3 | ||||||
@test length(F_BigInt.fac) == 3 | ||||||
@test length(F_ZZ.fac) == 3 | ||||||
|
||||||
@test unit(F) == 1 | ||||||
@test unit(F_Int128) == 1 | ||||||
@test unit(F_UInt128) == 1 | ||||||
@test unit(F_BigInt) == 1 | ||||||
@test unit(F_ZZ) == 1 | ||||||
|
||||||
|
||||||
# an example with two "large" factors | ||||||
repunit37 = ZZ(10)^37 -1 | ||||||
repunit41 = ZZ(10)^41 -1 | ||||||
FF = factor(repunit37*repunit41) # trickier but still quick | ||||||
@test length(FF.fac) == 8 | ||||||
|
||||||
|
||||||
# negative input | ||||||
F_minus1 = factor(-1) | ||||||
F_minus1_ZZ = factor(ZZ(-1)) | ||||||
@test length(F_minus1.fac) == 0 | ||||||
@test length(F_minus1_ZZ.fac) == 0 | ||||||
@test unit(F_minus1) == -1 | ||||||
@test unit(F_minus1_ZZ) == -1 | ||||||
|
||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is actually incorrect if
a == typemin(Int)
, as then-a == a
and we get an error casting that negative value toUInt
.But instead of fixing this locally, I suggest a slightly bigger change which then also allows avoiding creating Dictionaries twice:
Change this function to look like roughly this (might contain syntax errors):
I.e. the caller can specify
T
.Then continue:
Of course the final function is also not optimal, better would be to modify
function factor(N::ZZRingElem)
to takeT
as argument and use it, but that could be done later (in any case this is no worse than what your code right now).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided not to alter
factor(::ZZRingElem)
whose implementation is "special" (and possibly fragile?).