@@ -837,4 +837,108 @@ if Limb === UInt
837837 end
838838end
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+
840944end # module
0 commit comments