Skip to content

Commit

Permalink
Restore partial support for :fast rounding mode (#666)
Browse files Browse the repository at this point in the history
* Restore partial support for `:fast` rounding mode

* Add simple tests
  • Loading branch information
OlivierHnt authored Jun 3, 2024
1 parent 27e0947 commit c951192
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 18 deletions.
30 changes: 16 additions & 14 deletions src/intervals/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
Interval rounding type.
Available rounding types:
- `:fast` (unsupported): rounding via `prevfloat` and `nextfloat`.
- `:fast`: rounding via `prevfloat` and `nextfloat`. Currently only the functions
`+`, `-`, `*`, `/`, `inv` and `sqrt` are supported.
- `:tight`: rounding via [RoundingEmulator.jl](https://github.com/matsueushi/RoundingEmulator.jl).
- `:slow`: rounding via `BigFloat`.
- `:slow`: rounding via `BigFloat`. The other rounding modes default to `:slow`
whenever a faster algorithm is not available.
- `:none`: no rounding (non-rigorous numerics).
"""
struct IntervalRounding{T} end
Expand All @@ -26,10 +28,10 @@ for (f, fname) ∈ ((:+, :add), (:-, :sub), (:*, :mul), (:/, :div))
$g(::IntervalRounding, x::T, y::T, r::RoundingMode) where {T<:AbstractFloat} =
$g(IntervalRounding{:slow}(), x, y, r)

# $g(::IntervalRounding{:fast}, x::T, y::T, ::RoundingMode{:Down}) where {T<:AbstractFloat} =
# prevfloat($f(x, y))
# $g(::IntervalRounding{:fast}, x::T, y::T, ::RoundingMode{:Up}) where {T<:AbstractFloat} =
# nextfloat($f(x, y))
$g(::IntervalRounding{:fast}, x::T, y::T, ::RoundingMode{:Down}) where {T<:AbstractFloat} =
prevfloat($f(x, y))
$g(::IntervalRounding{:fast}, x::T, y::T, ::RoundingMode{:Up}) where {T<:AbstractFloat} =
nextfloat($f(x, y))

$g(::IntervalRounding{:tight}, x::T, y::T, ::RoundingMode{:Down}) where {T<:Union{Float32,Float64}} =
RoundingEmulator.$(Symbol(fname, :_down))(x, y)
Expand Down Expand Up @@ -93,10 +95,10 @@ _inv_round(x::Rational, ::RoundingMode) = inv(x) # exact operation
_inv_round(::IntervalRounding, x::AbstractFloat, r::RoundingMode) =
_inv_round(IntervalRounding{:slow}(), x, r)

# _inv_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Down}) =
# prevfloat(inv(x))
# _inv_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Up}) =
# nextfloat(inv(x))
_inv_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Down}) =
prevfloat(inv(x))
_inv_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Up}) =
nextfloat(inv(x))

_inv_round(::IntervalRounding{:tight}, x::Union{Float32,Float64}, ::RoundingMode{:Down}) =
RoundingEmulator.div_down(one(x), x)
Expand Down Expand Up @@ -125,10 +127,10 @@ _sqrt_round(x::AbstractFloat, r::RoundingMode) = _sqrt_round(interval_rounding()
_sqrt_round(::IntervalRounding, x::AbstractFloat, r::RoundingMode) =
_sqrt_round(IntervalRounding{:slow}(), x, r)

# _sqrt_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Down}) =
# prevfloat(sqrt(x))
# _sqrt_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Up}) =
# nextfloat(sqrt(x))
_sqrt_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Down}) =
prevfloat(sqrt(x))
_sqrt_round(::IntervalRounding{:fast}, x::AbstractFloat, ::RoundingMode{:Up}) =
nextfloat(sqrt(x))

_sqrt_round(::IntervalRounding{:tight}, x::Union{Float32,Float64}, ::RoundingMode{:Down}) =
RoundingEmulator.sqrt_down(x)
Expand Down
9 changes: 5 additions & 4 deletions test/interval_tests/rounding.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
x = interval(0.5)

# @testset "IntervalRounding{:fast}" begin
# IntervalArithmetic.interval_rounding() = IntervalArithmetic.IntervalRounding{:fast}()
# @test isequal_interval(sin(x), interval(0.47942553860420295, 0.47942553860420306))
# end
@testset "IntervalRounding{:fast}" begin
IntervalArithmetic.interval_rounding() = IntervalArithmetic.IntervalRounding{:fast}()
@test isequal_interval(interval(Float64, 0.5) + interval(Float64, 0.5), interval(0.9999999999999999, 1.0000000000000002))
@test isequal_interval(sqrt(interval(Float64, 9)), interval(2.9999999999999996, 3.0000000000000004))
end

@testset "IntervalRounding{:tight}" begin
IntervalArithmetic.interval_rounding() = IntervalArithmetic.IntervalRounding{:tight}()
Expand Down

0 comments on commit c951192

Please sign in to comment.