Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve show and string #183

Merged
merged 9 commits into from
Mar 19, 2024
Merged

Improve show and string #183

merged 9 commits into from
Mar 19, 2024

Conversation

Joel-Dahne
Copy link
Collaborator

This PR makes several updates to the show and string methods for Mag, Arf, Arb and Acb. Some of them are strict improvements, some of them are more opinionated. We can see which one we keep in the end.

After:

julia> Mag(1)
1.0
julia> Mag(1)
1.0
julia> Mag(π)
3.14159266
julia> show(IOContext(stdout, :compact => true), Mag(π))
3.14159
julia> Arf(1)
1.0
julia> Arf(1 // 3)
0.33333333333333333333333333333333333333333333333333333333333333333333333333333
julia> show(IOContext(stdout, :compact => true), Arf(1 // 3))
0.333333
julia> Arb(1)
1.0
julia> Arb(π)
[3.1415926535897932384626433832795028841971693993751058209749445923078164062862 +/- 1.93e-77]
julia> show(IOContext(stdout, :compact => true), Arb(π))
[3.14{72 digits}62 ± 1.93e-77]

Before:

julia> Mag(1)
(536870912 * 2^-29)
julia> Mag(π)
(843314857 * 2^-28)
julia> show(IOContext(stdout, :compact => true), Mag(π))
(843314857 * 2^-28)
julia> Arf(1)
1.0
julia> Arf(1 // 3)
0.3333333333333333333333333333333333333333333333333333333333333333333333333333348
julia> show(IOContext(stdout, :compact => true), Arf(1 // 3))
0.3333333333333333333333333333333333333333333333333333333333333333333333333333348
julia> Arb(1)
1.0000000000000000000000000000000000000000000000000000000000000000000000000000
julia> Arb(π)
[3.1415926535897932384626433832795028841971693993751058209749445923078164062862 +/- 1.93e-77]
julia> show(IOContext(stdout, :compact => true), Arb(π))
[3.1415926535897932384626433832795028841971693993751058209749445923078164062862 +/- 1.93e-77]

(Acb just prints the real and imaginary parts using the Arb version)

The first commit is an update to the interface and the remaining 5 make changes to the output format.

The string_nice method is removed, it never actually worked for Mag and Arf and was not particularly easy to use for Arb and Acb since you had to contruct the flag argument yourself. The interface is now based on Base.string, with flags for the various options. In addition to this we now use the arf_get_str function, which didn't exist when this code was first written. Before we converted Arf to BigFloat for printing, which is slightly problematic since Arf can represent more values than BigFloat.

The changes to the output format are (in the same order as the commits):

  1. Print Mag by converting to Arf. I think this is to prefer as the old output format is not particularly informative.
  2. Add compact show to Mag and Arf which only prints 6 digits. This is similar to how Float64 and BigFloat works.
  3. Add unicode argument to Base.string for Arb and Acb. This does replace(str, "+/-" => "±", "..." => "…") on the output.
  4. Add compact show for Arb and Acb. This sets the arguments condense = 2 and unicode = true for constructing the string.
  5. Remove trailing zeros for decimal numbers. This is similar to what the Base._prettify_bigfloat method does. I find this very convenient when the values are small integers, as 1.0 is significantly easier to read than 1.0000000000000000000000000000000000000000000000000000000000000000000000000000.

Some issues/possible improvements:

  1. The documentation for Base.string says that one should usually not define string directly, but this was the most natural way I found to be able to give formatting arguments when constructing strings. But Base does define it directly for e.g. Integer and BigFloat.
  2. I have not added any docstring for Base.string. Since the methods do accept a fairly large number of arguments this would maybe be reasonable to do.
  3. The decimal representation for Mag does round upwards. The printed result is hence not guaranteed to be an upper bound. I think it would be a nice improvement if it did round upwards. I thought I would add an issue in Flint about this (note that there is not even any mag_get_str function in Flint).

It now defines `string` methods for the above types, instead of
directly defining `show`. The string methods take as keyword arguments
the possible flags to the printing functions in Flint.

Arf now uses the function `arf_get_string` instead of converting to
BigFloat. This allows handling numbers with exponents outside the
range for BigFloat.

The `string_nice` methods have been removed, in favour of the above
string methods. In fact the string_nice never worked for Mag and Arf.
What previously was printed as (536870912 * 2^-29) is now printed as,
the significantly more helpful, 1.00000000.
@Joel-Dahne
Copy link
Collaborator Author

Oh, and maybe this is also a good time to publish 1.2.0?

src/show.jl Outdated
Comment on lines 41 to 51
function Base.string(
x::MagOrRef;
digits::Integer = digits_prec(30),
remove_trailing_zeros::Bool = true,
)
cstr = ccall(@libflint(arf_get_str), Ptr{UInt8}, (Ref{arf_struct}, Int), Arf(x), digits)
str = unsafe_string(cstr)
ccall(@libflint(flint_free), Nothing, (Ptr{UInt8},), cstr)

return remove_trailing_zeros ? _remove_trailing_zeros(str) : str
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could just replace this with

Suggested change
function Base.string(
x::MagOrRef;
digits::Integer = digits_prec(30),
remove_trailing_zeros::Bool = true,
)
cstr = ccall(@libflint(arf_get_str), Ptr{UInt8}, (Ref{arf_struct}, Int), Arf(x), digits)
str = unsafe_string(cstr)
ccall(@libflint(flint_free), Nothing, (Ptr{UInt8},), cstr)
return remove_trailing_zeros ? _remove_trailing_zeros(str) : str
end
function Base.string(
x::MagOrRef;
digits::Integer = digits_prec(30),
remove_trailing_zeros::Bool = true,
)
return string(Arf(x); digits, remove_trailing_zeros)
end

I actually didn't know that one can pass kwargs without explicitly writing them! when was it introduced?!

src/show.jl Outdated
Comment on lines 108 to 131
str = string(
realref(z);
digits,
more,
no_radius,
condense,
unicode,
remove_trailing_zeros,
)

if !iszero(imagref(z))
str *=
" + " *
string(
imagref(z);
digits,
more,
no_radius,
condense,
unicode,
remove_trailing_zeros,
) *
"im"
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
str = string(
realref(z);
digits,
more,
no_radius,
condense,
unicode,
remove_trailing_zeros,
)
if !iszero(imagref(z))
str *=
" + " *
string(
imagref(z);
digits,
more,
no_radius,
condense,
unicode,
remove_trailing_zeros,
) *
"im"
end
kwargs = (
:digits => digits,
:more => more,
:no_radius => no_radius,
:condense => condense,
:unicode => unicode,
:remove_trailing_zeros => remove_trailing_zeros
)
str = string(realref(z); kwargs...)
if !iszero(imagref(z))
str *= " + " * string(imagref(z); kwargs...) * "im"
end
return str

seems a bit more readable for me

@kalmarek
Copy link
Owner

sure, we can release 1.2.0.

I see all of those changes as clear improvements!

I wouldn't add any docstring to string -- nobody does so and lets keep it this way ;)

@Joel-Dahne
Copy link
Collaborator Author

I have made changes according to your comments and set the version to 1.2.

Regarding the kwargs I believe you already learned about this once before #152 (review).

@kalmarek
Copy link
Owner

well clearly I forgot again 🤣

@Joel-Dahne Joel-Dahne merged commit 2fcfa67 into master Mar 19, 2024
10 of 13 checks passed
@Joel-Dahne Joel-Dahne deleted the string branch March 19, 2024 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants