-
Notifications
You must be signed in to change notification settings - Fork 12
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
Ryu engineering2 #31
Ryu engineering2 #31
Conversation
if isdefined(Base, :Grisu) | ||
include("grisu.jl") | ||
else | ||
if isdefined(Base, :Ryu) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way users from 1.5 can also benefit
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if y ≈ 0.0 # 0 digits for numbers close to 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem oftentimes arises due 0.0 present as usually 0.0 = 1e-55
(some weird power for floats). Then this would mean that if 0.0 is present, precision would go to 55. It is better to set that precision needed to display 0 should always be 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
julia> 1e-200 ≈ 0.0
false
I think you'll be better off keeping a min/max precision and capping the ratio between them.
# 1.2334e5 = 123.334e3 | ||
# 1.2334-5 = 12.3334e-6 | ||
|
||
if positive |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is commented above and should be easy enough to follow. Though this function is less efficient (due to int parsing), I believe it is worth it as it greatly simplifies the logic
@@ -1,6 +1,7 @@ | |||
using Showoff | |||
using Test | |||
using Dates | |||
using Printf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add printf as we should match the behavior to @sprintf
as it was originally intended
@test Showoff.format_fixed_scientific(0.012345678, 4, false) == "1.2346×10⁻²" | ||
@test Showoff.format_fixed_scientific(-10.0, 4, false) == "-1.0000×10¹" | ||
@test Showoff.format_fixed_scientific(-10.0, 4, false) == "-1.0000×10¹" | ||
@test Showoff.format_fixed_scientific(-10.0, 4, false)[1:end-5] == @sprintf("%0.4e", -10.0)[1:end-4] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compare first half (without exponent)
end | ||
|
||
@testset "Showoff" begin | ||
x = [1.12345, 4.5678] | ||
@test showoff(x) == ["1.12345", "4.56780"] | ||
@test showoff([0.0, 50000.0]) == ["0", "5×10⁴"] | ||
@test showoff([0.0, 50000.0]) == ["0", "5.0×10⁴"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly breaking, as now engineering notation introduces the trailing 0, however it is now consistent with scientific as it also introduces the zero
Regarding your comments from #30 (review), for Plots, the performance of Showoff is completely insignificant, as |
Also I noticed that Makie too, uses this @SimonDanisch. |
Still not passing tests. Does it pass locally for you? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems close to mergeable, unless @SimonDanisch thinks the performance issues are serious. Certainly for Plots concerns about performance should not hold this back.
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if y ≈ 0.0 # 0 digits for numbers close to 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
julia> 1e-200 ≈ 0.0
false
I think you'll be better off keeping a min/max precision and capping the ratio between them.
It's strange, I pass the tests locally |
Are you testing with |
Co-authored-by: Tim Holy <tim.holy@gmail.com>
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if isapprox(y, 0, atol=1e-16) # 0 has undefined rtol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@timholy What about now?
The probelm with 0.0 is that it has undefined rtol and it is hard to judge if a number is close to zero
The choice behind 1e-16 is somewhat arbitrary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion was to keep track of both the min and max of e10
. Maybe something like this:
e10max = -(e10min = typemax(Int))
for y in ys
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
end
precision = min(-e10min, -e10max+16)
That way if all the numbers are tiny, you won't truncate unnecessarily.
Not sure whether the old 0 was important for something, but this design would also allow you to incorporate that if necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With your code
function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat})
ys = filter(isfinite, xs)
e10max = -(e10min = typemax(Int))
for y in ys
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
@show e10min, e10max
end
return precision = min(-e10min, -e10max+16)
end
The showoff fails, and I think it is due to 0.0s:
julia> showoff([0.0, 50000.0])
(e10min, e10max) = (-325, -325)
(e10min, e10max) = (-325, 0)
2-element Array{String,1}:
"0"
"5.00000000000000000×10⁴"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I still retain the zero number hack
function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat})
ys = filter(isfinite, xs)
e10max = -(e10min = typemax(Int))
for y in ys
if isapprox(y, 0, atol=1e-16)
continue
end
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
@show e10min, e10max
end
return precision = min(-e10min, -e10max+16)
end
and now the tests pass normally:
julia> showoff([0.0, 50000.0])
(e10min, e10max) = (0, 0)
2-element Array{String,1}:
"0"
"5.0×10⁴"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More changes
Regarding the tests, i pass them with both julia 1.5.3 and 1.4.2, of course the version of the julia needs to have Base.Ryu or else the tests would fail because of the fallback to Grisu.
|
And thanks for looking into this issue @timholy and giving a code review, it is always helpful to have feedback 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just take a look at my suggestion for handling the precision
in the case of small values, and then once you decide how you want to handle that we can merge this.
Regarding the tests, once this merges I'll check locally and probably update the tests to run on GitHub Actions before merging to master. So don't worry about it unless you hear otherwise from me later.
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if isapprox(y, 0, atol=1e-16) # 0 has undefined rtol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion was to keep track of both the min and max of e10
. Maybe something like this:
e10max = -(e10min = typemax(Int))
for y in ys
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
end
precision = min(-e10min, -e10max+16)
That way if all the numbers are tiny, you won't truncate unnecessarily.
Not sure whether the old 0 was important for something, but this design would also allow you to incorporate that if necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handle 0s and min max exponents
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if isapprox(y, 0, atol=1e-16) # 0 has undefined rtol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With your code
function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat})
ys = filter(isfinite, xs)
e10max = -(e10min = typemax(Int))
for y in ys
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
@show e10min, e10max
end
return precision = min(-e10min, -e10max+16)
end
The showoff fails, and I think it is due to 0.0s:
julia> showoff([0.0, 50000.0])
(e10min, e10max) = (-325, -325)
(e10min, e10max) = (-325, 0)
2-element Array{String,1}:
"0"
"5.00000000000000000×10⁴"
src/ryu.jl
Outdated
@@ -6,8 +6,11 @@ function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat}) | |||
ys = filter(isfinite, xs) | |||
precision = 0 | |||
for y in ys | |||
b, e10 = Ryu.reduce_shortest(convert(Float32, y)) | |||
precision = max(precision, -e10) | |||
if isapprox(y, 0, atol=1e-16) # 0 has undefined rtol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I still retain the zero number hack
function plain_precision_heuristic(xs::AbstractArray{<:AbstractFloat})
ys = filter(isfinite, xs)
e10max = -(e10min = typemax(Int))
for y in ys
if isapprox(y, 0, atol=1e-16)
continue
end
_, e10 = Ryu.reduce_shortest(y)
e10min = min(e10min, e10)
e10max = max(e10max, e10)
@show e10min, e10max
end
return precision = min(-e10min, -e10max+16)
end
and now the tests pass normally:
julia> showoff([0.0, 50000.0])
(e10min, e10max) = (0, 0)
2-element Array{String,1}:
"0"
"5.0×10⁴"
That's a pretty ugly hack but let's go with it (I really don't use this package so...). I'll merge this into my branch and then see whether I can figure out the test failures. Thanks! |
OK, so the problem is that the tests were failing on older versions of Julia, they were passing on 1.6 (which I presume is what you're using). Some of the things changed behaviors that look like bugs of the old spec; however, you also have some new bugs:
which we need to fix before we can merge this to master. (It should be -10.0000×10⁰.) Finally, some changes you made to I've put more time into this than it warrants so I'm going to have to rely on you to make these fixes, then I'll wrap everything up and merge. |
Co-authored-by: Tim Holy <tim.holy@gmail.com>
@timholy I'm creating a new PR due to some unresolved git issues I had with the previous commit. More details inside code review.