Printing
The task of printing an Arb
value in a human readable format is surprisingly tricky. See for example the issues #84, #208 and #217 which all are examples of confusions coming from the way Arb
values are printed by default.
The main source of confusion is the convention that, by default, the output is rounded so that the printed midpoint is correct to within 1 ulp (unit in the last decimal place). Compare
julia> Arb(π, prec = 64)
[3.141592653589793239 +/- 5.96e-19]
julia> Arb(π, prec = 128)
[3.1415926535897932384626433832795028842 +/- 1.06e-38]
to
julia> string(Arb(π, prec = 64), digits = 37, more = true)
"[3.141592653589793238512808959406186204 +/- 1.09e-19]"
While in all cases the output is correct, in the sense that the printed enclosure indeed is an enclosure of $\pi$. In the latter example though we forced Arb to print more digits of the midpoint that are not in the actual value for $\pi$.
This convention of rounding the output to be correct within 1 ulp can give confusing behavior when the radius is too large for even the first digit to be known to 1 ulp. In this case, no digits of the midpoints are printed and instead the value is printed in the format [+/- R]
where R
is an upper bound for the absolute value of the input. As above, the more
argument to string
can then be used to print more (possibly incorrect) digits.
julia> x = setball(Arb, 5, 2) # The interval is too wide to know the first digit to 1 ulp
[+/- 7.01]
julia> string(x, more = true)
"[5.0000000000000000000000000000000000000000000000000000000000000000000000000000 +/- 2.01]"
julia> string(x, digits = 5, more = true)
"[5.0000 +/- 2.01]"
In general the radius in the printed value will be larger than the actual value. This effect is particularly noticeable for wide values, but occurs otherwise as well. The effect is reduced by printing more (possibly incorrect) digits, but still persists (in part because the radius is rounded to 2 digits in the printing). For example we can consider the printed radius for an enclosure of $\pi$.
julia> x = Arb(π, prec = 64)
[3.141592653589793239 +/- 5.96e-19]
julia> string(x, digits = 50, more = true)
"[3.1415926535897932385128089594061862044327426701784 +/- 1.09e-19]"
julia> radius(x)
1.08420217e-19
Even for exact values the radius is printed if the number of digits requested is not enough to represent the value exactly.
julia> x = 1 / Arb(2^55, prec = 64) # Set x to the exact value 2^-55
[2.775557561562891351e-17 +/- 5.91e-37]
julia> Arblib.isexact(x) # The value is indeed exact, even though it is printed with a radius
true
julia> string(x, digits = 39) # We need at least 39 digits to print the exact value
"2.77555756156289135105907917022705078125e-17"
Serialization
As apparent from the above discussion, printing an Arb
value as a decimal string is a lossy operation. If you want to convert to a string as an intermediate representation, you can serialize the value using Arblib.dump_string
. The result can then be read back using Arblib.load_string
.
julia> x = Arb(π)
[3.1415926535897932384626433832795028841971693993751058209749445923078164062862 +/- 1.93e-77]
julia> str = Arblib.dump_string(x)
"6487ed5110b4611a62633145c06e0e68948127044533e63a0105df531d89cd91 -fd 1 -ff"
julia> y = Arblib.load_string(Arb, str)
[3.1415926535897932384626433832795028841971693993751058209749445923078164062862 +/- 1.93e-77]
julia> isequal(x, y) # x and y are exactly the same
true
API
Base.string
— Functionstring(x::ArbOrRef; digits, more, no_radius, condense, unicode, remove_trailing_zeros)
Convert x
to a decimal string. By default, this uses the midpoint-radius format "[m ± r]".
With default flags, the output can be parsed back as Arb(string(x))
, and this is guaranteed to produce an interval containing the original interval x
(but is generally wider). For lossless, but not human readable, serialization as a string, see dump_string
and load_string
.
By default, the output is rounded so that the value given for the midpoint is correct up to 1 ulp (unit in the last decimal place).
The output can be confusing for wide inputs, when the radius is too large for even the first digit to be known up to 1 ulp. In this case the interval is printed in the format [+/- R]
where R
is an upper bound for the absolute value of x
. The more
keyword argument (see below) can then be used (possibly in combination with digits
) to print more digits, which are however no longer guaranteed to be correct within 1 ulp.
julia> x = Arb((1, 2));
julia> string(x)
"[+/- 2.01]"
julia> string(x, more = true)
"[1.5000000000000000000000000000000000000000000000000000000000000000000000000000 +/- 0.501]"
julia> string(x, digits = 5, more = true)
"[1.5000 +/- 0.501]"
The getball
and getinterval
functions can also be useful in this case.
Keyword Arguments
digits::Integer = digits_prec(precision(x))
: The number of digits to display.more::Bool = false
: Iftrue
, display more (possibly incorrect) digits.no_radius::Bool = false
: Iftrue
, the radius is not displayed in the output. Unlessmore
is set, the output is rounded so that the midpoint is correct to 1 ulp. As a special case, if there are no significant digits after rounding, the result will be shown as $0e+n$, meaning that the result is between $-1e+n$ and $1e+n$ (following the contract that the output is correct to within one unit in the only shown digit).condense::Integer = 0
: If non-zero, strings of more than three timescondense
consecutive digits are condensed, only printing the leading and trailingcondense
digits along with brackets indicating the number of digits omitted (useful when computing values to extremely high precision).unicode::Bool = false
: Iftrue
, use unicode characters in the output, e.g.,±
instead of+/-
.remove_trailing_zeros::Bool = !no_radius
: Iftrue
, remove trailing zeros after the decimal point.
Examples
julia> x = Arb(π, prec = 64);
julia> string(x)
"[3.141592653589793239 +/- 5.96e-19]"
julia> string(x; no_radius=true)
"3.141592653589793239"
julia> y = Arb((1, 2), prec = 64);
julia> string(y)
"[+/- 2.01]"
julia> string(y, more = true)
"[1.500000000000000000 +/- 0.501]"
julia> string(y, digits = 30, more = true)
"[1.50000000000000000000000000000 +/- 0.501]"
julia> z = Arb(π, prec = 512);
julia> string(z)
"[3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481 +/- 2.99e-154]"
julia> string(z, condense = 2, unicode = true)
"[3.14{…149 digits…}81 ± 2.99e-154]"
Arblib.dump_string
— Functiondump_string(x::Union{MagLike,ArfLike,ArbLike})
Return a serialized string representation of x
.
The result can be read back in using load_string
.
For human readable output, see string
.
Arblib.load_string
— Functionload_string(T::Type{<:Union{Mag,Arf,Arb}}, str::AbstractString)
Parse a string str
as outputted by dump_string
and return an identical new object of type T
.