Skip to content

Commit

Permalink
Add method to rationalize Rational (#43427)
Browse files Browse the repository at this point in the history
* Add Method to Rationalize Rational and Integer

Co-authored-by: Jeff Bezanson <[email protected]>
Co-authored-by: Oscar Smith <[email protected]>
  • Loading branch information
3 people authored Jun 14, 2023
1 parent 03c4bc1 commit 8a1b642
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
21 changes: 16 additions & 5 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,11 @@ julia> typeof(numerator(a))
BigInt
```
"""
function rationalize(::Type{T}, x::AbstractFloat, tol::Real) where T<:Integer
function rationalize(::Type{T}, x::Union{AbstractFloat, Rational}, tol::Real) where T<:Integer
if tol < 0
throw(ArgumentError("negative tolerance $tol"))
end

T<:Unsigned && x < 0 && __throw_negate_unsigned()
isnan(x) && return T(x)//one(T)
isinf(x) && return unsafe_rational(x < 0 ? -one(T) : one(T), zero(T))
Expand All @@ -188,7 +189,6 @@ function rationalize(::Type{T}, x::AbstractFloat, tol::Real) where T<:Integer
a = trunc(x)
r = x-a
y = one(x)

tolx = oftype(x, tol)
nt, t, tt = tolx, zero(tolx), tolx
ia = np = nq = zero(T)
Expand Down Expand Up @@ -233,10 +233,21 @@ function rationalize(::Type{T}, x::AbstractFloat, tol::Real) where T<:Integer
return p // q
end
end
rationalize(::Type{T}, x::AbstractFloat; tol::Real = eps(x)) where {T<:Integer} = rationalize(T, x, tol)::Rational{T}
rationalize(::Type{T}, x::AbstractFloat; tol::Real = eps(x)) where {T<:Integer} = rationalize(T, x, tol)
rationalize(x::AbstractFloat; kvs...) = rationalize(Int, x; kvs...)
rationalize(::Type{T}, x::Complex; kvs...) where {T<:Integer} = Complex(rationalize(T, x.re, kvs...)::Rational{T}, rationalize(T, x.im, kvs...)::Rational{T})
rationalize(x::Complex; kvs...) = Complex(rationalize(Int, x.re, kvs...), rationalize(Int, x.im, kvs...))
rationalize(::Type{T}, x::Complex; kvs...) where {T<:Integer} = Complex(rationalize(T, x.re; kvs...), rationalize(T, x.im; kvs...))
rationalize(x::Complex; kvs...) = Complex(rationalize(Int, x.re; kvs...), rationalize(Int, x.im; kvs...))
rationalize(::Type{T}, x::Rational; tol::Real = 0) where {T<:Integer} = rationalize(T, x, tol)
rationalize(x::Rational; kvs...) = x
rationalize(x::Integer; kvs...) = Rational(x)
function rationalize(::Type{T}, x::Integer; kvs...) where {T<:Integer}
if Base.hastypemax(T) # BigInt doesn't
x < typemin(T) && return unsafe_rational(-one(T), zero(T))
x > typemax(T) && return unsafe_rational(one(T), zero(T))
end
return Rational{T}(x)
end


"""
numerator(x)
Expand Down
12 changes: 12 additions & 0 deletions test/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ using Test

@test @inferred(rationalize(Int, 3.0, 0.0)) === 3//1
@test @inferred(rationalize(Int, 3.0, 0)) === 3//1
@test @inferred(rationalize(Int, 33//100; tol=0.1)) === 1//3 # because tol
@test @inferred(rationalize(Int, 3; tol=0.0)) === 3//1
@test @inferred(rationalize(Int8, 1000//333)) === Rational{Int8}(3//1)
@test @inferred(rationalize(Int8, 1000//3)) === Rational{Int8}(1//0)
@test @inferred(rationalize(Int8, 1000)) === Rational{Int8}(1//0)
@test_throws OverflowError rationalize(UInt, -2.0)
@test_throws ArgumentError rationalize(Int, big(3.0), -1.)
# issue 26823
Expand Down Expand Up @@ -727,3 +732,10 @@ end
@test rationalize(1.192 + 2.233im) == 149//125 + 2233//1000*im
@test rationalize(Int8, 1.192 + 2.233im) == 118//99 + 67//30*im
end
@testset "rationalize(Complex) with tol" begin
# test: rationalize(x::Complex; kvs...)
precise_next = 7205759403792795//72057594037927936
@assert Float64(precise_next) == nextfloat(0.1)
@test rationalize(nextfloat(0.1) * im; tol=0) == precise_next * im
@test rationalize(0.1im; tol=eps(0.1)) == rationalize(0.1im)
end

0 comments on commit 8a1b642

Please sign in to comment.