Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

162 lines (134 sloc) 5.966 kb
type Rational{T<:Integer} <: Real
num::T
den::T
function Rational(num::T, den::T)
if num == 0 && den == 0
error("invalid rational: 0//0")
end
g = gcd(den, num)
new(div(num, g), div(den, g))
end
end
Rational{T<:Integer}(n::T, d::T) = Rational{T}(n,d)
Rational(n::Integer, d::Integer) = Rational(promote(n,d)...)
Rational(n::Integer) = Rational(n,one(n))
//(n::Integer, d::Integer ) = Rational(n,d)
//(x::Rational, y::Integer ) = x.num//(x.den*y)
//(x::Integer, y::Rational) = (x*y.den)//y.num
//(x::Rational, y::Rational) = (x.num*y.den)//(x.den*y.num)
//(x::Complex, y::Real ) = complex(real(x)//y,imag(x)//y)
//(x::Real, y::Complex ) = x*y'//real(y*y')
function //(x::Complex, y::Complex)
xy = x*y'
yy = real(y*y')
complex(real(xy)//yy, imag(xy)//yy)
end
function show(io, x::Rational)
if isinf(x)
print(io, x.num > 0 ? "Inf" : "-Inf")
else
show(io, num(x)); print(io, "//"); show(io, den(x))
end
end
convert{T<:Integer}(::Type{Rational{T}}, x::Rational) = Rational(convert(T,x.num),convert(T,x.den))
convert{T<:Integer}(::Type{Rational{T}}, x::Integer) = Rational(convert(T,x), convert(T,1))
function convert{T<:Integer}(::Type{Rational{T}}, x::FloatingPoint, tol::Real)
if isnan(x); return zero(T)//zero(T); end
if x < typemin(T); return -one(T)//zero(T); end
if typemax(T) < x; return one(T)//zero(T); end
y = x
a = d = one(T)
b = c = zero(T)
while true
f = convert(T,trunc(y)); y -= f
a, b, c, d = f*a+c, f*b+d, a, b
if y == 0 || abs(a/b-x) <= tol
return a//b
end
y = 1/y
end
end
convert{T<:Integer}(rt::Type{Rational{T}}, x::FloatingPoint) = convert(rt,x,0)
convert(::Type{Bool}, x::Rational) = (x!=0) # to resolve ambiguity
convert{T<:Rational}(::Type{T}, x::Rational) = x
convert{T<:Real}(::Type{T}, x::Rational) = convert(T, x.num/x.den)
promote_rule{T<:Integer}(::Type{Rational{T}}, ::Type{T}) = Rational{T}
promote_rule{T<:Integer,S<:Integer}(::Type{Rational{T}}, ::Type{S}) = Rational{promote_type(T,S)}
promote_rule{T<:Integer,S<:Integer}(::Type{Rational{T}}, ::Type{Rational{S}}) = Rational{promote_type(T,S)}
promote_rule{T<:Integer,S<:FloatingPoint}(::Type{Rational{T}}, ::Type{S}) = promote_type(T,S)
num(x::Integer) = x
den(x::Integer) = one(x)
num(x::Rational) = x.num
den(x::Rational) = x.den
sign(x::Rational) = sign(x.num)
signbit(x::Rational) = signbit(x.num)
copysign(x::Rational, y::Real) = copysign(x.num,y) // x.den
copysign(x::Rational, y::Rational) = copysign(x.num,y.num) // x.den
isnan(x::Rational) = false
isinf(x::Rational) = x.den == 0
isfinite(x::Rational) = x.den != 0
typemin{T<:Integer}(::Type{Rational{T}}) = -one(T)//zero(T)
typemax{T<:Integer}(::Type{Rational{T}}) = one(T)//zero(T)
integer_valued(x::Rational) = x.den == 1
float64_valued(x::Rational) = abs(x.num) <= x.den*maxintfloat(Float64)
hash(x::Rational) = integer_valued(x) ? hash(x.num) :
float64_valued(x) ? hash(float64(x)) :
bitmix(hash(x.num),hash(x.den))
-(x::Rational) = (-x.num) // x.den
+(x::Rational, y::Rational) = (x.num*y.den + x.den*y.num) // (x.den*y.den)
-(x::Rational, y::Rational) = (x.num*y.den - x.den*y.num) // (x.den*y.den)
*(x::Rational, y::Rational) = (x.num*y.num) // (x.den*y.den)
/(x::Rational, y::Rational) = (x.num*y.den) // (x.den*y.num)
/(x::Rational, z::ComplexPair) = inv(z/x)
==(x::Rational, y::Rational) = x.den == y.den && x.num == y.num
==(x::Rational, y::Integer ) = x.den == 1 && x.num == y
==(x::Integer , y::Rational) = y == x
# needed to avoid ambiguity between ==(x::Real, z::Complex) and ==(x::Rational, y::Number)
==(z::Complex , x::Rational) = real_valued(z) && real(z) == x
==(x::Rational, z::Complex ) = real_valued(z) && real(z) == x
==(x::Rational, y::Number ) = x.num == x.den*y
==(x::Number , y::Rational) = y == x
==(x::Rational, y::FloatingPoint) = x.den==0 ? oftype(y,x)==y : x.num == x.den*y
< (x::Rational, y::Rational) = x.den == y.den ? x.num < y.num : x.num*y.den < x.den*y.num
< (x::Rational, y::Real ) = x.num < x.den*y
< (x::Real , y::Rational) = x*y.den < y.num
<=(x::Rational, y::Rational) = x.den == y.den ? x.num <= y.num : x.num*y.den <= x.den*y.num
<=(x::Rational, y::Real ) = x.num <= x.den*y
<=(x::Real , y::Rational) = x*y.den <= y.num
div(x::Rational, y::Rational) = div(x.num*y.den, x.den*y.num)
div(x::Rational, y::Real ) = div(x.num, x.den*y)
div(x::Real , y::Rational) = div(x*y.den, y.num)
fld(x::Rational, y::Rational) = fld(x.num*y.den, x.den*y.num)
fld(x::Rational, y::Real ) = fld(x.num, x.den*y)
fld(x::Real , y::Rational) = fld(x*y.den, y.num)
itrunc(x::Rational) = div(x.num,x.den)
ifloor(x::Rational) = fld(x.num,x.den)
iceil (x::Rational) = -fld(-x.num,x.den)
iround(x::Rational) = div(x.num*2 + copysign(x.den,x.num), x.den*2)
trunc(x::Rational) = Rational(itrunc(x))
floor(x::Rational) = Rational(ifloor(x))
ceil (x::Rational) = Rational(iceil(x))
round(x::Rational) = Rational(iround(x))
rational(x::Real) = rational(x, 0)
rational(x::Rational, tol::Real) = x
rational(x::Integer) = x // one(x)
rational(x::Integer, tol::Real) = x // one(x)
rational(x::Float32, tol::Real) = convert(Rational{Int32}, x, tol)
rational(x::Float64, tol::Real) = convert(Rational{Int64}, x, tol)
rational(z::Complex) = complex(rational(real(z)), rational(imag(z)))
rational(z::Complex, tol::Real) =
(tol /= sqrt(2); complex(rational(real(z), tol), rational(imag(z), tol)))
## rational to int coercion ##
for f in (:int8, :int16, :int32, :int64, :int128,
:uint8, :uint16, :uint32, :uint64, :uint128,
:signed, :integer, :unsigned, :int, :uint)
@eval ($f)(x::Rational) = ($f)(iround(x))
end
function ^(x::Rational, y::Integer)
if y < 0
Rational(x.den^-y, x.num^-y)
else
Rational(x.num^y, x.den^y)
end
end
^(x::Number, y::Rational) = x^(y.num/y.den)
Jump to Line
Something went wrong with that request. Please try again.