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.

Note

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 radiustrue
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 sametrue

API

Base.stringFunction
string(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).

Warning

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: If true, display more (possibly incorrect) digits.
  • no_radius::Bool = false: If true, the radius is not displayed in the output. Unless more 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 times condense consecutive digits are condensed, only printing the leading and trailing condense digits along with brackets indicating the number of digits omitted (useful when computing values to extremely high precision).
  • unicode::Bool = false: If true, use unicode characters in the output, e.g., ± instead of +/-.
  • remove_trailing_zeros::Bool = !no_radius: If true, 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]"
source
Arblib.dump_stringFunction
dump_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.

source
Arblib.load_stringFunction
load_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.

source