From 75e7a054402cc18d79950bb28aa3a84c67a492b1 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:41:43 +0200 Subject: [PATCH 01/11] Set Julia compat to 1.10 --- .github/workflows/CI.yml | 2 +- Project.toml | 6 +++--- README.md | 2 +- docs/src/index.md | 2 +- test/aqua.jl | 40 +++++++++++++++++++++------------------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e6e164ba..160590f6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: version: - - '1.9' + - '1.10' - '1' - 'nightly' os: diff --git a/Project.toml b/Project.toml index eebe3dc7..473c5f44 100644 --- a/Project.toml +++ b/Project.toml @@ -34,11 +34,11 @@ CRlibm = "1.0.2" DiffRules = "1" ForwardDiff = "0.10, 1" IntervalSets = "0.7" -LinearAlgebra = "1.9" +LinearAlgebra = "1.10" MacroTools = "0.5" OpenBLASConsistentFPCSR_jll = "0.3.29" Random = "1.9" RecipesBase = "1" RoundingEmulator = "0.2" -SparseArrays = "1.9.0" -julia = "1.9" +SparseArrays = "1.10" +julia = "1.10" diff --git a/README.md b/README.md index c1430053..20b40e79 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The official documentation is available online: https://juliaintervals.github.io ## Installation -The IntervalArithmetic.jl package requires to [install Julia](https://julialang.org/downloads/) (v1.9 or above). +The IntervalArithmetic.jl package requires to [install Julia](https://julialang.org/downloads/) (v1.10 or above). Then, start Julia and execute the following command in the REPL: diff --git a/docs/src/index.md b/docs/src/index.md index 3a60a15f..418728c6 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -7,7 +7,7 @@ IntervalArithmetic.jl is a Julia package for validated numerics in Julia. All ca ## Installation ```@repl -using Pkg # Julia v1.9 or above +using Pkg # Julia v1.10 or above redirect_stderr(devnull) do # hide Pkg.add("IntervalArithmetic") end # hide diff --git a/test/aqua.jl b/test/aqua.jl index 88c10f32..1f76f1ec 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -2,27 +2,29 @@ using Test using IntervalArithmetic using Aqua -if VERSION ≥ v"1.10" - @testset "Aqua tests (performance)" begin - # This tests that we don't accidentally run into - # https://github.com/JuliaLang/julia/issues/29393 - # Aqua.test_unbound_args(IntervalArithmetic) - ua = Aqua.detect_unbound_args_recursively(IntervalArithmetic) - @test length(ua) == 0 +@testset "Aqua tests (performance)" begin + # This tests that we don't accidentally run into + # https://github.com/JuliaLang/julia/issues/29393 + # Aqua.test_unbound_args(IntervalArithmetic) + ua = Aqua.detect_unbound_args_recursively(IntervalArithmetic) + @test length(ua) == 0 - # See: https://github.com/SciML/OrdinaryDiffEq.jl/issues/1750 - # Test that we're not introducing method ambiguities across deps - ambs = Aqua.detect_ambiguities(IntervalArithmetic; recursive = true) - pkg_match(pkgname, pkdir::Nothing) = false - pkg_match(pkgname, pkdir::AbstractString) = occursin(pkgname, pkdir) - filter!(x -> pkg_match("IntervalArithmetic", pkgdir(last(x).module)), ambs) - for method_ambiguity ∈ ambs - @show method_ambiguity - end + # See: https://github.com/SciML/OrdinaryDiffEq.jl/issues/1750 + # Test that we're not introducing method ambiguities across deps + ambs = Aqua.detect_ambiguities(IntervalArithmetic; recursive = true) + pkg_match(pkgname, pkdir::Nothing) = false + pkg_match(pkgname, pkdir::AbstractString) = occursin(pkgname, pkdir) + filter!(x -> pkg_match("IntervalArithmetic", pkgdir(last(x).module)), ambs) + for method_ambiguity ∈ ambs + @show method_ambiguity + end + if VERSION ≥ v"1.11" @test length(ambs) == 0 + else # version 1.10 + @test_broken length(ambs) == 0 end +end - @testset "Aqua tests (additional)" begin - Aqua.test_all(IntervalArithmetic) - end +@testset "Aqua tests (additional)" begin + Aqua.test_all(IntervalArithmetic; ambiguities = VERSION ≥ v"1.11") end From 1e1c96bcf17f759c674680551f9a083ebd052b1c Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:41:43 +0200 Subject: [PATCH 02/11] Set ForwardDiff compat to 1.0 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 473c5f44..2b4b499e 100644 --- a/Project.toml +++ b/Project.toml @@ -32,7 +32,7 @@ IntervalArithmeticSparseArraysExt = "SparseArrays" Arblib = "1.3.0" CRlibm = "1.0.2" DiffRules = "1" -ForwardDiff = "0.10, 1" +ForwardDiff = "1" IntervalSets = "0.7" LinearAlgebra = "1.10" MacroTools = "0.5" From 066d80e59b37aaf266842538836002e659ff7f3e Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:45:19 +0200 Subject: [PATCH 03/11] Rework display --- Project.toml | 4 ++- src/IntervalArithmetic.jl | 2 ++ src/display.jl | 64 +++++++++++++++++----------------- test/interval_tests/display.jl | 40 ++++++++++----------- 4 files changed, 57 insertions(+), 53 deletions(-) diff --git a/Project.toml b/Project.toml index 2b4b499e..9be31ca4 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ CRlibm = "96374032-68de-5a5b-8d9e-752f78720389" MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" OpenBLASConsistentFPCSR_jll = "6cdc7f73-28fd-5e50-80fb-958a8875b1af" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" RoundingEmulator = "5eaf0fd0-dfba-4ccb-bf02-d820a40db705" [weakdeps] @@ -37,7 +38,8 @@ IntervalSets = "0.7" LinearAlgebra = "1.10" MacroTools = "0.5" OpenBLASConsistentFPCSR_jll = "0.3.29" -Random = "1.9" +Random = "1.10" +Printf = "1.10" RecipesBase = "1" RoundingEmulator = "0.2" SparseArrays = "1.10" diff --git a/src/IntervalArithmetic.jl b/src/IntervalArithmetic.jl index c5cca463..c0f068cb 100644 --- a/src/IntervalArithmetic.jl +++ b/src/IntervalArithmetic.jl @@ -77,6 +77,8 @@ include("piecewise.jl") # +import Printf + include("display.jl") export setdisplay diff --git a/src/display.jl b/src/display.jl index 5928eac4..03ca9cbc 100644 --- a/src/display.jl +++ b/src/display.jl @@ -49,7 +49,7 @@ Display options: - significant digits: 6 julia> x = interval(0.1, 0.3) -[0.0999999, 0.300001]_com +[0.1, 0.3]_com julia> setdisplay(:full) Display options: @@ -69,7 +69,7 @@ Display options: - significant digits: 3 julia> x -[0.0999, 0.301]_com +[0.1, 0.3]_com julia> setdisplay(; decorations = false) Display options: @@ -79,7 +79,7 @@ Display options: - significant digits: 3 julia> x -[0.0999, 0.301] +[0.1, 0.3] ``` """ function setdisplay(format::Symbol = display_options.format; @@ -312,41 +312,41 @@ end # code inspired by `_string(x::BigFloat, k::Integer)` in base/mpfr.jl function _round_string(x::T, sigdigits::Int, r::RoundingMode) where {T<:AbstractFloat} - str_x = string(x) - str_digits = split(contains(str_x, '.') ? split(str_x, '.'; limit = 2)[2] : str_x, 'e'; limit = 2)[1] - len = length(str_digits) - if isinteger(x) && sigdigits ≥ len # `x` is exactly representable - return replace(_round_string(big(x), length(str_x), RoundNearest), "e-0" => "e-") - elseif ispow2(abs(x)) && sigdigits ≥ len # `x` is exactly representable - return replace(_round_string(big(x), len + 1, RoundNearest), "e-0" => "e-") - else - return _round_string(big(x), sigdigits, r) - end -end + !isfinite(x) && return string(x) -_round_string(x::BigFloat, sigdigits::Int, ::RoundingMode{:Nearest}) = - Base.MPFR._string(x, sigdigits-1) # `sigdigits-1` digits after the decimal + ndigits = ceil(Int, precision(x) * log10(T(2))) + sci_str = Printf.@sprintf("%.*e", ndigits, x) -function _round_string(x::BigFloat, sigdigits::Int, r::RoundingMode) - if !isfinite(x) - return string(Float64(x)) - else - str_x = string(x) - str_digits = split(split(str_x, '.'; limit = 2)[2], 'e'; limit = 2)[1] - len = length(str_digits) - if isinteger(x) && sigdigits ≥ len # `x` is exactly representable - return _round_string(big(x), length(str_x), RoundNearest) - elseif ispow2(abs(x)) && sigdigits ≥ len # `x` is exactly representable - return _round_string(big(x), len + 1, RoundNearest) - else - # `sigdigits` digits after the decimal - str = Base.MPFR.string_mpfr(x, "%.$(sigdigits)Re") - rounded_str = _round_string(str, r) - return Base.MPFR._prettify_bigfloat(rounded_str) + if abs(x) < floatmax(T) + ndigits_ = ndigits - 1 + sci_str_ = Printf.@sprintf("%.*e", ndigits_, x) + + if parse(T, sci_str) == parse(T, sci_str_) + ndigits = ndigits_ + sci_str = sci_str_ end end + + mantissa = split(sci_str, 'e')[1] + + mantissa_digits = replace(mantissa, "." => "") + + significant_digits = length(rstrip(mantissa_digits, '0')) + + is_representable = significant_digits ≤ sigdigits + + # `min(sigdigits-1, ndigits)` ensure we do not exceed the precision of `x` + str = is_representable ? Printf.@sprintf("%.*e", min(sigdigits-1, ndigits), x) : _round_string(Printf.@sprintf("%.*e", sigdigits, x), r) + + return Base.MPFR._prettify_bigfloat(str) end +_round_string(x::AbstractFloat, sigdigits::Int, r::RoundingMode{:Nearest}) = + _round_string(big(x), sigdigits, r) + +_round_string(x::BigFloat, sigdigits::Int, ::RoundingMode{:Nearest}) = + Base.MPFR._string(x, sigdigits-1) # `sigdigits-1` digits after the decimal + _round_string(s::String, ::RoundingMode{:Up}) = startswith(s, '-') ? string('-', _round_string_down(s[2:end])) : _round_string_up(s) diff --git a/test/interval_tests/display.jl b/test/interval_tests/display.jl index bc1d7156..9623cfdd 100644 --- a/test/interval_tests/display.jl +++ b/test/interval_tests/display.jl @@ -82,9 +82,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[1.0, 2.0]_com" @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_com_NG" - @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.30001]_com" - @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.30001f0]_com" - @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.29981)]_com" + @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.3]_com" + @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.3f0]_com" + @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == @@ -99,9 +99,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[1.0, 2.0]" @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_NG" - @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.30001]" - @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.30001f0]" - @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.29981)]" + @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.3]" + @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.3f0]" + @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)" @test sprint(show, MIME("text/plain"), large_expo) == @@ -114,9 +114,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[1.0, 2.0]_com" @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_com_NG" - @test sprint(show, MIME("text/plain"), b) == "[-2.2250738585072014e-308, 1.3000000000000000445]_com" - @test sprint(show, MIME("text/plain"), b32) == "[-1.1754944f-38, 1.2999999523162841797f0]_com" - @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.2998046875000000001)]_com" + @test sprint(show, MIME("text/plain"), b) == "[-2.2250738585072014e-308, 1.3]_com" + @test sprint(show, MIME("text/plain"), b32) == "[-1.1754944f-38, 1.3f0]_com" + @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == @@ -153,9 +153,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "(1.5 ± 0.5)_com" @test sprint(show, MIME("text/plain"), a_NG) == "(1.5 ± 0.5)_com_NG" - @test sprint(show, MIME("text/plain"), b) == "(0.65 ± 0.650001)_com" - @test sprint(show, MIME("text/plain"), b32) == "(0.65f0 ± 0.650001f0)_com" - @test sprint(show, MIME("text/plain"), b16) == "(Float16(0.649902) ± Float16(0.649903))_com" + @test sprint(show, MIME("text/plain"), b) == "(0.65 ± 0.65)_com" + @test_broken sprint(show, MIME("text/plain"), b32) == "(0.65f0 ± 0.65f0)_com" + @test_broken sprint(show, MIME("text/plain"), b16) == "(Float16(0.649902) ± Float16(0.65))_com" @test sprint(show, MIME("text/plain"), br) == "(1//10 ± 6//5)_com" @test sprint(show, MIME("text/plain"), c) == "(1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == @@ -170,9 +170,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "1.5 ± 0.5" @test sprint(show, MIME("text/plain"), a_NG) == "(1.5 ± 0.5)_NG" - @test sprint(show, MIME("text/plain"), b) == "0.65 ± 0.650001" - @test sprint(show, MIME("text/plain"), b32) == "0.65f0 ± 0.650001f0" - @test sprint(show, MIME("text/plain"), b16) == "Float16(0.649902) ± Float16(0.649903)" + @test sprint(show, MIME("text/plain"), b) == "0.65 ± 0.65" + @test_broken sprint(show, MIME("text/plain"), b32) == "0.65f0 ± 0.65f0" + @test_broken sprint(show, MIME("text/plain"), b16) == "Float16(0.649902) ± Float16(0.65)" @test sprint(show, MIME("text/plain"), br) == "1//10 ± 6//5" @test sprint(show, MIME("text/plain"), c) == "1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞" @test sprint(show, MIME("text/plain"), large_expo) == @@ -197,7 +197,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[0.0, 2.0]_com + im*[1.0, 1.0]_com" @test sprint(show, MIME("text/plain"), b) == "[0.0, 2.0]_com - im*[1.0, 1.0]_com" - @test sprint(show, MIME("text/plain"), c) == "[0.0, 1.00001e-70]_com - im*[0.999999e-70, 1.00001e-70]_com" + @test sprint(show, MIME("text/plain"), c) == "[0.0, 1.0e-70]_com - im*[1.0e-70, 1.0e-70]_com" end @testset "No decorations" begin @@ -205,7 +205,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[0.0, 2.0] + im*[1.0, 1.0]" @test sprint(show, MIME("text/plain"), b) == "[0.0, 2.0] - im*[1.0, 1.0]" - @test sprint(show, MIME("text/plain"), c) == "[0.0, 1.00001e-70] - im*[0.999999e-70, 1.00001e-70]" + @test sprint(show, MIME("text/plain"), c) == "[0.0, 1.0e-70] - im*[1.0e-70, 1.0e-70]" end end end @@ -216,7 +216,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "Interval{Float64}(0.0, 2.0, com) + im*Interval{Float64}(1.0, 1.0, com)" @test sprint(show, MIME("text/plain"), b) == "Interval{Float64}(0.0, 2.0, com) - im*Interval{Float64}(1.0, 1.0, com)" - # @test sprint(show, MIME("text/plain"), c) == "Interval{Float64}(0.0, 2.0, com) + im*Interval{Float64}(1.0, 1.0, com)" + @test sprint(show, MIME("text/plain"), c) == "Interval{Float64}(0.0, 1.0e-70, com) - im*Interval{Float64}(1.0e-70, 1.0e-70, com)" end @testset "Midpoint format" begin @@ -227,7 +227,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "(1.0 ± 1.0)_com + im*(1.0 ± 0.0)_com" @test sprint(show, MIME("text/plain"), b) == "(1.0 ± 1.0)_com - im*(1.0 ± 0.0)_com" - @test sprint(show, MIME("text/plain"), c) == "(5.0e-71 ± 5.00001e-71)_com - im*(1.0e-70 ± 0.0)_com" + @test sprint(show, MIME("text/plain"), c) == "(5.0e-71 ± 5.0e-71)_com - im*(1.0e-70 ± 0.0)_com" end @testset "No decorations" begin @@ -235,7 +235,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "(1.0 ± 1.0) + im*(1.0 ± 0.0)" @test sprint(show, MIME("text/plain"), b) == "(1.0 ± 1.0) - im*(1.0 ± 0.0)" - @test sprint(show, MIME("text/plain"), c) == "(5.0e-71 ± 5.00001e-71) - im*(1.0e-70 ± 0.0)" + @test sprint(show, MIME("text/plain"), c) == "(5.0e-71 ± 5.0e-71) - im*(1.0e-70 ± 0.0)" end end end From 48d14cc79b581f35dfc6982c5c30dbbc6df747f3 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:48:20 +0200 Subject: [PATCH 04/11] Rework comparison functionalities --- ext/IntervalArithmeticForwardDiffExt.jl | 7 +- src/intervals/real_interface.jl | 145 ++++++++++-------------- test/interval_tests/consistency.jl | 17 +-- test/interval_tests/set_operations.jl | 26 ++--- 4 files changed, 87 insertions(+), 108 deletions(-) diff --git a/ext/IntervalArithmeticForwardDiffExt.jl b/ext/IntervalArithmeticForwardDiffExt.jl index de64f6d1..cc05a222 100644 --- a/ext/IntervalArithmeticForwardDiffExt.jl +++ b/ext/IntervalArithmeticForwardDiffExt.jl @@ -23,8 +23,8 @@ Base.promote_rule(::Type{ExactReal{S}}, ::Type{Dual{T, V, N}}) where {S<:Real, T Base.promote_rule(::Type{Dual{T, V, N}}, ::Type{ExactReal{S}}) where {S<:Real, T, V, N} = Dual{T,ExactReal{IntervalArithmetic.promote_numtype(V, S)},N} -Base.:(==)(x::Union{BareInterval,Interval}, y::Dual) = x == value(y) -Base.:(==)(x::Dual, y::Union{BareInterval,Interval}) = value(x) == y +Base.:(==)(x::Interval, y::Dual) = x == value(y) +Base.:(==)(x::Dual, y::Interval) = value(x) == y function Base.:(^)(x::Dual{Txy,<:Interval}, y::Dual{Txy,<:Interval}) where {Txy} vx, vy = value(x), value(y) @@ -91,10 +91,9 @@ function Base.:(^)(x::ExactReal, y::Dual{<:Ty}) where {Ty} end end - # Piecewise functions -function (constant::Constant)(::Dual{T, Interval{S}}) where {T, S} +function (constant::Constant)(::Dual{T,Interval{S}}) where {T, S} return Dual{T}(interval(S, constant.value), interval(S, 0.0)) end diff --git a/src/intervals/real_interface.jl b/src/intervals/real_interface.jl index 6b776e26..cc2ce170 100644 --- a/src/intervals/real_interface.jl +++ b/src/intervals/real_interface.jl @@ -78,100 +78,77 @@ Base.hash(x::Interval, h::UInt) = hash(sup(x), hash(inf(x), hash(Interval, h))) # -for T ∈ (:BareInterval, :Interval) - @eval begin - function Base.:(==)(x::$T, y::$T) # also returned when calling `≤`, `≥`, `isequal` - isthin(x) && return sup(x) == y - isthin(y) && return x == sup(y) - return throw(ArgumentError("`==` is purposely not supported when the intervals are overlapping. See instead `isequal_interval`")) - end - - Base.:<(::$T, ::$T) = # also returned when calling `isless`, `>` - throw(ArgumentError("`<` is purposely not supported for intervals. See instead `isstrictless`, `strictprecedes`")) - - Base.isdisjoint(::$T, ::$T) = - throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`")) - - Base.issubset(::$T, ::$T) = - throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`")) - - Base.issetequal(::$T, ::$T) = - throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`")) - - Base.in(::$T, ::$T) = - throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) - Base.in(::Real, ::$T) = - throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) - Base.in(::$T, ::Real) = - throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) - - Base.isempty(::$T) = - throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`")) - - Base.isfinite(::$T) = # also returned when calling `isinf` - throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`")) - - Base.isnan(::$T) = - throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`")) - - Base.intersect(::$T) = - throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`")) - - Base.union!(::BitSet, ::$T) = # needed to resolve ambiguity - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - Base.union!(::AbstractSet, ::$T) = # also returned when calling `intersect`, `symdiff` with intervals - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - Base.union!(::AbstractVector{S}, ::$T) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - Base.union!(::AbstractVector{S}, ::$T, ::Any, ::Any...) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - Base.union!(::AbstractVector{S}, ::$T, ::$T, ::Any...) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - Base.union!(::AbstractVector{S}, ::Any, ::$T, ::Any...) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - - Base.setdiff(::$T) = - throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`")) - Base.setdiff!(::AbstractSet, ::$T) = - throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`")) - end +function Base.:(==)(x::Interval, y::Interval) # also returned when calling `≤`, `≥`, `isequal` + isthin(x) && return sup(x) == y + isthin(y) && return x == sup(y) + isdisjoint_interval(x, y) && return false + return throw(ArgumentError("`==` is purposely not supported when the intervals are overlapping. See instead `isequal_interval`")) +end + +function Base.:<(x::Interval, y::Interval) + isthin(x) && return sup(x) < y + isthin(y) && return x < sup(y) + strictprecedes(x, y) && return true + strictprecedes(y, x) && return false + return throw(ArgumentError("`<` is purposely not supported when the intervals are overlapping. See instead `strictprecedes`")) end -Base.union!(::AbstractVector{S}, ::BareInterval, ::Interval, ::Any...) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -Base.union!(::AbstractVector{S}, ::Interval, ::BareInterval, ::Any...) where {S} = - throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.isdisjoint(::Interval, ::Interval) = +# throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`")) + +# Base.issubset(::Interval, ::Interval) = +# throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`")) + +# Base.issetequal(::Interval, ::Interval) = +# throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`")) + +# Base.in(::Interval, ::Interval) = +# throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) + +Base.isempty(::Interval) = + throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`")) + +# Base.isfinite(::Interval) = # also returned when calling `isinf` +# throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`")) + +Base.isnan(::Interval) = + throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`")) + +# Base.intersect(::Interval) = +# throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`")) + +# Base.union!(::BitSet, ::Interval) = # needed to resolve ambiguity +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.union!(::AbstractSet, ::Interval) = # also returned when calling `intersect`, `symdiff` with intervals +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.union!(::AbstractVector{S}, ::Interval) where {S} = +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.union!(::AbstractVector{S}, ::Interval, ::Any, ::Any...) where {S} = +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.union!(::AbstractVector{S}, ::Interval, ::Interval, ::Any...) where {S} = +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +# Base.union!(::AbstractVector{S}, ::Any, ::Interval, ::Any...) where {S} = +# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) + +# Base.setdiff(::Interval) = +# throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`")) +# Base.setdiff!(::AbstractSet, ::Interval) = +# throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`")) # pointwise equality -""" - ==(::BareInterval, ::Number) - ==(::Number, ::BareInterval) - ==(::Interval, ::Number) - ==(::Number, ::Interval) - -Test whether an interval is the singleton of a given number. In other words, the -result is true if and only if the interval contains only that number. - -!!! note - Comparison between intervals is purposely disallowed. Indeed, equality - between non-singleton intervals has distinct properties, notably ``x = y`` - does not imply ``x - y = 0``. See instead [`isequal_interval`](@ref). -""" -Base.:(==)(x::Union{BareInterval,Interval}, y::Number) = isthin(x, y) -Base.:(==)(x::Number, y::Union{BareInterval,Interval}) = y == x +Base.:(==)(x::Interval, y::Number) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y) +Base.:(==)(x::Number, y::Interval) = y == x # needed to resolve ambiguity from irrationals.jl -Base.:(==)(x::Interval, y::AbstractIrrational) = isthin(x, y) +Base.:(==)(x::Interval, y::AbstractIrrational) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y) Base.:(==)(x::AbstractIrrational, y::Interval) = y == x # needed to resolve ambiguity from complex.jl Base.:(==)(x::Interval, y::Complex) = isreal(y) & (real(y) == x) Base.:(==)(x::Complex, y::Interval) = y == x -# follows docstring of `Base.iszero` -Base.iszero(x::Union{BareInterval,Interval}) = isthinzero(x) -# follows docstring of `Base.isone` -Base.isone(x::Union{BareInterval,Interval}) = isthinone(x) +Base.:<(x::Interval, y::Real) = (!isthin(x) & in_interval(y, x)) | isempty_interval(x) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : sup(x) < y +Base.:<(x::Real, y::Interval) = (!isthin(y) & in_interval(x, y)) | isempty_interval(y) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : x < inf(y) + -# follows docstring of `Base.isinteger` -Base.isinteger(x::Union{BareInterval,Interval}) = isthininteger(x) +Base.isinteger(x::Interval) = !isthin(x) & !isdisjoint_interval(x, floor(x), ceil(x)) ? throw(ArgumentError("`isinteger` is purposely not supported for non-thin containing at least one integer. See instead `isthininteger`")) : isthininteger(x) diff --git a/test/interval_tests/consistency.jl b/test/interval_tests/consistency.jl index eca6bd4f..6e0327a9 100644 --- a/test/interval_tests/consistency.jl +++ b/test/interval_tests/consistency.jl @@ -364,17 +364,20 @@ @testset "Disallowed `Real` functionalities" begin x, y = interval(1), interval(2) @test x != y - @test (interval(1, 2) != y) & (y != interval(1, 2)) + @test_throws ArgumentError interval(1, 2) != y + @test_throws ArgumentError y != interval(1, 2) @test_throws ArgumentError interval(1, 2) == interval(1, 2) - @test_throws ArgumentError x < y - @test_throws ArgumentError isdisjoint(x, y) - @test_throws ArgumentError issubset(x, y) - @test_throws ArgumentError issetequal(x, y) - @test_throws ArgumentError x ∈ y + @test x < y + @test isdisjoint(x, y) + @test !issubset(x, y) + @test !issetequal(x, y) + @test x ∉ y @test_throws ArgumentError isempty(x) - @test_throws ArgumentError isfinite(x) + @test_throws MethodError isfinite(x) @test_throws ArgumentError isnan(x) @test isinteger(x) + @test !isinteger(interval(1.2, 1.9)) + @test_throws ArgumentError isinteger(interval(1.5, 2.5)) @test x == 1 @test isone(x) @test !iszero(x) diff --git a/test/interval_tests/set_operations.jl b/test/interval_tests/set_operations.jl index eed5e45a..dadf4eb7 100644 --- a/test/interval_tests/set_operations.jl +++ b/test/interval_tests/set_operations.jl @@ -1,17 +1,17 @@ using IntervalArithmetic: interval_diff -@testset "removed interval" begin - @test_throws ArgumentError intersect(interval(1)) - @test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5) - @test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.)) - @test_throws ArgumentError union(interval(1)) - @test_throws ArgumentError union(interval(1), 2, [1], 4., 5) - @test_throws ArgumentError union(interval(1), interval(2.), interval(3.)) - @test_throws ArgumentError setdiff(interval(1)) - @test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5) - @test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.)) - @test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.)) -end +# @testset "removed interval" begin +# @test_throws ArgumentError intersect(interval(1)) +# @test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5) +# @test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.)) +# @test_throws ArgumentError union(interval(1)) +# @test_throws ArgumentError union(interval(1), 2, [1], 4., 5) +# @test_throws ArgumentError union(interval(1), interval(2.), interval(3.)) +# @test_throws ArgumentError setdiff(interval(1)) +# @test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5) +# @test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.)) +# @test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.)) +# end @testset "interiordiff" begin x = interval(2, 4) @@ -57,4 +57,4 @@ end @test interval_diff(interval(1, 10), interval(-1, 14)) == [] @test interval_diff(interval(1, 10), interval(1, 10)) == [] -end \ No newline at end of file +end From 7d1e90b937e46ae66325f29d93b6086551845b46 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:48:20 +0200 Subject: [PATCH 05/11] Remove ambiguous set functionalities --- ext/IntervalArithmeticForwardDiffExt.jl | 2 ++ src/intervals/real_interface.jl | 44 ++++++++++++------------- test/interval_tests/consistency.jl | 4 +-- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/ext/IntervalArithmeticForwardDiffExt.jl b/ext/IntervalArithmeticForwardDiffExt.jl index cc05a222..a789cc21 100644 --- a/ext/IntervalArithmeticForwardDiffExt.jl +++ b/ext/IntervalArithmeticForwardDiffExt.jl @@ -25,6 +25,8 @@ Base.promote_rule(::Type{Dual{T, V, N}}, ::Type{ExactReal{S}}) where {S<:Real, T Base.:(==)(x::Interval, y::Dual) = x == value(y) Base.:(==)(x::Dual, y::Interval) = value(x) == y +Base.:<(x::Interval, y::Dual) = x < value(y) +Base.:<(x::Dual, y::Interval) = value(x) < y function Base.:(^)(x::Dual{Txy,<:Interval}, y::Dual{Txy,<:Interval}) where {Txy} vx, vy = value(x), value(y) diff --git a/src/intervals/real_interface.jl b/src/intervals/real_interface.jl index cc2ce170..6d527ea3 100644 --- a/src/intervals/real_interface.jl +++ b/src/intervals/real_interface.jl @@ -108,32 +108,32 @@ end Base.isempty(::Interval) = throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`")) -# Base.isfinite(::Interval) = # also returned when calling `isinf` -# throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`")) +Base.isfinite(::Interval) = # also returned when calling `isinf` + throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`")) Base.isnan(::Interval) = throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`")) -# Base.intersect(::Interval) = -# throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`")) - -# Base.union!(::BitSet, ::Interval) = # needed to resolve ambiguity -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -# Base.union!(::AbstractSet, ::Interval) = # also returned when calling `intersect`, `symdiff` with intervals -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -# Base.union!(::AbstractVector{S}, ::Interval) where {S} = -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -# Base.union!(::AbstractVector{S}, ::Interval, ::Any, ::Any...) where {S} = -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -# Base.union!(::AbstractVector{S}, ::Interval, ::Interval, ::Any...) where {S} = -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) -# Base.union!(::AbstractVector{S}, ::Any, ::Interval, ::Any...) where {S} = -# throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) - -# Base.setdiff(::Interval) = -# throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`")) -# Base.setdiff!(::AbstractSet, ::Interval) = -# throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`")) +Base.intersect(::Interval) = + throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`")) + +Base.union!(::BitSet, ::Interval) = # needed to resolve ambiguity + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +Base.union!(::AbstractSet, ::Interval) = # also returned when calling `intersect`, `symdiff` with intervals + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +Base.union!(::AbstractVector{S}, ::Interval) where {S} = + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +Base.union!(::AbstractVector{S}, ::Interval, ::Any, ::Any...) where {S} = + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +Base.union!(::AbstractVector{S}, ::Interval, ::Interval, ::Any...) where {S} = + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) +Base.union!(::AbstractVector{S}, ::Any, ::Interval, ::Any...) where {S} = + throw(ArgumentError("`union!` is purposely not supported for intervals. See instead `hull`")) + +Base.setdiff(::Interval) = + throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`")) +Base.setdiff!(::AbstractSet, ::Interval) = + throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`")) # pointwise equality diff --git a/test/interval_tests/consistency.jl b/test/interval_tests/consistency.jl index 6e0327a9..9b0ad1a6 100644 --- a/test/interval_tests/consistency.jl +++ b/test/interval_tests/consistency.jl @@ -370,10 +370,10 @@ @test x < y @test isdisjoint(x, y) @test !issubset(x, y) - @test !issetequal(x, y) + @test_throws ArgumentError !issetequal(x, y) @test x ∉ y @test_throws ArgumentError isempty(x) - @test_throws MethodError isfinite(x) + @test_throws ArgumentError isfinite(x) @test_throws ArgumentError isnan(x) @test isinteger(x) @test !isinteger(interval(1.2, 1.9)) From ed16a216987732f9a4838bd2cdb6aee191c49108 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:48:20 +0200 Subject: [PATCH 06/11] Change `@test_broken` to `@test` --- test/aqua.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/aqua.jl b/test/aqua.jl index 1f76f1ec..3c585886 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -18,11 +18,7 @@ using Aqua for method_ambiguity ∈ ambs @show method_ambiguity end - if VERSION ≥ v"1.11" - @test length(ambs) == 0 - else # version 1.10 - @test_broken length(ambs) == 0 - end + @test length(ambs) == 0 end @testset "Aqua tests (additional)" begin From 8bf082e25ca1b395ba14f4b6600ef6cef9253fc8 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 10:48:20 +0200 Subject: [PATCH 07/11] Set default matmul mode to `:fast` --- src/IntervalArithmetic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IntervalArithmetic.jl b/src/IntervalArithmetic.jl index c0f068cb..8c20a39a 100644 --- a/src/IntervalArithmetic.jl +++ b/src/IntervalArithmetic.jl @@ -230,7 +230,7 @@ Configure the default behavior for: [`IntervalArithmetic.MatMulMode`](@ref). Keyword: `matmul`. Available options: `:fast` (default), `:slow`. """ -function configure(; numtype::Type{<:NumTypes}=Float64, flavor::Symbol=:set_based, rounding::Symbol=:correct, power::Symbol=:fast, matmul::Symbol=:slow) +function configure(; numtype::Type{<:NumTypes}=Float64, flavor::Symbol=:set_based, rounding::Symbol=:correct, power::Symbol=:fast, matmul::Symbol=:fast) configure_numtype(numtype) configure_flavor(flavor) configure_rounding(rounding) From 1b63e4fd389e4b25562a78bcb32205eee225d500 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 11:27:19 +0200 Subject: [PATCH 08/11] Update real interface --- src/intervals/real_interface.jl | 61 +++++++++++------------------- test/interval_tests/consistency.jl | 42 ++++++++++++++------ 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/intervals/real_interface.jl b/src/intervals/real_interface.jl index 6d527ea3..fcf8ddb7 100644 --- a/src/intervals/real_interface.jl +++ b/src/intervals/real_interface.jl @@ -79,42 +79,45 @@ Base.hash(x::Interval, h::UInt) = hash(sup(x), hash(inf(x), hash(Interval, h))) # function Base.:(==)(x::Interval, y::Interval) # also returned when calling `≤`, `≥`, `isequal` - isthin(x) && return sup(x) == y - isthin(y) && return x == sup(y) + isthin(x) & isthin(y) && return isequal_interval(x, y) isdisjoint_interval(x, y) && return false - return throw(ArgumentError("`==` is purposely not supported when the intervals are overlapping. See instead `isequal_interval`")) + return throw(ArgumentError("`==` is purposely not supported for overlapping non-thin intervals. See instead `isequal_interval`")) end function Base.:<(x::Interval, y::Interval) - isthin(x) && return sup(x) < y - isthin(y) && return x < sup(y) strictprecedes(x, y) && return true strictprecedes(y, x) && return false - return throw(ArgumentError("`<` is purposely not supported when the intervals are overlapping. See instead `strictprecedes`")) + isthin(x) & isthin(y) && return !isequal_interval(x, y) + return throw(ArgumentError("`<` is purposely not supported for overlapping intervals. See instead `strictprecedes`")) end -# Base.isdisjoint(::Interval, ::Interval) = -# throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`")) +function Base.isfinite(x::Interval) # also returned when calling `isinf` + isbounded(x) && return true + return throw(ArgumentError("`isfinite` is purposely not supported for intervals containing infinite bounds. See instead `isbounded`")) +end + +Base.isnan(x::Interval) = isnai(x) -# Base.issubset(::Interval, ::Interval) = -# throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`")) +Base.isinteger(x::Interval) = !isthin(x) & !isdisjoint_interval(x, floor(x), ceil(x)) ? throw(ArgumentError("`isinteger` is purposely not supported for a non-thin interval containing at least one integer. See instead `isthininteger`")) : isthininteger(x) -# Base.issetequal(::Interval, ::Interval) = -# throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`")) +# disallowed -# Base.in(::Interval, ::Interval) = -# throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) +Base.in(::Interval, ::Interval) = + throw(ArgumentError("`in` is purposely not supported for intervals. See instead `in_interval`")) Base.isempty(::Interval) = throw(ArgumentError("`isempty` is purposely not supported for intervals. See instead `isempty_interval`")) -Base.isfinite(::Interval) = # also returned when calling `isinf` - throw(ArgumentError("`isfinite` is purposely not supported for intervals. See instead `isbounded`")) - -Base.isnan(::Interval) = - throw(ArgumentError("`isnan` is purposely not supported for intervals. See instead `isnai`")) +Base.isapprox(::Interval, ::Interval) = + throw(ArgumentError("`isapprox` is purposely not supported for intervals")) -Base.intersect(::Interval) = +Base.isdisjoint(::Interval, ::Interval) = + throw(ArgumentError("`isdisjoint` is purposely not supported for intervals. See instead `isdisjoint_interval`")) +Base.issubset(::Interval, ::Interval) = + throw(ArgumentError("`issubset` is purposely not supported for intervals. See instead `issubset_interval`")) +Base.issetequal(::Interval, ::Interval) = + throw(ArgumentError("`issetequal` is purposely not supported for intervals. See instead `isequal_interval`")) +Base.intersect(::Interval, ::Interval...) = throw(ArgumentError("`intersect` is purposely not supported for intervals. See instead `intersect_interval`")) Base.union!(::BitSet, ::Interval) = # needed to resolve ambiguity @@ -134,21 +137,3 @@ Base.setdiff(::Interval) = throw(ArgumentError("`setdiff` is purposely not supported for intervals. See instead `interiordiff`")) Base.setdiff!(::AbstractSet, ::Interval) = throw(ArgumentError("`setdiff!` is purposely not supported for intervals. See instead `interiordiff`")) - -# pointwise equality - -Base.:(==)(x::Interval, y::Number) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y) -Base.:(==)(x::Number, y::Interval) = y == x -# needed to resolve ambiguity from irrationals.jl -Base.:(==)(x::Interval, y::AbstractIrrational) = !isthin(x) & in_interval(y, x) ? throw(ArgumentError("`==` is purposely not supported when the number is contained in the interval. See instead `isthin`")) : isthin(x, y) -Base.:(==)(x::AbstractIrrational, y::Interval) = y == x -# needed to resolve ambiguity from complex.jl -Base.:(==)(x::Interval, y::Complex) = isreal(y) & (real(y) == x) -Base.:(==)(x::Complex, y::Interval) = y == x - - -Base.:<(x::Interval, y::Real) = (!isthin(x) & in_interval(y, x)) | isempty_interval(x) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : sup(x) < y -Base.:<(x::Real, y::Interval) = (!isthin(y) & in_interval(x, y)) | isempty_interval(y) ? throw(ArgumentError("`<` is purposely not supported when the number is contained in the interval, or if the interval is empty")) : x < inf(y) - - -Base.isinteger(x::Interval) = !isthin(x) & !isdisjoint_interval(x, floor(x), ceil(x)) ? throw(ArgumentError("`isinteger` is purposely not supported for non-thin containing at least one integer. See instead `isthininteger`")) : isthininteger(x) diff --git a/test/interval_tests/consistency.jl b/test/interval_tests/consistency.jl index 9b0ad1a6..159d1460 100644 --- a/test/interval_tests/consistency.jl +++ b/test/interval_tests/consistency.jl @@ -361,26 +361,46 @@ end end - @testset "Disallowed `Real` functionalities" begin + @testset "`Real` functionalities" begin x, y = interval(1), interval(2) + + @test !isnan(x) + + @test isone(x) + @test !iszero(x) + @test_throws ArgumentError iszero(interval(0, 1)) @test x != y + @test x == 1 + @test_throws ArgumentError interval(1, 2) != 2 @test_throws ArgumentError interval(1, 2) != y @test_throws ArgumentError y != interval(1, 2) @test_throws ArgumentError interval(1, 2) == interval(1, 2) + @test x < y - @test isdisjoint(x, y) - @test !issubset(x, y) - @test_throws ArgumentError !issetequal(x, y) - @test x ∉ y - @test_throws ArgumentError isempty(x) - @test_throws ArgumentError isfinite(x) - @test_throws ArgumentError isnan(x) + @test x < 2 + @test !(x > y) + @test !(x < x) + @test !(x < 1) + @test_throws ArgumentError x < interval(1, 2) + + @test isfinite(x) + @test_throws ArgumentError isfinite(interval(1, Inf)) + @test isinteger(x) @test !isinteger(interval(1.2, 1.9)) @test_throws ArgumentError isinteger(interval(1.5, 2.5)) - @test x == 1 - @test isone(x) - @test !iszero(x) + + # + + @test_throws ArgumentError intersect(x, x) + @test_throws ArgumentError isapprox(x, x) + @test_throws ArgumentError isdisjoint(x, x) + @test_throws ArgumentError issubset(x, x) + @test_throws ArgumentError issetequal(x, x) + @test_throws ArgumentError x ∈ x + @test_throws ArgumentError isempty(x) + @test_throws ArgumentError union(x, x) + @test_throws ArgumentError setdiff(x, x) end end From 12a6ca8dc2263c0369d142d4c58834c727fbf3bf Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Fri, 18 Jul 2025 11:54:15 +0200 Subject: [PATCH 09/11] Bring some tests back --- test/interval_tests/set_operations.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/interval_tests/set_operations.jl b/test/interval_tests/set_operations.jl index dadf4eb7..37648024 100644 --- a/test/interval_tests/set_operations.jl +++ b/test/interval_tests/set_operations.jl @@ -1,17 +1,17 @@ using IntervalArithmetic: interval_diff -# @testset "removed interval" begin -# @test_throws ArgumentError intersect(interval(1)) -# @test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5) -# @test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.)) -# @test_throws ArgumentError union(interval(1)) -# @test_throws ArgumentError union(interval(1), 2, [1], 4., 5) -# @test_throws ArgumentError union(interval(1), interval(2.), interval(3.)) -# @test_throws ArgumentError setdiff(interval(1)) -# @test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5) -# @test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.)) -# @test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.)) -# end +@testset "removed interval" begin + @test_throws ArgumentError intersect(interval(1)) + @test_throws ArgumentError intersect(interval(1), 2, [1], 4., 5) + @test_throws ArgumentError intersect(interval(1), interval(2.), interval(3.)) + @test_throws ArgumentError union(interval(1)) + @test_throws ArgumentError union(interval(1), 2, [1], 4., 5) + @test_throws ArgumentError union(interval(1), interval(2.), interval(3.)) + @test_throws ArgumentError setdiff(interval(1)) + @test_throws ArgumentError setdiff(interval(1), 2, [1], 4., 5) + @test_throws ArgumentError setdiff(interval(1), interval(2.), interval(3.)) + @test_throws ArgumentError symdiff(interval(1), interval(2.), interval(3.)) +end @testset "interiordiff" begin x = interval(2, 4) From c64782be8452f4738d2346b7916d8ae94f5866fe Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Tue, 22 Jul 2025 18:28:05 +0200 Subject: [PATCH 10/11] Fix display --- src/display.jl | 125 ++++++--------------------------- test/interval_tests/display.jl | 48 ++++++------- 2 files changed, 45 insertions(+), 128 deletions(-) diff --git a/src/display.jl b/src/display.jl index 03ca9cbc..9f0f0173 100644 --- a/src/display.jl +++ b/src/display.jl @@ -196,14 +196,14 @@ function _str_basic_repr(a::BareInterval{<:AbstractFloat}, format::Symbol) return string(str_lo, ", ", str_hi) elseif format === :midpoint m = mid(a) - str_m = _round_string(m, sigdigits, RoundNearest) + str_m = _round_string(m, sigdigits) # str_m = ifelse(m ≥ 0, string('+', str_m), str_m) - output = string(str_m, " ± ", _round_string(radius(a), sigdigits, RoundUp)) + output = string(str_m, " ± ", _round_string(radius(a), sigdigits)) return replace(output, "Inf" => '∞') else - str_lo = _round_string(lo, sigdigits, RoundDown) + str_lo = _round_string(lo, sigdigits) # str_lo = ifelse(lo ≥ 0, string('+', str_lo), str_lo) - str_hi = _round_string(hi, sigdigits, RoundUp) + str_hi = _round_string(hi, sigdigits) # str_hi = ifelse(hi ≥ 0, string('+', str_hi), str_hi) output = string('[', str_lo, ", ", str_hi, ']') return replace(output, "Inf]" => "∞)", "[-Inf" => "(-∞") @@ -231,26 +231,26 @@ function _str_basic_repr(a::BareInterval{Float32}, format::Symbol) return string(str_lo, ", ", str_hi) elseif format === :midpoint m = mid(a) - str_m = _round_string(m, sigdigits, RoundNearest) + str_m = _round_string(m, sigdigits) str_m = replace(string(str_m, "f0"), "NaNf0" => "NaN32", "Inff0" => "Inf32") if contains(str_m, 'e') str_m = replace(str_m, 'e' => 'f', "f0" => "") end # str_m = ifelse(m ≥ 0, string('+', str_m), str_m) - str_r = _round_string(radius(a), sigdigits, RoundUp) + str_r = _round_string(radius(a), sigdigits) str_r = replace(string(str_r, "f0"), "NaNf0" => "NaN32", "Inff0" => "Inf32") if contains(str_r, 'e') str_r = replace(str_r, 'e' => 'f', "f0" => "") end return string(str_m, " ± ", str_r) else - str_lo = _round_string(lo, sigdigits, RoundDown) + str_lo = _round_string(lo, sigdigits) str_lo = replace(string('[', str_lo, "f0"), "NaNf0" => "NaN32", "[-Inff0" => "(-∞") if contains(str_lo, 'e') str_lo = replace(str_lo, 'e' => 'f', "f0" => "") end # str_lo = ifelse(lo ≥ 0, string('+', str_lo), str_lo) - str_hi = _round_string(hi, sigdigits, RoundUp) + str_hi = _round_string(hi, sigdigits) str_hi = replace(string(str_hi, "f0]"), "NaNf0" => "NaN32", "Inff0]" => "∞)") if contains(str_hi, 'e') str_hi = replace(str_hi, 'e' => 'f', "f0" => "") @@ -274,14 +274,14 @@ function _str_basic_repr(a::BareInterval{Float16}, format::Symbol) return replace(output, "Float16(NaN)" => "NaN16", "Float16(-Inf)" => "-Inf16", "Float16(Inf)" => "Inf16") elseif format === :midpoint m = mid(a) - str_m = _round_string(m, sigdigits, RoundNearest) + str_m = _round_string(m, sigdigits) # str_m = ifelse(m ≥ 0, string('+', str_m), str_m) - output = string("Float16(", str_m, ") ± Float16(", _round_string(radius(a), sigdigits, RoundUp), ')') + output = string("Float16(", str_m, ") ± Float16(", _round_string(radius(a), sigdigits), ')') return replace(output, "Float16(NaN)" => "NaN16", "Float16(Inf)" => '∞') else - str_lo = _round_string(lo, sigdigits, RoundDown) + str_lo = _round_string(lo, sigdigits) # str_lo = ifelse(lo ≥ 0, string('+', str_lo), str_lo) - str_hi = _round_string(sup(a), sigdigits, RoundUp) + str_hi = _round_string(sup(a), sigdigits) # str_hi = ifelse(hi ≥ 0, string('+', str_hi), str_hi) output = string("[Float16(", str_lo, "), Float16(", str_hi, ")]") return replace(output, "Float16(NaN)" => "NaN16", "[Float16(-Inf)" => "(-∞", "Float16(Inf)]" => "∞)") @@ -308,102 +308,19 @@ function _str_basic_repr(a::BareInterval{<:Rational}, format::Symbol) end end -# round to the prescribed significant digits -# code inspired by `_string(x::BigFloat, k::Integer)` in base/mpfr.jl +# truncate to the prescribed significant digits -function _round_string(x::T, sigdigits::Int, r::RoundingMode) where {T<:AbstractFloat} +function _round_string(x::AbstractFloat, sigdigits::Int) !isfinite(x) && return string(x) - - ndigits = ceil(Int, precision(x) * log10(T(2))) - sci_str = Printf.@sprintf("%.*e", ndigits, x) - - if abs(x) < floatmax(T) - ndigits_ = ndigits - 1 - sci_str_ = Printf.@sprintf("%.*e", ndigits_, x) - - if parse(T, sci_str) == parse(T, sci_str_) - ndigits = ndigits_ - sci_str = sci_str_ - end - end - - mantissa = split(sci_str, 'e')[1] - - mantissa_digits = replace(mantissa, "." => "") - - significant_digits = length(rstrip(mantissa_digits, '0')) - - is_representable = significant_digits ≤ sigdigits - - # `min(sigdigits-1, ndigits)` ensure we do not exceed the precision of `x` - str = is_representable ? Printf.@sprintf("%.*e", min(sigdigits-1, ndigits), x) : _round_string(Printf.@sprintf("%.*e", sigdigits, x), r) - - return Base.MPFR._prettify_bigfloat(str) -end - -_round_string(x::AbstractFloat, sigdigits::Int, r::RoundingMode{:Nearest}) = - _round_string(big(x), sigdigits, r) - -_round_string(x::BigFloat, sigdigits::Int, ::RoundingMode{:Nearest}) = - Base.MPFR._string(x, sigdigits-1) # `sigdigits-1` digits after the decimal - -_round_string(s::String, ::RoundingMode{:Up}) = - startswith(s, '-') ? string('-', _round_string_down(s[2:end])) : _round_string_up(s) - -_round_string(s::String, ::RoundingMode{:Down}) = - startswith(s, '-') ? string('-', _round_string_up(s[2:end])) : _round_string_down(s) - -function _round_string_up(s::String) - # `s` has one extra significant digit to control the rounding - mantissa, exponent = eachsplit(s, 'e') - mantissa = mantissa[1:end-1] - len = length(mantissa) - idx = findlast(d -> (d !== '9') & (d !== '.'), mantissa) - if idx == len # last significant digit is not `9` - d = parse(Int, mantissa[len]) + 1 # increase the last significant digit - return string(view(mantissa, 1:len-1), d, 'e', exponent) - else - if isnothing(idx) # all significant digits are `9` - expo = parse(Int, exponent) + 1 # increase the exponent by `1` - expo_str = string(expo; pad = 2) - exponent = expo < 0 ? expo_str : string('+', expo_str) - return string("1.", '0'^(len - 2), 'e', exponent) - else - new_mantissa = string( - view(mantissa, 1:idx-1), - parse(Int, mantissa[idx]) + 1, - # add `"."` if the last significant digit not equal to `9` is before the decimal point - idx == 1 ? "." : "", - '0'^(len - idx)) - return string(new_mantissa, 'e', exponent) - end - end + max_sig_digits = _count_sigdigits(string(x)) + ndigits = min(sigdigits, max_sig_digits) + str = Printf.@sprintf("%.*g", ndigits, x) + occursin(r"[eE]", str) && return replace(str, r"^([+-]?\d+)(?=[eE])" => s"\1.0", r"([eE][+-])0+(\d+)" => s"\1\2") + !occursin(r"\.", str) && return str * ".0" + return str end -function _round_string_down(s::String) - # `s` has one extra significant digit to control the rounding - mantissa, exponent = eachsplit(s, 'e') - len = length(mantissa) - idx = findlast(d -> (d !== '0') & (d !== '.'), mantissa) - if idx == len # last significant digit is not `0` - return string(view(mantissa, 1:len-1), 'e', exponent) # truncate - else - if isnothing(idx) # all significant digits are `0` - expo = parse(Int, exponent) - 1 # decrease the exponent by `1` - expo_str = string(expo; pad = 2) - exponent = expo < 0 ? expo_str : string('+', expo_str) - return string("9.", '9'^(len - 3), 'e', exponent) - else - new_mantissa = string( - view(mantissa, 1:idx-1), - parse(Int, mantissa[idx]) - 1, - # add `"."` if the last significant digit not equal to `0` is before the decimal point - idx == 1 ? "." : "", - '9'^(len - (idx + 1))) - return string(new_mantissa, 'e', exponent) - end - end -end +_count_sigdigits(s::AbstractString) = length(replace(split(s, r"[eE]")[1], '-' => "", '.' => "", r"^0+" => "")) # diff --git a/test/interval_tests/display.jl b/test/interval_tests/display.jl index 9623cfdd..9f4f2311 100644 --- a/test/interval_tests/display.jl +++ b/test/interval_tests/display.jl @@ -19,18 +19,18 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), emptyinterval(BareInterval{Float64})) == "∅" - @test sprint(show, MIME("text/plain"), a) == "[-2.22508e-308, 1.30001]" + @test sprint(show, MIME("text/plain"), a) == "[-2.22507e-308, 1.3]" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.00001e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" end @testset "20 significant digits" begin # `decorations` keyword has no impact for `BareInterval` setdisplay(; sigdigits = 20, decorations = true) - @test sprint(show, MIME("text/plain"), a) == "[-2.2250738585072014e-308, 1.3000000000000000445]" + @test sprint(show, MIME("text/plain"), a) == "[-2.2250738585072014e-308, 1.3]" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0000000000000000001e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" end end @@ -43,7 +43,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "BareInterval{Float64}(-2.2250738585072014e-308, 1.3)" @test sprint(show, MIME("text/plain"), large_expo) == - "BareInterval{BigFloat}(0.0, 1.000000000000000000000000000000000000000000000000000000000000000000000000000004e$(BIGFLOAT_SIGN_STR)123456789)" + "BareInterval{BigFloat}(0.0, $(sup(large_expo)))" end @testset "Midpoint format" begin @@ -52,9 +52,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), emptyinterval(BareInterval{Float64})) == "∅" - @test sprint(show, MIME("text/plain"), a) == "0.65 ± 0.650001" + @test sprint(show, MIME("text/plain"), a) == "0.65 ± 0.65" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.00001e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" + "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" end end @@ -82,13 +82,13 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[1.0, 2.0]_com" @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_com_NG" - @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.3]_com" - @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.3f0]_com" - @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" + @test sprint(show, MIME("text/plain"), b) == "[-2.22507e-308, 1.3]_com" + @test sprint(show, MIME("text/plain"), b32) == "[-1.17549f-38, 1.3f0]_com" + @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.00001e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" + "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" end @testset "No decorations" begin @@ -99,13 +99,13 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[1.0, 2.0]" @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_NG" - @test sprint(show, MIME("text/plain"), b) == "[-2.22508e-308, 1.3]" - @test sprint(show, MIME("text/plain"), b32) == "[-1.1755f-38, 1.3f0]" - @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]" + @test sprint(show, MIME("text/plain"), b) == "[-2.22507e-308, 1.3]" + @test sprint(show, MIME("text/plain"), b32) == "[-1.17549f-38, 1.3f0]" + @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.00001e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" end end @@ -116,11 +116,11 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a_NG) == "[1.0, 2.0]_com_NG" @test sprint(show, MIME("text/plain"), b) == "[-2.2250738585072014e-308, 1.3]_com" @test sprint(show, MIME("text/plain"), b32) == "[-1.1754944f-38, 1.3f0]_com" - @test_broken sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" + @test sprint(show, MIME("text/plain"), b16) == "[Float16(-6.104e-5), Float16(1.3)]_com" @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0000000000000000001e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" + "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" end end @@ -139,7 +139,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), br) == "Interval{Rational{Int64}}(-11//10, 13//10, com)" @test sprint(show, MIME("text/plain"), c) == "Interval{Float64}(-1.0, Inf, dac)" @test sprint(show, MIME("text/plain"), large_expo) == - "Interval{BigFloat}(0.0, 1.000000000000000000000000000000000000000000000000000000000000000000000000000004e$(BIGFLOAT_SIGN_STR)123456789, com)" + "Interval{BigFloat}(0.0, $(sup(large_expo)), com)" end @testset "Midpoint format" begin @@ -154,12 +154,12 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "(1.5 ± 0.5)_com" @test sprint(show, MIME("text/plain"), a_NG) == "(1.5 ± 0.5)_com_NG" @test sprint(show, MIME("text/plain"), b) == "(0.65 ± 0.65)_com" - @test_broken sprint(show, MIME("text/plain"), b32) == "(0.65f0 ± 0.65f0)_com" - @test_broken sprint(show, MIME("text/plain"), b16) == "(Float16(0.649902) ± Float16(0.65))_com" + @test sprint(show, MIME("text/plain"), b32) == "(0.65f0 ± 0.65f0)_com" + @test sprint(show, MIME("text/plain"), b16) == "(Float16(0.65) ± Float16(0.65))_com" @test sprint(show, MIME("text/plain"), br) == "(1//10 ± 6//5)_com" @test sprint(show, MIME("text/plain"), c) == "(1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.00001e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆_com" + "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆_com" end @testset "No decorations" begin @@ -171,12 +171,12 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "1.5 ± 0.5" @test sprint(show, MIME("text/plain"), a_NG) == "(1.5 ± 0.5)_NG" @test sprint(show, MIME("text/plain"), b) == "0.65 ± 0.65" - @test_broken sprint(show, MIME("text/plain"), b32) == "0.65f0 ± 0.65f0" - @test_broken sprint(show, MIME("text/plain"), b16) == "Float16(0.649902) ± Float16(0.65)" + @test sprint(show, MIME("text/plain"), b32) == "0.65f0 ± 0.65f0" + @test sprint(show, MIME("text/plain"), b16) == "Float16(0.65) ± Float16(0.65)" @test sprint(show, MIME("text/plain"), br) == "1//10 ± 6//5" @test sprint(show, MIME("text/plain"), c) == "1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.00001e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" + "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" end end end From c4ddb768313f0b61d0c6c4cd76ecc6dea727f009 Mon Sep 17 00:00:00 2001 From: OlivierHnt <38465572+OlivierHnt@users.noreply.github.com> Date: Tue, 22 Jul 2025 18:33:19 +0200 Subject: [PATCH 11/11] Fix tests --- test/interval_tests/display.jl | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/test/interval_tests/display.jl b/test/interval_tests/display.jl index 9f4f2311..b713e45c 100644 --- a/test/interval_tests/display.jl +++ b/test/interval_tests/display.jl @@ -1,9 +1,3 @@ -if VERSION < v"1.13.0-DEV" - const BIGFLOAT_SIGN_STR = "+" -else - const BIGFLOAT_SIGN_STR = "" -end - setprecision(BigFloat, 256) do @testset "BareInterval" begin a = bareinterval(-floatmin(Float64), 1.3) @@ -21,7 +15,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[-2.22507e-308, 1.3]" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e+123456789]₂₅₆" end @testset "20 significant digits" begin @@ -30,7 +24,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "[-2.2250738585072014e-308, 1.3]" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e+123456789]₂₅₆" end end @@ -54,7 +48,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), a) == "0.65 ± 0.65" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" + "(5.0e+123456788 ± 5.0e+123456788)₂₅₆" end end @@ -88,7 +82,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" + "[0.0, 1.0e+123456789]₂₅₆_com" end @testset "No decorations" begin @@ -105,7 +99,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆" + "[0.0, 1.0e+123456789]₂₅₆" end end @@ -120,7 +114,7 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), br) == "[-11//10, 13//10]_com" @test sprint(show, MIME("text/plain"), c) == "[-1.0, ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "[0.0, 1.0e$(BIGFLOAT_SIGN_STR)123456789]₂₅₆_com" + "[0.0, 1.0e+123456789]₂₅₆_com" end end @@ -157,9 +151,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), b32) == "(0.65f0 ± 0.65f0)_com" @test sprint(show, MIME("text/plain"), b16) == "(Float16(0.65) ± Float16(0.65))_com" @test sprint(show, MIME("text/plain"), br) == "(1//10 ± 6//5)_com" - @test sprint(show, MIME("text/plain"), c) == "(1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞)_dac" + @test sprint(show, MIME("text/plain"), c) == "(1.79769e+308 ± ∞)_dac" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆_com" + "(5.0e+123456788 ± 5.0e+123456788)₂₅₆_com" end @testset "No decorations" begin @@ -174,9 +168,9 @@ setprecision(BigFloat, 256) do @test sprint(show, MIME("text/plain"), b32) == "0.65f0 ± 0.65f0" @test sprint(show, MIME("text/plain"), b16) == "Float16(0.65) ± Float16(0.65)" @test sprint(show, MIME("text/plain"), br) == "1//10 ± 6//5" - @test sprint(show, MIME("text/plain"), c) == "1.79769e$(BIGFLOAT_SIGN_STR)308 ± ∞" + @test sprint(show, MIME("text/plain"), c) == "1.79769e+308 ± ∞" @test sprint(show, MIME("text/plain"), large_expo) == - "(5.0e$(BIGFLOAT_SIGN_STR)123456788 ± 5.0e$(BIGFLOAT_SIGN_STR)123456788)₂₅₆" + "(5.0e+123456788 ± 5.0e+123456788)₂₅₆" end end end