Skip to content

Commit b84cd8f

Browse files
committed
Modified Floatmu-to-string procedure to compute shortest string that round-trips, as required by IEEE 754 standard.
1 parent 794d75e commit b84cd8f

File tree

2 files changed

+42
-34
lines changed

2 files changed

+42
-34
lines changed

src/Floatmu.jl

+36-34
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121

2222
#import Formatting
23-
import Printf.@printf
23+
import Printf.@sprintf
2424
import Base.convert, Base.show, Base.Float16, Base.Float32, Base.Float64
2525
import Base.sign, Base.signbit, Base.bitstring
2626
import Base.typemin, Base.typemax, Base.maxintfloat, Base.ldexp, Base.eps
@@ -326,7 +326,7 @@ julia> eps(Floatmu{2, 2})
326326
0.25
327327
328328
julia> eps(Floatmu{3, 5})
329-
0.0312
329+
0.031
330330
331331
julia> eps(Floatmu{8, 23})==eps(Float32)
332332
true
@@ -818,13 +818,13 @@ julia> convert(Float32,Floatmu{5, 10}(0.1)) == Float16(0.1)
818818
true
819819
820820
julia> convert(Floatmu{2, 4},0.1)
821-
0.125
821+
0.12
822822
823823
julia> convert(Floatmu{2, 4},0.1f0)
824-
0.125
824+
0.12
825825
826826
julia> convert(Floatmu{2, 4},Float16(0.1))
827-
0.125
827+
0.12
828828
829829
julia> Floatmu{5, 10}(0.1)==Float16(0.1)
830830
true
@@ -978,35 +978,37 @@ function tryparse(::Type{Floatmu{szE,szf}}, str::AbstractString) where {szE, szf
978978
end
979979

980980

981-
# Hack to use @printf with a format depending on the `Floatmu` used.
982-
# Since @printf is a macro, it cannot be called with anything other than a constant
983-
# for the format string.
984-
# The number of digits used to display a value is chosen so as to ensure
985-
# a correct round-trip (``In-and-out conversions'', David Matula,
986-
# Comm. ACM, 11(1), Jan. 1968)
987-
variable_printf(io,x::Floatmu{szE,2}) where {szE} = @printf(io,"%.2g",convert(Float64,x))
988-
variable_printf(io,x::Floatmu{szE,3}) where {szE} = @printf(io,"%.3g",convert(Float64,x))
989-
variable_printf(io,x::Floatmu{szE,4}) where {szE} = @printf(io,"%.3g",convert(Float64,x))
990-
variable_printf(io,x::Floatmu{szE,5}) where {szE} = @printf(io,"%.3g",convert(Float64,x))
991-
variable_printf(io,x::Floatmu{szE,6}) where {szE} = @printf(io,"%.4g",convert(Float64,x))
992-
variable_printf(io,x::Floatmu{szE,7}) where {szE} = @printf(io,"%.4g",convert(Float64,x))
993-
variable_printf(io,x::Floatmu{szE,8}) where {szE} = @printf(io,"%.4g",convert(Float64,x))
994-
variable_printf(io,x::Floatmu{szE,9}) where {szE} = @printf(io,"%.5g",convert(Float64,x))
995-
variable_printf(io,x::Floatmu{szE,10}) where {szE} = @printf(io,"%.5g",convert(Float64,x))
996-
variable_printf(io,x::Floatmu{szE,11}) where {szE} = @printf(io,"%.5g",convert(Float64,x))
997-
variable_printf(io,x::Floatmu{szE,12}) where {szE} = @printf(io,"%.5g",convert(Float64,x))
998-
variable_printf(io,x::Floatmu{szE,13}) where {szE} = @printf(io,"%.6g",convert(Float64,x))
999-
variable_printf(io,x::Floatmu{szE,14}) where {szE} = @printf(io,"%.6g",convert(Float64,x))
1000-
variable_printf(io,x::Floatmu{szE,15}) where {szE} = @printf(io,"%.6g",convert(Float64,x))
1001-
variable_printf(io,x::Floatmu{szE,16}) where {szE} = @printf(io,"%.7g",convert(Float64,x))
1002-
variable_printf(io,x::Floatmu{szE,17}) where {szE} = @printf(io,"%.7g",convert(Float64,x))
1003-
variable_printf(io,x::Floatmu{szE,18}) where {szE} = @printf(io,"%.7g",convert(Float64,x))
1004-
variable_printf(io,x::Floatmu{szE,19}) where {szE} = @printf(io,"%.8g",convert(Float64,x))
1005-
variable_printf(io,x::Floatmu{szE,20}) where {szE} = @printf(io,"%.8g",convert(Float64,x))
1006-
variable_printf(io,x::Floatmu{szE,21}) where {szE} = @printf(io,"%.8g",convert(Float64,x))
1007-
variable_printf(io,x::Floatmu{szE,22}) where {szE} = @printf(io,"%.8g",convert(Float64,x))
1008-
variable_printf(io,x::Floatmu{szE,23}) where {szE} = @printf(io,"%.9g",convert(Float64,x))
981+
# Hack to use @sprintf with a format depending on the `Floatmu` used.
982+
# Since @sprintf is a macro, it cannot be called with anything other
983+
# than a constant for the format string.
984+
sprintf1(v) = @sprintf("%.1g",v)
985+
sprintf2(v) = @sprintf("%.2g",v)
986+
sprintf3(v) = @sprintf("%.3g",v)
987+
sprintf4(v) = @sprintf("%.4g",v)
988+
sprintf5(v) = @sprintf("%.5g",v)
989+
sprintf6(v) = @sprintf("%.6g",v)
990+
sprintf7(v) = @sprintf("%.7g",v)
991+
sprintf8(v) = @sprintf("%.8g",v)
992+
sprintf9(v) = @sprintf("%.9g",v)
993+
function sprintf(sz)
994+
return @eval ($(Symbol("sprintf$sz")))
995+
end
1009996

997+
# Computing the shortest decimal string that round-trips.
998+
function variable_printf(io, x)
999+
s = @sprintf("%.9g",x) # Using the largest precision possibly required
1000+
sz = 9
1001+
tx = typeof(x)
1002+
while true
1003+
s2 = sprintf(sz)(x)
1004+
if parse(tx,s2) != x || sz == 1
1005+
print(io,s)
1006+
return
1007+
end
1008+
s = s2
1009+
sz = sz - 1
1010+
end
1011+
end
10101012

10111013
function show(io::IO, x::Floatmu{szE,szf}) where {szE, szf}
10121014
if isnan(x)
@@ -1329,7 +1331,7 @@ part of the resulting range:
13291331
julia> collect(FloatmuIterator(Floatmu{2,2},-Inf,Inf,5))
13301332
6-element Vector{Floatmu{2, 2}}:
13311333
-Infμ{2, 2}
1332-
-1.75
1334+
-1.8
13331335
-0.5
13341336
0.75
13351337
2.0

test/display.jl

+6
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
@test string(Floatmu{8,23}(-3.2)) == string(Float32(-3.2))
1515
end;
1616

17+
@testset "roundtrip" begin
18+
for x in (3.22,-3.22,0.1,-0.1,14.89)
19+
@test parse(Floatmu{6,10},string(Floatmu{6,10}(x))) == Floatmu{6,10}(x)
20+
end
21+
end;
22+
1723
@testset "bitstring" begin
1824
@test bitstring(Floatmu{2,2}(0.0)) == "00000"
1925
@test bitstring(Floatmu{2,2}(-0.0)) == "10000"

0 commit comments

Comments
 (0)