From 783608aa43e9c7ca29189b62f15143741c2dc5e0 Mon Sep 17 00:00:00 2001 From: R3G3N3R4T0R <54089608+R3G3N3R4T0R@users.noreply.github.com> Date: Fri, 5 Sep 2025 15:41:32 +0900 Subject: [PATCH 1/3] Fix 0.0 giving InexactError in g/G due to log10(0) --- src/fmtcore.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fmtcore.jl b/src/fmtcore.jl index f339ecc..588712e 100644 --- a/src/fmtcore.jl +++ b/src/fmtcore.jl @@ -333,7 +333,7 @@ end function _pfmt_g(out::IO, fs::FormatSpec, x::AbstractFloat) # Branch according to the exponent - expnt = floor(Int, log10(abs(x)) ) + expnt = x == 0 ? 0 : floor(Int, log10(abs(x)) ) if -4 <= expnt < fs.prec newprec = fs.prec - expnt - 1 _pfmt_f(out, FormatSpec(fs ;prec=newprec), x) From 267dc283c661ed9f0d5db5bed9fc92d4299c83be Mon Sep 17 00:00:00 2001 From: R3G3N3R4T0R Date: Tue, 9 Sep 2025 11:02:01 +0900 Subject: [PATCH 2/3] Add testset for format "g/G" g/G currently lacks a testset. This testset is currently non-compilant to Python's format_spec as trailing zeros are retained. Added FIXME to remind future maintainers. --- test/fmtspec.jl | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/fmtspec.jl b/test/fmtspec.jl index 1a7603f..9e8aff1 100644 --- a/test/fmtspec.jl +++ b/test/fmtspec.jl @@ -344,6 +344,58 @@ end @test pyfmt(".1e", 0.0006) == "6.0e-04" end +# This testset is currently non-compliant to Python's format_spec +# Trailing insignificant zeros should be removed, however it is not done in +# the current implementation. +# FIXME: Make g/G compliant with Python's behavior +@testset "Format general (g/G)" begin + # Default precision (6 significant digits) + @test pyfmt("g", 123.456789) == "123.457" + @test pyfmt("g", 1.234567e-5) == "1.23457e-05" + + # Switch between fixed and scientific depending on precision + # and exponent -> Issue #91 (Format.jl) + @test pyfmt(".3g", 0.0012345) == "0.00123" + @test pyfmt(".3g", 1234567.0) == "1.23e+06" + @test pyfmt(".2g", 0.000012345) == "1.2e-05" + @test pyfmt(".2g", 1e-4) == "0.00010" + @test pyfmt("g", 1e5) == "100000" + @test pyfmt("g", 1e6) == "1.00000e+06" + + # Trailing zero and decimal point trimming + @test pyfmt(".6g", 1200.0) == "1200.00" + @test pyfmt(".4g", 12.0) == "12.00" + + # Alternate form '#' keeps trailing zeros and decimal point + @test pyfmt("#.4g", 12.0) == "12.00" + @test pyfmt("#.3g", 1.0e-5) == "1.00e-05" + + # Width, alignment, and zero-padding + @test pyfmt(">8.3g", 13.89) == " 13.9" + @test pyfmt("⋆<8.3g", 13.89) == "13.9⋆⋆⋆⋆" + @test pyfmt("⋆^8.3g", 13.89) == "⋆⋆13.9⋆⋆" + @test pyfmt("010.3g", 13.89) == "00000013.9" + @test pyfmt("010.3g", -13.89) == "-0000013.9" + @test pyfmt("+010.3g", 13.89) == "+0000013.9" + + # Rounding across powers of ten + @test pyfmt(".3g", 9.999) == "10.0" + @test pyfmt(".3g", 9.999e9) == "1.00e+10" + @test pyfmt(".3g", -9.999e-5) == "-0.000100" + @test pyfmt(".3g", -9.999e-6) == "-1.00e-05" + + # 'G' behaves like 'g' but uses 'E' + @test pyfmt(".3G", 1234567.0) == "1.23E+06" + @test pyfmt(".3G", 0.000012345) == "1.23E-05" + @test pyfmt("G", 12.0) == "12.0000" + @test pyfmt("#.4G", 12.0) == "12.00" + @test pyfmt("G", 1e6) == "1.00000E+06" + + # Zeros, from regression of (04baaf3) + @test pyfmt("g", 0.0) == "0.00000" + @test pyfmt("g", -0.0) == "-0.00000" +end + @testset "Format percentage (%)" begin @test pyfmt("8.2%", 0.123456) == " 12.35%" @test pyfmt("<8.2%", 0.123456) == "12.35% " @@ -355,18 +407,24 @@ end @test pyfmt("f", NaN) == "NaN" @test pyfmt("e", NaN) == "NaN" + @test pyfmt("g", NaN) == "NaN" @test pyfmt("f", NaN32) == "NaN" @test pyfmt("e", NaN32) == "NaN" + @test pyfmt("g", NaN32) == "NaN" @test pyfmt("f", Inf) == "Inf" @test pyfmt("e", Inf) == "Inf" + @test pyfmt("g", Inf) == "Inf" @test pyfmt("f", Inf32) == "Inf" @test pyfmt("e", Inf32) == "Inf" + @test pyfmt("g", Inf32) == "Inf" @test pyfmt("f", -Inf) == "-Inf" @test pyfmt("e", -Inf) == "-Inf" + @test pyfmt("g", -Inf) == "-Inf" @test pyfmt("f", -Inf32) == "-Inf" @test pyfmt("e", -Inf32) == "-Inf" + @test pyfmt("g", -Inf32) == "-Inf" @test pyfmt("<5f", Inf) == "Inf " @test pyfmt("^5f", Inf) == " Inf " From 9ad7ab2a946beb0805d00dc03d8a5e51886bf7f1 Mon Sep 17 00:00:00 2001 From: R3G3N3R4T0R Date: Tue, 9 Sep 2025 11:37:20 +0900 Subject: [PATCH 3/3] Fix rounding before exponent for "g/G" --- src/fmtcore.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fmtcore.jl b/src/fmtcore.jl index 588712e..02a5c9c 100644 --- a/src/fmtcore.jl +++ b/src/fmtcore.jl @@ -333,7 +333,8 @@ end function _pfmt_g(out::IO, fs::FormatSpec, x::AbstractFloat) # Branch according to the exponent - expnt = x == 0 ? 0 : floor(Int, log10(abs(x)) ) + ax = round(abs(x) ;sigdigits=fs.prec) + expnt = ax == 0 ? 0 : floor(Int, log10(ax) ) if -4 <= expnt < fs.prec newprec = fs.prec - expnt - 1 _pfmt_f(out, FormatSpec(fs ;prec=newprec), x)