Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions base/gmp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -837,4 +837,108 @@ if Limb === UInt
end
end

module MPQ

# Rational{BigInt}
import .Base: unsafe_rational, __throw_rational_argerror_zero
import ..GMP: BigInt, MPZ, Limb, isneg

mutable struct _MPQ
num_alloc::Cint
num_size::Cint
num_d::Ptr{Limb}
den_alloc::Cint
den_size::Cint
den_d::Ptr{Limb}
# to prevent GC
rat::Rational{BigInt}
end

const mpq_t = Ref{_MPQ}

_MPQ(x::BigInt,y::BigInt) = _MPQ(x.alloc, x.size, x.d,
y.alloc, y.size, y.d,
unsafe_rational(BigInt, x, y))
_MPQ() = _MPQ(BigInt(), BigInt())
_MPQ(x::Rational{BigInt}) = _MPQ(x.num, x.den)

function sync_rational!(xq::_MPQ)
xq.rat.num.alloc = xq.num_alloc
xq.rat.num.size = xq.num_size
xq.rat.num.d = xq.num_d
xq.rat.den.alloc = xq.den_alloc
xq.rat.den.size = xq.den_size
xq.rat.den.d = xq.den_d
return xq.rat
end

function Rational{BigInt}(num::BigInt, den::BigInt)
if iszero(den)
iszero(num) && __throw_rational_argerror_zero(BigInt)
num = isneg(num) ? -one(BigInt) : one(BigInt)
return unsafe_rational(BigInt, num, den)
end
xq = _MPQ(MPZ.set(num), MPZ.set(den))
ccall((:__gmpq_canonicalize, :libgmp), Cvoid, (mpq_t,), xq)
return sync_rational!(xq)
end

function Base.:+(x::Rational{BigInt}, y::Rational{BigInt})
if iszero(x.den) || iszero(y.den)
if iszero(x.den) && iszero(y.den) && isneg(x.num) != isneg(y.num)
throw(DivideError())
end
return iszero(x.den) ? x : y
end
zq = _MPQ()
ccall((:__gmpq_add, :libgmp), Cvoid,
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
return sync_rational!(zq)
end
function Base.:-(x::Rational{BigInt}, y::Rational{BigInt})
if iszero(x.den) || iszero(y.den)
if iszero(x.den) && iszero(y.den) && isneg(x.num) == isneg(y.num)
throw(DivideError())
end
return iszero(x.den) ? x : -y
end
zq = _MPQ()
ccall((:__gmpq_sub, :libgmp), Cvoid,
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
return sync_rational!(zq)
end
function Base.:*(x::Rational{BigInt}, y::Rational{BigInt})
if iszero(x.den) || iszero(y.den)
if iszero(x.num) || iszero(y.num)
throw(DivideError())
end
return xor(isneg(x.num),isneg(y.num)) ? -one(BigInt)//zero(BigInt) : one(BigInt)//zero(BigInt)
end
zq = _MPQ()
ccall((:__gmpq_mul, :libgmp), Cvoid,
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
return sync_rational!(zq)
end
function Base.://(x::Rational{BigInt}, y::Rational{BigInt})
if iszero(x.den)
if iszero(y.den)
throw(DivideError())
end
return isneg(y.num) ? -x : x
elseif iszero(y.den)
return y.den // y.num
elseif iszero(y.num)
if iszero(x.num)
throw(DivideError())
end
return (isneg(x.num) ? -one(BigFloat) : one(BigFloat)) // y.num
end
zq = _MPQ()
ccall((:__gmpq_div, :libgmp), Cvoid,
(mpq_t,mpq_t,mpq_t), zq, _MPQ(x), _MPQ(y))
return sync_rational!(zq)
end

end # MPQ module

end # module