Skip to content

Commit 217a449

Browse files
authored
Use mpq functions for Rational{BigInt} (#38520)
Fixes #9826.
1 parent 3ffb4fb commit 217a449

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

base/gmp.jl

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,4 +837,108 @@ if Limb === UInt
837837
end
838838
end
839839

840+
module MPQ
841+
842+
# Rational{BigInt}
843+
import .Base: unsafe_rational, __throw_rational_argerror_zero
844+
import ..GMP: BigInt, MPZ, Limb, isneg
845+
846+
mutable struct _MPQ
847+
num_alloc::Cint
848+
num_size::Cint
849+
num_d::Ptr{Limb}
850+
den_alloc::Cint
851+
den_size::Cint
852+
den_d::Ptr{Limb}
853+
# to prevent GC
854+
rat::Rational{BigInt}
855+
end
856+
857+
const mpq_t = Ref{_MPQ}
858+
859+
_MPQ(x::BigInt,y::BigInt) = _MPQ(x.alloc, x.size, x.d,
860+
y.alloc, y.size, y.d,
861+
unsafe_rational(BigInt, x, y))
862+
_MPQ() = _MPQ(BigInt(), BigInt())
863+
_MPQ(x::Rational{BigInt}) = _MPQ(x.num, x.den)
864+
865+
function sync_rational!(xq::_MPQ)
866+
xq.rat.num.alloc = xq.num_alloc
867+
xq.rat.num.size = xq.num_size
868+
xq.rat.num.d = xq.num_d
869+
xq.rat.den.alloc = xq.den_alloc
870+
xq.rat.den.size = xq.den_size
871+
xq.rat.den.d = xq.den_d
872+
return xq.rat
873+
end
874+
875+
function Rational{BigInt}(num::BigInt, den::BigInt)
876+
if iszero(den)
877+
iszero(num) && __throw_rational_argerror_zero(BigInt)
878+
num = isneg(num) ? -one(BigInt) : one(BigInt)
879+
return unsafe_rational(BigInt, num, den)
880+
end
881+
xq = _MPQ(MPZ.set(num), MPZ.set(den))
882+
ccall((:__gmpq_canonicalize, :libgmp), Cvoid, (mpq_t,), xq)
883+
return sync_rational!(xq)
884+
end
885+
886+
function Base.:+(x::Rational{BigInt}, y::Rational{BigInt})
887+
if iszero(x.den) || iszero(y.den)
888+
if iszero(x.den) && iszero(y.den) && isneg(x.num) != isneg(y.num)
889+
throw(DivideError())
890+
end
891+
return iszero(x.den) ? x : y
892+
end
893+
zq = _MPQ()
894+
ccall((:__gmpq_add, :libgmp), Cvoid,
895+
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
896+
return sync_rational!(zq)
897+
end
898+
function Base.:-(x::Rational{BigInt}, y::Rational{BigInt})
899+
if iszero(x.den) || iszero(y.den)
900+
if iszero(x.den) && iszero(y.den) && isneg(x.num) == isneg(y.num)
901+
throw(DivideError())
902+
end
903+
return iszero(x.den) ? x : -y
904+
end
905+
zq = _MPQ()
906+
ccall((:__gmpq_sub, :libgmp), Cvoid,
907+
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
908+
return sync_rational!(zq)
909+
end
910+
function Base.:*(x::Rational{BigInt}, y::Rational{BigInt})
911+
if iszero(x.den) || iszero(y.den)
912+
if iszero(x.num) || iszero(y.num)
913+
throw(DivideError())
914+
end
915+
return xor(isneg(x.num),isneg(y.num)) ? -one(BigInt)//zero(BigInt) : one(BigInt)//zero(BigInt)
916+
end
917+
zq = _MPQ()
918+
ccall((:__gmpq_mul, :libgmp), Cvoid,
919+
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
920+
return sync_rational!(zq)
921+
end
922+
function Base.://(x::Rational{BigInt}, y::Rational{BigInt})
923+
if iszero(x.den)
924+
if iszero(y.den)
925+
throw(DivideError())
926+
end
927+
return isneg(y.num) ? -x : x
928+
elseif iszero(y.den)
929+
return y.den // y.num
930+
elseif iszero(y.num)
931+
if iszero(x.num)
932+
throw(DivideError())
933+
end
934+
return (isneg(x.num) ? -one(BigFloat) : one(BigFloat)) // y.num
935+
end
936+
zq = _MPQ()
937+
ccall((:__gmpq_div, :libgmp), Cvoid,
938+
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
939+
return sync_rational!(zq)
940+
end
941+
942+
end # MPQ module
943+
840944
end # module

0 commit comments

Comments
 (0)