Skip to content

Commit 5a27205

Browse files
authored
Add iroot and check parameter to root for Integer. (#939)
* Add iroot and check parameter to root for Integer. * Switch to default check=true and fix bug. * Add ispower and ispower_with_root for BigInt (untested). * Implement ispower and ispower_with_root for integer types.
1 parent 4f53ea2 commit 5a27205

File tree

4 files changed

+247
-15
lines changed

4 files changed

+247
-15
lines changed

docs/src/integer.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,16 @@ AbstractAlgebra.sqrt(a::BigInt)
147147
issquare(a::BigInt)
148148
```
149149

150+
```@docs
151+
root(a::BigInt)
152+
iroot(a::BigInt)
153+
```
154+
155+
```@docs
156+
ispower(a::BigInt)
157+
ispower_with_root(a::BigInt)
158+
```
159+
150160
```@docs
151161
AbstractAlgebra.exp(a::BigInt)
152162
```

src/AbstractAlgebra.jl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ import .Generic: abs_series, abs_series_type,
439439
isone, isreverse, isrimhook, issubmodule,
440440
isunit,
441441
laurent_ring, lcm, leading_coefficient, leading_monomial,
442-
leading_term, length,
442+
leading_term, length,
443443
leglength, main_variable,
444444
main_variable_extract, main_variable_insert,
445445
map1, map2, map_from_func,
@@ -451,25 +451,25 @@ import .Generic: abs_series, abs_series_type,
451451
monomial_iszero, monomial_set!,
452452
MPolyBuildCtx, mullow_karatsuba,
453453
ngens, norm, normalise,
454-
num_coeff, one,
454+
num_coeff, one,
455455
order, ordering, parity, partitionseq, Perm, perm,
456456
permtype, @perm_str, polcoeff, poly, poly_ring,
457457
precision, preimage, preimage_map,
458-
prime, push_term!,
458+
prime, push_term!,
459459
rand_ordering, reduce!,
460460
rels, rel_series, rel_series_type,
461-
rescale!, retraction_map, reverse,
461+
rescale!, retraction_map, reverse,
462462
right_kernel, rowlength, section_map, setcoeff!,
463463
set_exponent_vector!, set_limit!,
464464
setpermstyle, size,
465465
sort_terms!, summands,
466466
supermodule, term, terms, total_degree,
467467
to_univariate, trailing_coefficient,
468-
truncate, upscale, var_index,
468+
truncate, upscale, var_index,
469469
zero,
470470
# Moved from Hecke into Misc
471-
Loc, Localization, LocElem,
472-
roots, sturm_sequence
471+
Loc, Localization, LocElem,
472+
roots, sturm_sequence
473473

474474
# Do not export inv, div, divrem, exp, log, sqrt, numerator and denominator as we define our own
475475
export abs_series, abs_series_type,
@@ -499,7 +499,7 @@ export abs_series, abs_series_type,
499499
issubmodule, issymmetric,
500500
isterm_recursive, isunit, iszero,
501501
lcm, leading_coefficient, leading_monomial, leading_term,
502-
length,
502+
length,
503503
main_variable, main_variable_extract, main_variable_insert,
504504
mat, matrix_repr, max_fields, mod,
505505
monomial, monomial!, monomials,
@@ -508,18 +508,18 @@ export abs_series, abs_series_type,
508508
mul_ks, mul_red!, mullow_karatsuba, mulmod,
509509
needs_parentheses, newton_to_monomial!, ngens,
510510
normalise, nullspace, num_coeff,
511-
one, order, ordering,
511+
one, order, ordering,
512512
parent_type, parity, partitionseq, Perm, perm, permtype,
513513
@perm_str, polcoeff, polynomial, poly,
514-
poly_ring, pow_multinomial,
514+
poly_ring, pow_multinomial,
515515
ppio, precision, preimage, prime,
516-
push_term!, rank,
516+
push_term!, rank,
517517
rand_ordering, reduce!,
518518
renormalize!, rel_series, rel_series_type, rels,
519-
resultant, resultant_ducos,
519+
resultant, resultant_ducos,
520520
resultant_euclidean, resultant_subresultant,
521521
resultant_sylvester, resx, reverse, rowlength,
522-
setcoeff!, set_exponent_vector!,
522+
setcoeff!, set_exponent_vector!,
523523
setpermstyle,
524524
size, sort_terms!, subst, summands, supermodule,
525525
sylvester_matrix, term, terms, to_univariate,
@@ -528,8 +528,8 @@ export abs_series, abs_series_type,
528528
MatrixElem, PolynomialElem,
529529
# Moved from Hecke into Misc
530530
divexact_low, divhigh,
531-
ismonic, Loc, Localization, LocElem, mulhigh_n,
532-
PolyCoeffs, roots, sturm_sequence
531+
ismonic, Loc, Localization, LocElem, mulhigh_n,
532+
PolyCoeffs, roots, sturm_sequence
533533

534534
# TODO remove these two once removed from dependent packages (Hecke)
535535
export displayed_with_minus_in_front, show_minus_one

src/julia/Integer.jl

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#
55
###############################################################################
66

7+
export iroot, ispower, ispower_with_root, root
8+
79
###############################################################################
810
#
911
# Data type and parent object methods
@@ -177,6 +179,159 @@ function issquare(a::T) where T <: Integer
177179
return a == s*s
178180
end
179181

182+
###############################################################################
183+
#
184+
# Root
185+
#
186+
###############################################################################
187+
188+
function root(a::BigInt, n::Int; check::Bool=true)
189+
a < 0 && iseven(n) && throw(DomainError((a, n),
190+
"Argument `a` must be positive if exponent `n` is even"))
191+
n <= 0 && throw(DomainError(n, "Exponent must be positive"))
192+
z = BigInt()
193+
exact = Bool(ccall((:__gmpz_root, :libgmp), Cint,
194+
(Ref{BigInt}, Ref{BigInt}, Cint), z, a, n))
195+
check && !exact && error("Not a perfect n-th power (n = $n)")
196+
return z
197+
end
198+
199+
@doc Markdown.doc"""
200+
root(a::T, n::Int; check::Bool=true) where T <: Integer
201+
202+
Return the $n$-th root of $a$. If `check=true` the function will test if the
203+
input was a perfect $n$-th power, otherwise an exception will be raised. We
204+
require $n > 0$ and also $a \geq 0$ if $n$ is even.
205+
"""
206+
function root(a::T, n::Int; check::Bool=true) where T <: Integer
207+
if n == 2
208+
a < 0 && throw(DomainError((a, n),
209+
"Argument `a` must be positive if exponent `n` is even"))
210+
s = isqrt(a)
211+
exact = true
212+
if check
213+
r = a - s*s
214+
exact = r == 0
215+
!exact && error("Not a perfect n-th power (n = $n)")
216+
end
217+
return s
218+
else
219+
return T(root(BigInt(a), n; check=check))
220+
end
221+
end
222+
223+
moduli3 = [7, 8, 13]
224+
residues3 = [[0, 1, 6], [0, 1, 3, 5, 7], [0, 1, 5, 8, 12]]
225+
226+
moduli5 = [8, 11, 31]
227+
residues5 = [[0, 1, 3, 5, 7], [0, 1, 10], [0, 1, 5, 6, 25, 26, 30]]
228+
229+
moduli7 = [8, 29, 43]
230+
residues7 = [[0, 1, 3, 5, 7], [0, 1, 12, 17, 28], [0, 1, 6, 7, 36, 37, 42]]
231+
232+
function ispower_moduli(a::Integer, n::Int)
233+
if mod(n, 3) == 0
234+
for i = 1:length(moduli3)
235+
if !(mod(a, moduli3[i]) in residues3[i])
236+
return false
237+
end
238+
end
239+
elseif (n % 5) == 0
240+
for i = 1:length(moduli5)
241+
if !(mod(a, moduli5[i]) in residues5[i])
242+
return false
243+
end
244+
end
245+
elseif (n % 3) == 0
246+
for i = 1:length(moduli7)
247+
if !(mod(a, moduli7[i]) in residues7[i])
248+
return false
249+
end
250+
end
251+
elseif isodd(n)
252+
if !(mod(a, moduli5[1]) in residues5[1])
253+
return false
254+
end
255+
end
256+
return true
257+
end
258+
259+
@doc Markdown.doc"""
260+
ispower_with_root(a::T, n::Int) where T <: Integer
261+
262+
Return `true, q` if $a$ is a perfect $n$-th power with $a = q^n$. Otherwise
263+
return `false, 0`. We require $n > 0$.
264+
"""
265+
function ispower_with_root(a::T, n::Int) where T <: Integer
266+
n <= 0 && throw(DomainError(n, "exponent n must be positive"))
267+
if n == 1 || a == 0 || a == 1
268+
return (true, a)
269+
elseif a == -1
270+
return isodd(n) ? (true, a) : (false, zero(T))
271+
elseif mod(n, 2) == 0 && a < 0
272+
return false, zero(BigInt)
273+
elseif !ispower_moduli(a, n)
274+
return (false, zero(BigInt))
275+
end
276+
277+
q = BigInt()
278+
r = BigInt()
279+
ccall((:__gmpz_rootrem, :libgmp), Nothing,
280+
(Ref{BigInt}, Ref{BigInt}, Ref{BigInt}, Int), q, r, a, n)
281+
return iszero(r) ? (true, T(q)) : (false, zero(T))
282+
end
283+
284+
@doc Markdown.doc"""
285+
ispower(a::T, n::Int) where T <: Integer
286+
287+
Return `true` if $a$ is a perfect $n$-th power, i.e. if there is an integer $b$
288+
such that $a = b^n$. We require $n > 0$.
289+
"""
290+
function ispower(a::T, n::Int) where T <: Integer
291+
n <= 0 && throw(DomainError(n, "n is not positive"))
292+
if n == 1 || a == 0 || a == 1
293+
return true
294+
elseif a == -1
295+
return isodd(n) ? true : false
296+
elseif mod(n, 2) == 0 && a < 0
297+
return false
298+
elseif !ispower_moduli(a, n)
299+
return false
300+
end
301+
302+
q = BigInt()
303+
r = BigInt()
304+
ccall((:__gmpz_rootrem, :libgmp), Nothing,
305+
(Ref{BigInt}, Ref{BigInt}, Ref{BigInt}, Int), q, r, BigInt(a), n)
306+
307+
return r == 0
308+
end
309+
310+
function iroot(a::BigInt, n::Int)
311+
a < 0 && iseven(n) && throw(DomainError((a, n),
312+
"Argument `a` must be positive if exponent `n` is even"))
313+
n <= 0 && throw(DomainError(n, "Exponent must be positive"))
314+
z = BigInt()
315+
ccall((:__gmpz_root, :libgmp), Cint,
316+
(Ref{BigInt}, Ref{BigInt}, Cint), z, a, n)
317+
return z
318+
end
319+
320+
@doc Markdown.doc"""
321+
iroot(a::T, n::Int) where T <: Integer
322+
323+
Return the truncated integer part of the $n$-th root of $a$ (round towards
324+
zero). We require $n > 0$ and also $a \geq 0$ if $n$ is even.
325+
"""
326+
function iroot(a::T, n::Int) where T <: Integer
327+
if n == 2
328+
a < 0 && throw(DomainError((a, n),
329+
"Argument `a` must be positive if exponent `n` is even"))
330+
return isqrt(a)
331+
end
332+
return T(iroot(BigInt(a), n))
333+
end
334+
180335
###############################################################################
181336
#
182337
# Exponential

test/julia/Integers-test.jl

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,73 @@ end
133133
end
134134
end
135135

136+
@testset "Julia.Integers.root" begin
137+
@test root(BigInt(1000), 3) == 10
138+
@test root(-BigInt(27), 3) == -3
139+
@test root(BigInt(27), 3; check=true) == 3
140+
@test root(BigInt(16), 2; check=true) == 4
141+
142+
@test_throws DomainError root(-BigInt(1000), 4)
143+
@test_throws DomainError root(BigInt(1000), -3)
144+
@test_throws DomainError root(BigInt(-16), 2)
145+
146+
@test_throws ErrorException root(BigInt(1100), 3)
147+
@test_throws ErrorException root(-BigInt(40), 3)
148+
149+
@test iroot(BigInt(1000), 3) == 10
150+
@test iroot(BigInt(1100), 3) == 10
151+
@test iroot(-BigInt(40), 3) == -3
152+
@test iroot(BigInt(17), 2) == 4
153+
154+
@test_throws DomainError iroot(-BigInt(1000), 4)
155+
@test_throws DomainError iroot(BigInt(1000), -3)
156+
@test_throws DomainError iroot(-BigInt(16), 2)
157+
158+
@test root(1000, 3) == 10
159+
@test root(-27, 3) == -3
160+
@test root(27, 3) == 3
161+
@test root(16, 2) == 4
162+
163+
@test_throws DomainError root(-1000, 4)
164+
@test_throws DomainError root(1000, -3)
165+
@test_throws DomainError root(-16, 2)
166+
167+
@test_throws ErrorException root(1100, 3)
168+
@test_throws ErrorException root(-40, 3)
169+
170+
@test iroot(1000, 3) == 10
171+
@test iroot(1100, 3) == 10
172+
@test iroot(-40, 3) == -3
173+
@test iroot(17, 2) == 4
174+
175+
@test_throws DomainError iroot(-1000, 4)
176+
@test_throws DomainError iroot(1000, -3)
177+
@test_throws DomainError iroot(-16, 2)
178+
179+
for T in [BigInt, Int]
180+
for i = 1:1000
181+
n = rand(1:20)
182+
a = BigInt(rand(-1000:1000))
183+
if iseven(n)
184+
a = abs(a)
185+
end
186+
p = a^n
187+
if T == BigInt || ndigits(p; base=2) < ndigits(typemax(T); base=2)
188+
p = T(p)
189+
190+
@test ispower(p, n)
191+
192+
flag, q = ispower_with_root(p, n)
193+
194+
@test flag && q == a
195+
end
196+
end
197+
198+
@test_throws DomainError ispower(T(5), -1)
199+
@test_throws DomainError ispower_with_root(T(5), 0)
200+
end
201+
end
202+
136203
@testset "Julia.Integers.exp" begin
137204
@test AbstractAlgebra.exp(0) == 1
138205
@test_throws DomainError AbstractAlgebra.exp(1)

0 commit comments

Comments
 (0)