Arblib.jl
Arblib.jl copied to clipboard
default show for Arb might be confusing
This is an interval containing 0:
julia> let x = sin(Arb(π))
@info "" x contains(x, 0) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info:
│ x = [+/- 2.83e-77]
│ contains(x, 0) = true
│ Arblib.midref(x) = 1.0969174409793520767073235159733943661910882381141135060401716459409529154108e-77
└ Float64(Arblib.radref(x)) = 1.730607217577946e-77
This is an interval containing 1:
julia> let x = sin(Arb(π)/2)
@info "sin(Arb(π))" x contains(x, 1) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info: sin(Arb(π))
│ x = [1.000000000000000000000000000000000000000000000000000000000000000000000000000 +/- 1.74e-77]
│ contains(x, 1) = true
│ Arblib.midref(x) = 0.99999999999999999999999999999999999999999999999999999999999999999999999999999
└ Float64(Arblib.radref(x)) = 8.737900781332737e-78
This is an interval containing 1.5:
julia> let x = 1.5sin(Arb(π)/2)
@info "1.5sin(Arb(π)/2)" x contains(2x, 3) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info: 1.5sin(Arb(π)/2)
│ x = [1.5000000000000000000000000000000000000000000000000000000000000000000000000000 +/- 4.77e-77]
│ contains(2x, 3) = true
│ Arblib.midref(x) = 1.5
└ Float64(Arblib.radref(x)) = 3.0379188354575523e-77
let's try the same with set_interval!:
julia> let x = Arblib.set_interval!(Arb(), Arf(-0.5), Arf(0.5))
@info "[-0.5, 0.5]" x contains(x, 0) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info: [-0.5, 0.5]
│ x = [+/- 0.501]
│ contains(x, 0) = true
│ Arblib.midref(x) = 0
└ Float64(Arblib.radref(x)) = 0.5000000009313226
julia> let x = Arblib.set_interval!(Arb(), Arf(0.5), Arf(1.5))
@info "[0.5, 1.5]" x contains(x, 1) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info: [0.5, 1.5]
│ x = [1e+0 +/- 0.501]
│ contains(x, 1) = true
│ Arblib.midref(x) = 1
└ Float64(Arblib.radref(x)) = 0.5000000009313226
julia> let x = Arblib.set_interval!(Arb(), Arf(1.0), Arf(2.0))
@info "[1.0, 2.0]" x contains(2x, 3) Arblib.midref(x) Float64(Arblib.radref(x))
end
┌ Info: [1.0, 2.0]
│ x = [+/- 2.01] ← this is unexpected
│ contains(2x, 3) = true
│ Arblib.midref(x) = 1.5
└ Float64(Arblib.radref(x)) = 0.5000000009313226
moreover:
julia> let x = Arblib.set_interval!(Arb(), Arf(1.0), Arf(2.0))
@info "[1.0, 2.0]" Arblib.string_decimal(x) Arblib.string_nice(x)
end
┌ Info: [1.0, 2.0]
│ Arblib.string_decimal(x) = "1.5 +/- 0.5"
└ Arblib.string_nice(x) = "[+/- 2.01]"
What is exactly the bug? My hunch is that in the second and third case the midpoint is not exactly what is printed. Printed is the rounded version. The first I guess is a concise printing. In the other cases the midpoint has an exact representation and is therefore abbreviated.
the bug is that
julia> Arblib.set_interval!(Arb(), Arf(-2.0), Arf(2.0))
[+/- 2.01]
julia> Arblib.set_interval!(Arb(), Arf(1.0), Arf(2.0))
[+/- 2.01]
julia> Arblib.string_decimal(Arblib.set_interval!(Arb(), Arf(1.0), Arf(2.0)))
"1.5 +/- 0.5"
julia> Arblib.string_decimal(Arblib.set_interval!(Arb(), Arf(-2.0), Arf(2.0)))
"0 +/- 2"
the interval [-2.0, 2.0] has the same string_nice (which is used for show) as [1.0, 2.0]
oh I see
I don't think this is a bug but a result of the fact that string_nice only shows correct digits. The Interval [1.0, 2.0] contains both 1 and 2 so not a single digit of the number is known, hence it give anything before the +/- and has to resort to using the radius alone for the result. We get the same result with for example
julia> Arblib.set_interval!(Arb(), Arf(80000), Arf(90000))
[+/- 9.01e+4]
thanks for the explanation @Joel-Dahne; I found it confusing, but it makes perfect sense after explanation; however: given that this requires an explanation should we switch to string_decimal for show?
That is a good point actually! I have actually been bitten a couple of times by this behaviour myself. The main risk I see with this is that reading that string back with arb_get_str is not guaranteed to give an enclosure since for string_decimal, as written in the documentation, "The printed value of the radius is not adjusted to compensate for the fact that the binary-to-decimal conversion of both the midpoint and the radius introduces additional error."
I see, but given the problems with string_nice users should be discouraged from parsing the readable string representation of Arbs:
julia> x = Arblib.set_interval!(Arb(), Arf(1.0), Arf(2.0))
[+/- 2.01]
julia> y = Arb(Arblib.string_nice(x))
[+/- 2.02]
julia> Arblib.midref(y)
0
julia> z = Arb(Arblib.string_decimal(x)) # ← but not guaranteed to enclose x...
[+/- 2.01]
julia> Arblib.midref(z)
1.5
the functions for loading and storing are dump_string and load_string!. This requires additional entry in the docs though.
EDIT:
is there a function in julia for serialization into strings? I thought about repr, but reading the docs it doesn't seem to be the one...