JuliaDynamics/DrWatson.jl

Inconsistent rounding for parameters in savename

Opened this issue · 3 comments

When using savename, some unexpected behaviour can happen when using some parameter values with the sigdigits keyword. This seems to be due to the fact that savename uses the round function to format numbers, which is designed for outputting numbers as strings. One issue occurs when using very small or large numbers, and is due to a known bug in round, but is machine specific.

For example,

julia> savename("test", (p1=3.6e-23,), sigdigits=1)
"test_p1=4.0000000000000004e-23"

but for one order of magnitude larger

julia> savename("test", (p1=3.6e-22,), sigdigits=1)
"test_p1=4e-22"

Additionally, while it may round the correct number of significant digits, the output will not necessarily represent the specified number of significant digits. Specifically, this occurs when there should be additional zeros, which are either not be added to the given number, or are dropped when the number rounds to something that can be represented with fewer digits. For example,

julia> savename("test", (p1=3.5e-6,), sigdigits=4)
"test_p1=3.5e-6"
julia> savename("test", (p1=3.4999e-6,), sigdigits=4)
"test_p1=3.5e-6"

It would probably be more robust to use string formatting methods, for example the Printf.@sprintf macro, to produce the final string after using the round function.

I am using DrWatson v2.9.1 and julia version 1.7.3.

Great! Thanks a lot for the great bug report! I agree with your suggestion for the fix, if anyone wants to do a PR this seems rather simple!

rs7q5 commented

Adding Printf.@sprintf would also be useful for when using savename to create legend or plot annotation for when I want to keep trailing zeros to make them consistent.

edit: which is a feature I would like.

Hello, I tried working on this issue, making changes to the valtostring(val, digits, sigdigits) but I am unable to figure out an error. Can anyone please help me through it?

How do I pass a variable to the format string in @sprintf?
It works for constants, and solving this error/finding an alternative should solve this issue.

I am currently doing the following:

@sprintf("%.$(digits)f", val)

Which results in:

ERROR: LoadError: ArgumentError: First argument to `@sprintf` must be a format string.
Stacktrace:
 [1] var"@sprintf"(__source__::LineNumberNode, __module__::Module, fmt::Any, args::Vararg{Any})
   @ Printf C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Printf\src\Printf.jl:1030
 [2] include(mod::Module, _path::String)
   @ Base .\Base.jl:495
 [3] include(x::String)
   @ DrWatson C:\ADARSH\Julia\DrWatson.jl\src\DrWatson.jl:2
 [4] top-level scope
   @ C:\ADARSH\Julia\DrWatson.jl\src\DrWatson.jl:21
 [5] include
   @ Base .\Base.jl:495 [inlined]
 [6] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
   @ Base .\loading.jl:2216
 [7] top-level scope
   @ stdin:3
in expression starting at C:\ADARSH\Julia\DrWatson.jl\src\naming.jl:169
in expression starting at C:\ADARSH\Julia\DrWatson.jl\src\naming.jl:160
in expression starting at C:\ADARSH\Julia\DrWatson.jl\src\DrWatson.jl:1
in expression starting at stdin:
Stacktrace:
  [1] pkgerror(msg::String)
    @ Pkg.Types C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Pkg\src\Types.jl:70
  [2] precompile(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; internal_call::Bool, strict::Bool, warn_loaded::Bool, already_instantiated::Bool, timing::Bool, _from_loading::Bool, kwargs::@Kwargs{io::Base.TTY})  
    @ Pkg.API C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Pkg\src\API.jl:1656
  [3] precompile(pkgs::Vector{Pkg.Types.PackageSpec}; io::Base.TTY, kwargs::@Kwargs{_from_loading::Bool})
    @ Pkg.API C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Pkg\src\API.jl:159
  [4] precompile
    @ Pkg.API C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Pkg\src\API.jl:147 [inlined]
  [5] #precompile#114
    @ Pkg.API C:\Users\Adarsh\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Pkg\src\API.jl:146 [inlined]
  [6] #invokelatest#2
    @ Base .\essentials.jl:889 [inlined]
  [7] invokelatest
    @ Base .\essentials.jl:884 [inlined]
  [8] _require(pkg::Base.PkgId, env::String)
    @ Base .\loading.jl:1957
  [9] __require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1806
 [10] #invoke_in_world#3
    @ Base .\essentials.jl:921 [inlined]
 [11] invoke_in_world
    @ Base .\essentials.jl:918 [inlined]
 [12] _require_prelocked(uuidkey::Base.PkgId, env::String)
    @ Base .\loading.jl:1797
 [13] macro expansion
    @ Base .\loading.jl:1784 [inlined]
 [14] macro expansion
    @ Base .\lock.jl:267 [inlined]
 [15] __require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1747
 [16] #invoke_in_world#3
    @ Base .\essentials.jl:921 [inlined]
 [17] invoke_in_world
    @ Base .\essentials.jl:918 [inlined]
 [18] require(into::Module, mod::Symbol)
    @ Base .\loading.jl:1740

What can be the way out here? Is there an alternative method?