Revision f442e4230a41d0d40f81346c1707f946f743cbcf authored by Jeff Bezanson on 09 June 2021, 02:51:34 UTC, committed by GitHub on 09 June 2021, 02:51:34 UTC
This PR implements a way to keep tables of methods that are
not part of the internal method table, but still participate
in the special support we have for keeping tables of methods,
in particular unification through precompilation and efficient
lookup. The intended design use case is to allow for method overlay
tables for various non-CPU backends (e.g. GPU and TPU). These
backends would like to modify basic function like `sin` to
perform better on the device in question (or in the case of TPU
to define them over non-LLVM intrinsics).

It is worth noting that this PR only gives the ability to keep
these tables of methods. It assigns no particular meaning to them
and the runtime (and regular inference) do not look at them.
They are designed as an implementation detail for external
compilers and similar tools.

 # Demo

```julia
julia> using Base.Experimental: @overlay, @MethodTable

julia> @MethodTable(mt)
 # 0 methods:

julia> @overlay mt function sin(x::Float64)
           1
       end

julia> @overlay mt function cos(x::Float64)
           1
       end

julia> mt
 # 2 methods:
[1] cos(x::Float64) in Main at REPL[5]:1
[2] sin(x::Float64) in Main at REPL[4]:1

julia> Base._methods_by_ftype(Tuple{typeof(sin), Float64}, mt, 1, typemax(UInt))
1-element Vector{Any}:
 Core.MethodMatch(Tuple{typeof(sin), Float64}, svec(), sin(x::Float64) in Main at REPL[4]:1, true)

julia> Base._methods_by_ftype(Tuple{typeof(sin), Float64}, 1, typemax(UInt))
1-element Vector{Any}:
 Core.MethodMatch(Tuple{typeof(sin), Float64}, svec(Float64), sin(x::T) where T<:Union{Float32, Float64} in Base.Math at special/trig.jl:29, true)
```

Co-authored-by: Tim Besard <tim.besard@gmail.com>
Co-authored-by: Julian P Samaroo <jpsamaroo@jpsamaroo.me>
Co-authored-by: Keno Fischer <keno@juliacomputing.com>
1 parent 0e3276c
Raw File
ryu.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Base.Ryu

const maxMantissa = (UInt64(1) << 53) - 1
todouble(sign, exp, mant) = Core.bitcast(Float64, (UInt64(sign) << 63) | (UInt64(exp) << 52) | (UInt64(mant)))

@testset "Ryu" begin

@testset "Float64" begin

@testset "Basic" begin
    @test Ryu.writeshortest(0.0) == "0.0"
    @test Ryu.writeshortest(-0.0) == "-0.0"
    @test Ryu.writeshortest(1.0) == "1.0"
    @test Ryu.writeshortest(-1.0) == "-1.0"
    @test Ryu.writeshortest(NaN) == "NaN"
    @test Ryu.writeshortest(Inf) == "Inf"
    @test Ryu.writeshortest(-Inf) == "-Inf"
end

@testset "SwitchToSubnormal" begin
    @test "2.2250738585072014e-308" == Ryu.writeshortest(2.2250738585072014e-308)
end

@testset "MinAndMax" begin
    @test "1.7976931348623157e308" == Ryu.writeshortest(Core.bitcast(Float64, 0x7fefffffffffffff))
    @test "5.0e-324" == Ryu.writeshortest(Core.bitcast(Float64, Int64(1)))
end

@testset "LotsOfTrailingZeros" begin
    @test "2.9802322387695312e-8" == Ryu.writeshortest(2.98023223876953125e-8)
end

@testset "Regression" begin
    @test "-2.109808898695963e16" == Ryu.writeshortest(-2.109808898695963e16)
    @test "4.940656e-318" == Ryu.writeshortest(4.940656e-318)
    @test "1.18575755e-316" == Ryu.writeshortest(1.18575755e-316)
    @test "2.989102097996e-312" == Ryu.writeshortest(2.989102097996e-312)
    @test "9.0608011534336e15" == Ryu.writeshortest(9.0608011534336e15)
    @test "4.708356024711512e18" == Ryu.writeshortest(4.708356024711512e18)
    @test "9.409340012568248e18" == Ryu.writeshortest(9.409340012568248e18)
    @test "1.2345678" == Ryu.writeshortest(1.2345678)
end

@testset "LooksLikePow5" begin
    # These numbers have a mantissa that is a multiple of the largest power of 5 that fits,
    # and an exponent that causes the computation for q to result in 22, which is a corner
    # case for Ryu.
    @test "5.764607523034235e39" == Ryu.writeshortest(Core.bitcast(Float64, 0x4830F0CF064DD592))
    @test "1.152921504606847e40" == Ryu.writeshortest(Core.bitcast(Float64, 0x4840F0CF064DD592))
    @test "2.305843009213694e40" == Ryu.writeshortest(Core.bitcast(Float64, 0x4850F0CF064DD592))
end

@testset "OutputLength" begin
    @test "1.0" == Ryu.writeshortest(1.0) # already tested in Basic
    @test "1.2" == Ryu.writeshortest(1.2)
    @test "1.23" == Ryu.writeshortest(1.23)
    @test "1.234" == Ryu.writeshortest(1.234)
    @test "1.2345" == Ryu.writeshortest(1.2345)
    @test "1.23456" == Ryu.writeshortest(1.23456)
    @test "1.234567" == Ryu.writeshortest(1.234567)
    @test "1.2345678" == Ryu.writeshortest(1.2345678) # already tested in Regressi
    @test "1.23456789" == Ryu.writeshortest(1.23456789)
    @test "1.234567895" == Ryu.writeshortest(1.234567895) # 1.234567890 would be trimm
    @test "1.2345678901" == Ryu.writeshortest(1.2345678901)
    @test "1.23456789012" == Ryu.writeshortest(1.23456789012)
    @test "1.234567890123" == Ryu.writeshortest(1.234567890123)
    @test "1.2345678901234" == Ryu.writeshortest(1.2345678901234)
    @test "1.23456789012345" == Ryu.writeshortest(1.23456789012345)
    @test "1.234567890123456" == Ryu.writeshortest(1.234567890123456)
    @test "1.2345678901234567" == Ryu.writeshortest(1.2345678901234567)

  # Test 32-bit chunking
    @test "4.294967294" == Ryu.writeshortest(4.294967294) # 2^32 -
    @test "4.294967295" == Ryu.writeshortest(4.294967295) # 2^32 -
    @test "4.294967296" == Ryu.writeshortest(4.294967296) # 2^
    @test "4.294967297" == Ryu.writeshortest(4.294967297) # 2^32 +
    @test "4.294967298" == Ryu.writeshortest(4.294967298) # 2^32 +
end

# Test min, max shift values in shiftright128
@testset "MinMaxShift" begin
    # 32-bit opt-size=0:  49 <= dist <= 50
    # 32-bit opt-size=1:  30 <= dist <= 50
    # 64-bit opt-size=0:  50 <= dist <= 50
    # 64-bit opt-size=1:  30 <= dist <= 50
    @test "1.7800590868057611e-307" == Ryu.writeshortest(todouble(false, 4, 0))
    # 32-bit opt-size=0:  49 <= dist <= 49
    # 32-bit opt-size=1:  28 <= dist <= 49
    # 64-bit opt-size=0:  50 <= dist <= 50
    # 64-bit opt-size=1:  28 <= dist <= 50
    @test "2.8480945388892175e-306" == Ryu.writeshortest(todouble(false, 6, maxMantissa))
    # 32-bit opt-size=0:  52 <= dist <= 53
    # 32-bit opt-size=1:   2 <= dist <= 53
    # 64-bit opt-size=0:  53 <= dist <= 53
    # 64-bit opt-size=1:   2 <= dist <= 53
    @test "2.446494580089078e-296" == Ryu.writeshortest(todouble(false, 41, 0))
    # 32-bit opt-size=0:  52 <= dist <= 52
    # 32-bit opt-size=1:   2 <= dist <= 52
    # 64-bit opt-size=0:  53 <= dist <= 53
    # 64-bit opt-size=1:   2 <= dist <= 53
    @test "4.8929891601781557e-296" == Ryu.writeshortest(todouble(false, 40, maxMantissa))

    # 32-bit opt-size=0:  57 <= dist <= 58
    # 32-bit opt-size=1:  57 <= dist <= 58
    # 64-bit opt-size=0:  58 <= dist <= 58
    # 64-bit opt-size=1:  58 <= dist <= 58
    @test "1.8014398509481984e16" == Ryu.writeshortest(todouble(false, 1077, 0))
    # 32-bit opt-size=0:  57 <= dist <= 57
    # 32-bit opt-size=1:  57 <= dist <= 57
    # 64-bit opt-size=0:  58 <= dist <= 58
    # 64-bit opt-size=1:  58 <= dist <= 58
    @test "3.6028797018963964e16" == Ryu.writeshortest(todouble(false, 1076, maxMantissa))
    # 32-bit opt-size=0:  51 <= dist <= 52
    # 32-bit opt-size=1:  51 <= dist <= 59
    # 64-bit opt-size=0:  52 <= dist <= 52
    # 64-bit opt-size=1:  52 <= dist <= 59
    @test "2.900835519859558e-216" == Ryu.writeshortest(todouble(false, 307, 0))
    # 32-bit opt-size=0:  51 <= dist <= 51
    # 32-bit opt-size=1:  51 <= dist <= 59
    # 64-bit opt-size=0:  52 <= dist <= 52
    # 64-bit opt-size=1:  52 <= dist <= 59
    @test "5.801671039719115e-216" == Ryu.writeshortest(todouble(false, 306, maxMantissa))

    # https:#github.com/ulfjack/ryu/commit/19e44d16d80236f5de25800f56d82606d1be00b9#commitcomment-30146483
    # 32-bit opt-size=0:  49 <= dist <= 49
    # 32-bit opt-size=1:  44 <= dist <= 49
    # 64-bit opt-size=0:  50 <= dist <= 50
    # 64-bit opt-size=1:  44 <= dist <= 50
    @test "3.196104012172126e-27" == Ryu.writeshortest(todouble(false, 934, 0x000FA7161A4D6E0C))
end

@testset "SmallIntegers" begin
    @test "9.007199254740991e15" == Ryu.writeshortest(9007199254740991.0)
    @test "9.007199254740992e15" == Ryu.writeshortest(9007199254740992.0)

    @test "1.0" == Ryu.writeshortest(1.0e+0)
    @test "12.0" == Ryu.writeshortest(1.2e+1)
    @test "123.0" == Ryu.writeshortest(1.23e+2)
    @test "1234.0" == Ryu.writeshortest(1.234e+3)
    @test "12345.0" == Ryu.writeshortest(1.2345e+4)
    @test "123456.0" == Ryu.writeshortest(1.23456e+5)
    @test "1.234567e6" == Ryu.writeshortest(1.234567e+6)
    @test "1.2345678e7" == Ryu.writeshortest(1.2345678e+7)
    @test "1.23456789e8" == Ryu.writeshortest(1.23456789e+8)
    @test "1.23456789e9" == Ryu.writeshortest(1.23456789e+9)
    @test "1.234567895e9" == Ryu.writeshortest(1.234567895e+9)
    @test "1.2345678901e10" == Ryu.writeshortest(1.2345678901e+10)
    @test "1.23456789012e11" == Ryu.writeshortest(1.23456789012e+11)
    @test "1.234567890123e12" == Ryu.writeshortest(1.234567890123e+12)
    @test "1.2345678901234e13" == Ryu.writeshortest(1.2345678901234e+13)
    @test "1.23456789012345e14" == Ryu.writeshortest(1.23456789012345e+14)
    @test "1.234567890123456e15" == Ryu.writeshortest(1.234567890123456e+15)

  # 10^i
    @test "1.0" == Ryu.writeshortest(1.0e+0)
    @test "10.0" == Ryu.writeshortest(1.0e+1)
    @test "100.0" == Ryu.writeshortest(1.0e+2)
    @test "1000.0" == Ryu.writeshortest(1.0e+3)
    @test "10000.0" == Ryu.writeshortest(1.0e+4)
    @test "100000.0" == Ryu.writeshortest(1.0e+5)
    @test "1.0e6" == Ryu.writeshortest(1.0e+6)
    @test "1.0e7" == Ryu.writeshortest(1.0e+7)
    @test "1.0e8" == Ryu.writeshortest(1.0e+8)
    @test "1.0e9" == Ryu.writeshortest(1.0e+9)
    @test "1.0e10" == Ryu.writeshortest(1.0e+10)
    @test "1.0e11" == Ryu.writeshortest(1.0e+11)
    @test "1.0e12" == Ryu.writeshortest(1.0e+12)
    @test "1.0e13" == Ryu.writeshortest(1.0e+13)
    @test "1.0e14" == Ryu.writeshortest(1.0e+14)
    @test "1.0e15" == Ryu.writeshortest(1.0e+15)

  # 10^15 + 10^i
    @test "1.000000000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+0)
    @test "1.00000000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+1)
    @test "1.0000000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+2)
    @test "1.000000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+3)
    @test "1.00000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+4)
    @test "1.0000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+5)
    @test "1.000000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+6)
    @test "1.00000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+7)
    @test "1.0000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+8)
    @test "1.000001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+9)
    @test "1.00001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+10)
    @test "1.0001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+11)
    @test "1.001e15" == Ryu.writeshortest(1.0e+15 + 1.0e+12)
    @test "1.01e15" == Ryu.writeshortest(1.0e+15 + 1.0e+13)
    @test "1.1e15" == Ryu.writeshortest(1.0e+15 + 1.0e+14)

  # Largest power of 2 <= 10^(i+1)
    @test "8.0" == Ryu.writeshortest(8.0)
    @test "64.0" == Ryu.writeshortest(64.0)
    @test "512.0" == Ryu.writeshortest(512.0)
    @test "8192.0" == Ryu.writeshortest(8192.0)
    @test "65536.0" == Ryu.writeshortest(65536.0)
    @test "524288.0" == Ryu.writeshortest(524288.0)
    @test "8.388608e6" == Ryu.writeshortest(8388608.0)
    @test "6.7108864e7" == Ryu.writeshortest(67108864.0)
    @test "5.36870912e8" == Ryu.writeshortest(536870912.0)
    @test "8.589934592e9" == Ryu.writeshortest(8589934592.0)
    @test "6.8719476736e10" == Ryu.writeshortest(68719476736.0)
    @test "5.49755813888e11" == Ryu.writeshortest(549755813888.0)
    @test "8.796093022208e12" == Ryu.writeshortest(8796093022208.0)
    @test "7.0368744177664e13" == Ryu.writeshortest(70368744177664.0)
    @test "5.62949953421312e14" == Ryu.writeshortest(562949953421312.0)
    @test "9.007199254740992e15" == Ryu.writeshortest(9007199254740992.0)

  # 1000 * (Largest power of 2 <= 10^(i+1))
    @test "8000.0" == Ryu.writeshortest(8.0e+3)
    @test "64000.0" == Ryu.writeshortest(64.0e+3)
    @test "512000.0" == Ryu.writeshortest(512.0e+3)
    @test "8.192e6" == Ryu.writeshortest(8192.0e+3)
    @test "6.5536e7" == Ryu.writeshortest(65536.0e+3)
    @test "5.24288e8" == Ryu.writeshortest(524288.0e+3)
    @test "8.388608e9" == Ryu.writeshortest(8388608.0e+3)
    @test "6.7108864e10" == Ryu.writeshortest(67108864.0e+3)
    @test "5.36870912e11" == Ryu.writeshortest(536870912.0e+3)
    @test "8.589934592e12" == Ryu.writeshortest(8589934592.0e+3)
    @test "6.8719476736e13" == Ryu.writeshortest(68719476736.0e+3)
    @test "5.49755813888e14" == Ryu.writeshortest(549755813888.0e+3)
    @test "8.796093022208e15" == Ryu.writeshortest(8796093022208.0e+3)
end

end # Float64

@testset "Float32" begin

@testset "Basic" begin
    @test "0.0" == Ryu.writeshortest(Float32(0.0))
    @test "-0.0" == Ryu.writeshortest(Float32(-0.0))
    @test "1.0" == Ryu.writeshortest(Float32(1.0))
    @test "-1.0" == Ryu.writeshortest(Float32(-1.0))
    @test "NaN" == Ryu.writeshortest(Float32(NaN))
    @test "Inf" == Ryu.writeshortest(Float32(Inf))
    @test "-Inf" == Ryu.writeshortest(Float32(-Inf))
end

@testset "SwitchToSubnormal" begin
    @test "1.1754944e-38" == Ryu.writeshortest(1.1754944f-38)
end

@testset "MinAndMax" begin
    @test "3.4028235e38" == Ryu.writeshortest(Core.bitcast(Float32, 0x7f7fffff))
    @test "1.0e-45" == Ryu.writeshortest(Core.bitcast(Float32, Int32(1)))
end

# Check that we return the exact boundary if it is the shortest
# representation, but only if the original floating point number is even.
@testset "BoundaryRoundeven" begin
    @test "3.355445e7" == Ryu.writeshortest(3.355445f7)
    @test "9.0e9" == Ryu.writeshortest(8.999999f9)
    @test "3.436672e10" == Ryu.writeshortest(3.4366717f10)
end

# If the exact value is exactly halfway between two shortest representations,
# then we round to even. It seems like this only makes a difference if the
# last two digits are ...2|5 or ...7|5, and we cut off the 5.
@testset "exactValueRoundeven" begin
    @test "305404.12" == Ryu.writeshortest(3.0540412f5)
    @test "8099.0312" == Ryu.writeshortest(8.0990312f3)
end

@testset "LotsOfTrailingZeros" begin
    # Pattern for the first test: 00111001100000000000000000000000
    @test "0.00024414062" == Ryu.writeshortest(2.4414062f-4)
    @test "0.0024414062" == Ryu.writeshortest(2.4414062f-3)
    @test "0.0043945312" == Ryu.writeshortest(4.3945312f-3)
    @test "0.0063476562" == Ryu.writeshortest(6.3476562f-3)
end

@testset "Regression" begin
    @test "4.7223665e21" == Ryu.writeshortest(4.7223665f21)
    @test "8.388608e6" == Ryu.writeshortest(8388608f0)
    @test "1.6777216e7" == Ryu.writeshortest(1.6777216f7)
    @test "3.3554436e7" == Ryu.writeshortest(3.3554436f7)
    @test "6.7131496e7" == Ryu.writeshortest(6.7131496f7)
    @test "1.9310392e-38" == Ryu.writeshortest(1.9310392f-38)
    @test "-2.47e-43" == Ryu.writeshortest(-2.47f-43)
    @test "1.993244e-38" == Ryu.writeshortest(1.993244f-38)
    @test "4103.9004" == Ryu.writeshortest(4103.9003f0)
    @test "5.3399997e9" == Ryu.writeshortest(5.3399997f9)
    @test "6.0898e-39" == Ryu.writeshortest(6.0898f-39)
    @test "0.0010310042" == Ryu.writeshortest(0.0010310042f0)
    @test "2.882326e17" == Ryu.writeshortest(2.8823261f17)
    @test "7.038531e-26" == Ryu.writeshortest(7.0385309f-26)
    @test "9.223404e17" == Ryu.writeshortest(9.2234038f17)
    @test "6.710887e7" == Ryu.writeshortest(6.7108872f7)
    @test "1.0e-44" == Ryu.writeshortest(1.0f-44)
    @test "2.816025e14" == Ryu.writeshortest(2.816025f14)
    @test "9.223372e18" == Ryu.writeshortest(9.223372f18)
    @test "1.5846086e29" == Ryu.writeshortest(1.5846085f29)
    @test "1.1811161e19" == Ryu.writeshortest(1.1811161f19)
    @test "5.368709e18" == Ryu.writeshortest(5.368709f18)
    @test "4.6143166e18" == Ryu.writeshortest(4.6143165f18)
    @test "0.007812537" == Ryu.writeshortest(0.007812537f0)
    @test "1.0e-45" == Ryu.writeshortest(1.4f-45)
    @test "1.18697725e20" == Ryu.writeshortest(1.18697724f20)
    @test "1.00014165e-36" == Ryu.writeshortest(1.00014165f-36)
    @test "200.0" == Ryu.writeshortest(200f0)
    @test "3.3554432e7" == Ryu.writeshortest(3.3554432f7)
end

@testset "LooksLikePow5" begin
    # These numbers have a mantissa that is the largest power of 5 that fits,
    # and an exponent that causes the computation for q to result in 10, which is a corner
    # case for Ryu.
    @test "6.7108864e17" == Ryu.writeshortest(Core.bitcast(Float32, 0x5D1502F9))
    @test "1.3421773e18" == Ryu.writeshortest(Core.bitcast(Float32, 0x5D9502F9))
    @test "2.6843546e18" == Ryu.writeshortest(Core.bitcast(Float32, 0x5E1502F9))
end

@testset "OutputLength" begin
    @test "1.0" == Ryu.writeshortest(Float32(1.0))
    @test "1.2" == Ryu.writeshortest(Float32(1.2))
    @test "1.23" == Ryu.writeshortest(Float32(1.23))
    @test "1.234" == Ryu.writeshortest(Float32(1.234))
    @test "1.2345" == Ryu.writeshortest(Float32(1.2345))
    @test "1.23456" == Ryu.writeshortest(Float32(1.23456))
    @test "1.234567" == Ryu.writeshortest(Float32(1.234567))
    @test "1.2345678" == Ryu.writeshortest(Float32(1.2345678))
    @test "1.23456735e-36" == Ryu.writeshortest(Float32(1.23456735e-36))
end

end # Float32

@testset "Float16" begin

@testset "Basic" begin
    @test "0.0" == Ryu.writeshortest(Float16(0.0))
    @test "-0.0" == Ryu.writeshortest(Float16(-0.0))
    @test "1.0" == Ryu.writeshortest(Float16(1.0))
    @test "-1.0" == Ryu.writeshortest(Float16(-1.0))
    @test "NaN" == Ryu.writeshortest(Float16(NaN))
    @test "Inf" == Ryu.writeshortest(Float16(Inf))
    @test "-Inf" == Ryu.writeshortest(Float16(-Inf))
end

let x=floatmin(Float16)
    while x <= floatmax(Float16)
        @test parse(Float16, Ryu.writeshortest(x)) == x
        x = nextfloat(x)
    end
end

# function testfloats(T)
#     x = floatmin(T)
#     i = 0
#     fails = 0
#     success = 0
#     while x < floatmax(T)
#         test = parse(T, Ryu.writeshortest(x)) == x
#         if !test

#             fails += 1
#         else
#             success += 1
#         end
#         x = nextfloat(x)
#         i += 1

#     end
#     return fails / (fails + success)
# end

end # Float16

@testset "Ryu.writefixed" begin
    @testset "Basic" begin
        @test Ryu.writefixed(todouble(false, 1234, 99999), 0) ==
            "3291009114715486435425664845573426149758869524108446525879746560"
    end
    @testset "Zero" begin
        @test Ryu.writefixed(0.0, 4) == "0.0000"
        @test Ryu.writefixed(0.0, 3) == "0.000"
        @test Ryu.writefixed(0.0, 2) == "0.00"
        @test Ryu.writefixed(0.0, 1) == "0.0"
        @test Ryu.writefixed(0.0, 0) == "0"
    end
    @testset "MinMax" begin
        @test Ryu.writefixed(todouble(false, 0, 1), 1074) ==
            "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" *
            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" *
            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" *
            "000000000000000000000000000000000000000000000000000000049406564584124654417656879286822137" *
            "236505980261432476442558568250067550727020875186529983636163599237979656469544571773092665" *
            "671035593979639877479601078187812630071319031140452784581716784898210368871863605699873072" *
            "305000638740915356498438731247339727316961514003171538539807412623856559117102665855668676" *
            "818703956031062493194527159149245532930545654440112748012970999954193198940908041656332452" *
            "475714786901472678015935523861155013480352649347201937902681071074917033322268447533357208" *
            "324319360923828934583680601060115061698097530783422773183292479049825247307763759272478746" *
            "560847782037344696995336470179726777175851256605511991315048911014510378627381672509558373" *
            "89733598993664809941164205702637090279242767544565229087538682506419718265533447265625"
        @test Ryu.writefixed(todouble(false, 2046, 0xFFFFFFFFFFFFF), 0) ==
            "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558" *
            "632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245" *
            "490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168" *
            "738177180919299881250404026184124858368"
    end
    @testset "RoundToEven" begin
        @test Ryu.writefixed(0.125, 3) == "0.125"
        @test Ryu.writefixed(0.125, 2) == "0.12"
        @test Ryu.writefixed(0.375, 3) == "0.375"
        @test Ryu.writefixed(0.375, 2) == "0.38"
    end
    @testset "RoundToEvenInteger" begin
        @test Ryu.writefixed(2.5, 1) == "2.5"
        @test Ryu.writefixed(2.5, 0) == "2"
        @test Ryu.writefixed(3.5, 1) == "3.5"
        @test Ryu.writefixed(3.5, 0) == "4"
    end
    @testset "NonRoundToEvenScenarios" begin
        @test Ryu.writefixed(0.748046875, 3) == "0.748"
        @test Ryu.writefixed(0.748046875, 2) == "0.75"
        @test Ryu.writefixed(0.748046875, 1) == "0.7"

        @test Ryu.writefixed(0.2509765625, 3) == "0.251"
        @test Ryu.writefixed(0.2509765625, 2) == "0.25"
        @test Ryu.writefixed(0.2509765625, 1) == "0.3"

        @test Ryu.writefixed(todouble(false, 1021, 1), 54) == "0.250000000000000055511151231257827021181583404541015625"
        @test Ryu.writefixed(todouble(false, 1021, 1),  3) == "0.250"
        @test Ryu.writefixed(todouble(false, 1021, 1),  2) == "0.25"
        @test Ryu.writefixed(todouble(false, 1021, 1),  1) == "0.3"
    end
    @testset "VaryingPrecision" begin
        @test Ryu.writefixed(1729.142857142857, 47) == "1729.14285714285711037518922239542007446289062500000"
        @test Ryu.writefixed(1729.142857142857, 46) == "1729.1428571428571103751892223954200744628906250000"
        @test Ryu.writefixed(1729.142857142857, 45) == "1729.142857142857110375189222395420074462890625000"
        @test Ryu.writefixed(1729.142857142857, 44) == "1729.14285714285711037518922239542007446289062500"
        @test Ryu.writefixed(1729.142857142857, 43) == "1729.1428571428571103751892223954200744628906250"
        @test Ryu.writefixed(1729.142857142857, 42) == "1729.142857142857110375189222395420074462890625"
        @test Ryu.writefixed(1729.142857142857, 41) == "1729.14285714285711037518922239542007446289062"
        @test Ryu.writefixed(1729.142857142857, 40) == "1729.1428571428571103751892223954200744628906"
        @test Ryu.writefixed(1729.142857142857, 39) == "1729.142857142857110375189222395420074462891"
        @test Ryu.writefixed(1729.142857142857, 38) == "1729.14285714285711037518922239542007446289"
        @test Ryu.writefixed(1729.142857142857, 37) == "1729.1428571428571103751892223954200744629"
        @test Ryu.writefixed(1729.142857142857, 36) == "1729.142857142857110375189222395420074463"
        @test Ryu.writefixed(1729.142857142857, 35) == "1729.14285714285711037518922239542007446"
        @test Ryu.writefixed(1729.142857142857, 34) == "1729.1428571428571103751892223954200745"
        @test Ryu.writefixed(1729.142857142857, 33) == "1729.142857142857110375189222395420074"
        @test Ryu.writefixed(1729.142857142857, 32) == "1729.14285714285711037518922239542007"
        @test Ryu.writefixed(1729.142857142857, 31) == "1729.1428571428571103751892223954201"
        @test Ryu.writefixed(1729.142857142857, 30) == "1729.142857142857110375189222395420"
        @test Ryu.writefixed(1729.142857142857, 29) == "1729.14285714285711037518922239542"
        @test Ryu.writefixed(1729.142857142857, 28) == "1729.1428571428571103751892223954"
        @test Ryu.writefixed(1729.142857142857, 27) == "1729.142857142857110375189222395"
        @test Ryu.writefixed(1729.142857142857, 26) == "1729.14285714285711037518922240"
        @test Ryu.writefixed(1729.142857142857, 25) == "1729.1428571428571103751892224"
        @test Ryu.writefixed(1729.142857142857, 24) == "1729.142857142857110375189222"
        @test Ryu.writefixed(1729.142857142857, 23) == "1729.14285714285711037518922"
        @test Ryu.writefixed(1729.142857142857, 22) == "1729.1428571428571103751892"
        @test Ryu.writefixed(1729.142857142857, 21) == "1729.142857142857110375189"
        @test Ryu.writefixed(1729.142857142857, 20) == "1729.14285714285711037519"
        @test Ryu.writefixed(1729.142857142857, 19) == "1729.1428571428571103752"
        @test Ryu.writefixed(1729.142857142857, 18) == "1729.142857142857110375"
        @test Ryu.writefixed(1729.142857142857, 17) == "1729.14285714285711038"
        @test Ryu.writefixed(1729.142857142857, 16) == "1729.1428571428571104"
        @test Ryu.writefixed(1729.142857142857, 15) == "1729.142857142857110"
        @test Ryu.writefixed(1729.142857142857, 14) == "1729.14285714285711"
        @test Ryu.writefixed(1729.142857142857, 13) == "1729.1428571428571"
        @test Ryu.writefixed(1729.142857142857, 12) == "1729.142857142857"
        @test Ryu.writefixed(1729.142857142857, 11) == "1729.14285714286"
        @test Ryu.writefixed(1729.142857142857, 10) == "1729.1428571429"
        @test Ryu.writefixed(1729.142857142857,  9) == "1729.142857143"
        @test Ryu.writefixed(1729.142857142857,  8) == "1729.14285714"
        @test Ryu.writefixed(1729.142857142857,  7) == "1729.1428571"
        @test Ryu.writefixed(1729.142857142857,  6) == "1729.142857"
        @test Ryu.writefixed(1729.142857142857,  5) == "1729.14286"
        @test Ryu.writefixed(1729.142857142857,  4) == "1729.1429"
        @test Ryu.writefixed(1729.142857142857,  3) == "1729.143"
        @test Ryu.writefixed(1729.142857142857,  2) == "1729.14"
        @test Ryu.writefixed(1729.142857142857,  1) == "1729.1"
        @test Ryu.writefixed(1729.142857142857,  0) == "1729"
    end

    @testset "Carrying" begin
        @test Ryu.writefixed(  0.0009, 4) == "0.0009"
        @test Ryu.writefixed(  0.0009, 3) == "0.001"
        @test Ryu.writefixed(  0.0029, 4) == "0.0029"
        @test Ryu.writefixed(  0.0029, 3) == "0.003"
        @test Ryu.writefixed(  0.0099, 4) == "0.0099"
        @test Ryu.writefixed(  0.0099, 3) == "0.010"
        @test Ryu.writefixed(  0.0299, 4) == "0.0299"
        @test Ryu.writefixed(  0.0299, 3) == "0.030"
        @test Ryu.writefixed(  0.0999, 4) == "0.0999"
        @test Ryu.writefixed(  0.0999, 3) == "0.100"
        @test Ryu.writefixed(  0.2999, 4) == "0.2999"
        @test Ryu.writefixed(  0.2999, 3) == "0.300"
        @test Ryu.writefixed(  0.9999, 4) == "0.9999"
        @test Ryu.writefixed(  0.9999, 3) == "1.000"
        @test Ryu.writefixed(  2.9999, 4) == "2.9999"
        @test Ryu.writefixed(  2.9999, 3) == "3.000"
        @test Ryu.writefixed(  9.9999, 4) == "9.9999"
        @test Ryu.writefixed(  9.9999, 3) == "10.000"
        @test Ryu.writefixed( 29.9999, 4) == "29.9999"
        @test Ryu.writefixed( 29.9999, 3) == "30.000"
        @test Ryu.writefixed( 99.9999, 4) == "99.9999"
        @test Ryu.writefixed( 99.9999, 3) == "100.000"
        @test Ryu.writefixed(299.9999, 4) == "299.9999"
        @test Ryu.writefixed(299.9999, 3) == "300.000"

        @test Ryu.writefixed(  0.09, 2) == "0.09"
        @test Ryu.writefixed(  0.09, 1) == "0.1"
        @test Ryu.writefixed(  0.29, 2) == "0.29"
        @test Ryu.writefixed(  0.29, 1) == "0.3"
        @test Ryu.writefixed(  0.99, 2) == "0.99"
        @test Ryu.writefixed(  0.99, 1) == "1.0"
        @test Ryu.writefixed(  2.99, 2) == "2.99"
        @test Ryu.writefixed(  2.99, 1) == "3.0"
        @test Ryu.writefixed(  9.99, 2) == "9.99"
        @test Ryu.writefixed(  9.99, 1) == "10.0"
        @test Ryu.writefixed( 29.99, 2) == "29.99"
        @test Ryu.writefixed( 29.99, 1) == "30.0"
        @test Ryu.writefixed( 99.99, 2) == "99.99"
        @test Ryu.writefixed( 99.99, 1) == "100.0"
        @test Ryu.writefixed(299.99, 2) == "299.99"
        @test Ryu.writefixed(299.99, 1) == "300.0"

        @test Ryu.writefixed(  0.9, 1) == "0.9"
        @test Ryu.writefixed(  0.9, 0) == "1"
        @test Ryu.writefixed(  2.9, 1) == "2.9"
        @test Ryu.writefixed(  2.9, 0) == "3"
        @test Ryu.writefixed(  9.9, 1) == "9.9"
        @test Ryu.writefixed(  9.9, 0) == "10"
        @test Ryu.writefixed( 29.9, 1) == "29.9"
        @test Ryu.writefixed( 29.9, 0) == "30"
        @test Ryu.writefixed( 99.9, 1) == "99.9"
        @test Ryu.writefixed( 99.9, 0) == "100"
        @test Ryu.writefixed(299.9, 1) == "299.9"
        @test Ryu.writefixed(299.9, 0) == "300"
    end

    @testset "RoundingResultZero" begin
        @test Ryu.writefixed(0.004, 3) == "0.004"
        @test Ryu.writefixed(0.004, 2) == "0.00"
        @test Ryu.writefixed(0.4, 1) == "0.4"
        @test Ryu.writefixed(0.4, 0) == "0"
        @test Ryu.writefixed(0.5, 1) == "0.5"
        @test Ryu.writefixed(0.5, 0) == "0"
    end

    @testset "Regression" begin
        @test Ryu.writefixed(7.018232e-82, 6) == "0.000000"
    end

    @testset "Trimming of trailing zeros" begin
        @test Ryu.writefixed(0.0, 1, false, false, false, UInt8('.'), true) == "0"
        @test Ryu.writefixed(1.0, 1, false, false, false, UInt8('.'), true) == "1"
        @test Ryu.writefixed(2.0, 1, false, false, false, UInt8('.'), true) == "2"

        @test Ryu.writefixed(1.25e+5, 0, false, false, false, UInt8('.'), true) == "125000"
        @test Ryu.writefixed(1.25e+5, 1, false, false, false, UInt8('.'), true) == "125000"
        @test Ryu.writefixed(1.25e+5, 2, false, false, false, UInt8('.'), true) == "125000"
    end
end # fixed

@testset "Ryu.writeexp" begin

@testset "Basic" begin
    @test Ryu.writeexp(todouble(false, 1234, 99999), 62) ==
    "3.29100911471548643542566484557342614975886952410844652587974656e+63"
end

@testset "Zero" begin
    @test Ryu.writeexp(0.0, 4) == "0.0000e+00"
    @test Ryu.writeexp(0.0, 3) == "0.000e+00"
    @test Ryu.writeexp(0.0, 2) == "0.00e+00"
    @test Ryu.writeexp(0.0, 1) == "0.0e+00"
    @test Ryu.writeexp(0.0, 0) == "0e+00"
end

@testset "MinMax" begin
    @test Ryu.writeexp(todouble(false, 0, 1), 750) ==
    "4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983" *
    "636163599237979656469544571773092665671035593979639877479601078187812630071319031140452784" *
    "581716784898210368871863605699873072305000638740915356498438731247339727316961514003171538" *
    "539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748" *
    "012970999954193198940908041656332452475714786901472678015935523861155013480352649347201937" *
    "902681071074917033322268447533357208324319360923828934583680601060115061698097530783422773" *
    "183292479049825247307763759272478746560847782037344696995336470179726777175851256605511991" *
    "315048911014510378627381672509558373897335989936648099411642057026370902792427675445652290" *
    "87538682506419718265533447265625e-324"

    @test Ryu.writeexp(todouble(false, 2046, 0xFFFFFFFFFFFFF), 308) ==
    "1.7976931348623157081452742373170435679807056752584499659891747680315726078002853876058955" *
    "863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624" *
    "549009038932894407586850845513394230458323690322294816580855933212334827479782620414472316" *
    "8738177180919299881250404026184124858368e+308"
end

@testset "RoundToEven" begin
    @test Ryu.writeexp(0.125, 2) == "1.25e-01"
    @test Ryu.writeexp(0.125, 1) == "1.2e-01"
    @test Ryu.writeexp(0.375, 2) == "3.75e-01"
    @test Ryu.writeexp(0.375, 1) == "3.8e-01"
end

@testset "RoundToEvenInteger" begin
    @test Ryu.writeexp(2.5, 1) == "2.5e+00"
    @test Ryu.writeexp(2.5, 0) == "2e+00"
    @test Ryu.writeexp(3.5, 1) == "3.5e+00"
    @test Ryu.writeexp(3.5, 0) == "4e+00"
end

@testset "NonRoundToEvenScenarios" begin
    @test Ryu.writeexp(0.748046875, 2) == "7.48e-01"
    @test Ryu.writeexp(0.748046875, 1) == "7.5e-01"
    @test Ryu.writeexp(0.748046875, 0) == "7e-01"    # 0.75 would round to "8e-01", but this is smaller

    @test Ryu.writeexp(0.2509765625, 2) == "2.51e-01"
    @test Ryu.writeexp(0.2509765625, 1) == "2.5e-01"
    @test Ryu.writeexp(0.2509765625, 0) == "3e-01"    # 0.25 would round to "2e-01", but this is larger

    @test Ryu.writeexp(todouble(false, 1021, 1), 53) ==
    "2.50000000000000055511151231257827021181583404541015625e-01"
    @test Ryu.writeexp(todouble(false, 1021, 1),  2) ==
    "2.50e-01"
    @test Ryu.writeexp(todouble(false, 1021, 1),  1) ==
    "2.5e-01"
    @test Ryu.writeexp(todouble(false, 1021, 1),  0) ==
    "3e-01"    # 0.25 would round to "2e-01", but this is larger (again)
end

@testset "VaryingPrecision" begin
    @test Ryu.writeexp(1729.142857142857, 50) == "1.72914285714285711037518922239542007446289062500000e+03"
    @test Ryu.writeexp(1729.142857142857, 49) == "1.7291428571428571103751892223954200744628906250000e+03"
    @test Ryu.writeexp(1729.142857142857, 48) == "1.729142857142857110375189222395420074462890625000e+03"
    @test Ryu.writeexp(1729.142857142857, 47) == "1.72914285714285711037518922239542007446289062500e+03"
    @test Ryu.writeexp(1729.142857142857, 46) == "1.7291428571428571103751892223954200744628906250e+03"
    @test Ryu.writeexp(1729.142857142857, 45) == "1.729142857142857110375189222395420074462890625e+03"
    @test Ryu.writeexp(1729.142857142857, 44) == "1.72914285714285711037518922239542007446289062e+03"
    @test Ryu.writeexp(1729.142857142857, 43) == "1.7291428571428571103751892223954200744628906e+03"
    @test Ryu.writeexp(1729.142857142857, 42) == "1.729142857142857110375189222395420074462891e+03"
    @test Ryu.writeexp(1729.142857142857, 41) == "1.72914285714285711037518922239542007446289e+03"
    @test Ryu.writeexp(1729.142857142857, 40) == "1.7291428571428571103751892223954200744629e+03"
    @test Ryu.writeexp(1729.142857142857, 39) == "1.729142857142857110375189222395420074463e+03"
    @test Ryu.writeexp(1729.142857142857, 38) == "1.72914285714285711037518922239542007446e+03"
    @test Ryu.writeexp(1729.142857142857, 37) == "1.7291428571428571103751892223954200745e+03"
    @test Ryu.writeexp(1729.142857142857, 36) == "1.729142857142857110375189222395420074e+03"
    @test Ryu.writeexp(1729.142857142857, 35) == "1.72914285714285711037518922239542007e+03"
    @test Ryu.writeexp(1729.142857142857, 34) == "1.7291428571428571103751892223954201e+03"
    @test Ryu.writeexp(1729.142857142857, 33) == "1.729142857142857110375189222395420e+03"
    @test Ryu.writeexp(1729.142857142857, 32) == "1.72914285714285711037518922239542e+03"
    @test Ryu.writeexp(1729.142857142857, 31) == "1.7291428571428571103751892223954e+03"
    @test Ryu.writeexp(1729.142857142857, 30) == "1.729142857142857110375189222395e+03"
    @test Ryu.writeexp(1729.142857142857, 29) == "1.72914285714285711037518922240e+03"
    @test Ryu.writeexp(1729.142857142857, 28) == "1.7291428571428571103751892224e+03"
    @test Ryu.writeexp(1729.142857142857, 27) == "1.729142857142857110375189222e+03"
    @test Ryu.writeexp(1729.142857142857, 26) == "1.72914285714285711037518922e+03"
    @test Ryu.writeexp(1729.142857142857, 25) == "1.7291428571428571103751892e+03"
    @test Ryu.writeexp(1729.142857142857, 24) == "1.729142857142857110375189e+03"
    @test Ryu.writeexp(1729.142857142857, 23) == "1.72914285714285711037519e+03"
    @test Ryu.writeexp(1729.142857142857, 22) == "1.7291428571428571103752e+03"
    @test Ryu.writeexp(1729.142857142857, 21) == "1.729142857142857110375e+03"
    @test Ryu.writeexp(1729.142857142857, 20) == "1.72914285714285711038e+03"
    @test Ryu.writeexp(1729.142857142857, 19) == "1.7291428571428571104e+03"
    @test Ryu.writeexp(1729.142857142857, 18) == "1.729142857142857110e+03"
    @test Ryu.writeexp(1729.142857142857, 17) == "1.72914285714285711e+03"
    @test Ryu.writeexp(1729.142857142857, 16) == "1.7291428571428571e+03"
    @test Ryu.writeexp(1729.142857142857, 15) == "1.729142857142857e+03"
    @test Ryu.writeexp(1729.142857142857, 14) == "1.72914285714286e+03"
    @test Ryu.writeexp(1729.142857142857, 13) == "1.7291428571429e+03"
    @test Ryu.writeexp(1729.142857142857, 12) == "1.729142857143e+03"
    @test Ryu.writeexp(1729.142857142857, 11) == "1.72914285714e+03"
    @test Ryu.writeexp(1729.142857142857, 10) == "1.7291428571e+03"
    @test Ryu.writeexp(1729.142857142857,  9) == "1.729142857e+03"
    @test Ryu.writeexp(1729.142857142857,  8) == "1.72914286e+03"
    @test Ryu.writeexp(1729.142857142857,  7) == "1.7291429e+03"
    @test Ryu.writeexp(1729.142857142857,  6) == "1.729143e+03"
    @test Ryu.writeexp(1729.142857142857,  5) == "1.72914e+03"
    @test Ryu.writeexp(1729.142857142857,  4) == "1.7291e+03"
    @test Ryu.writeexp(1729.142857142857,  3) == "1.729e+03"
    @test Ryu.writeexp(1729.142857142857,  2) == "1.73e+03"
    @test Ryu.writeexp(1729.142857142857,  1) == "1.7e+03"
    @test Ryu.writeexp(1729.142857142857,  0) == "2e+03"
end

@testset "Carrying" begin
    @test Ryu.writeexp(2.0009, 4) == "2.0009e+00"
    @test Ryu.writeexp(2.0009, 3) == "2.001e+00"
    @test Ryu.writeexp(2.0029, 4) == "2.0029e+00"
    @test Ryu.writeexp(2.0029, 3) == "2.003e+00"
    @test Ryu.writeexp(2.0099, 4) == "2.0099e+00"
    @test Ryu.writeexp(2.0099, 3) == "2.010e+00"
    @test Ryu.writeexp(2.0299, 4) == "2.0299e+00"
    @test Ryu.writeexp(2.0299, 3) == "2.030e+00"
    @test Ryu.writeexp(2.0999, 4) == "2.0999e+00"
    @test Ryu.writeexp(2.0999, 3) == "2.100e+00"
    @test Ryu.writeexp(2.2999, 4) == "2.2999e+00"
    @test Ryu.writeexp(2.2999, 3) == "2.300e+00"
    @test Ryu.writeexp(2.9999, 4) == "2.9999e+00"
    @test Ryu.writeexp(2.9999, 3) == "3.000e+00"
    @test Ryu.writeexp(9.9999, 4) == "9.9999e+00"
    @test Ryu.writeexp(9.9999, 3) == "1.000e+01"

    @test Ryu.writeexp(2.09, 2) == "2.09e+00"
    @test Ryu.writeexp(2.09, 1) == "2.1e+00"
    @test Ryu.writeexp(2.29, 2) == "2.29e+00"
    @test Ryu.writeexp(2.29, 1) == "2.3e+00"
    @test Ryu.writeexp(2.99, 2) == "2.99e+00"
    @test Ryu.writeexp(2.99, 1) == "3.0e+00"
    @test Ryu.writeexp(9.99, 2) == "9.99e+00"
    @test Ryu.writeexp(9.99, 1) == "1.0e+01"

    @test Ryu.writeexp(2.9, 1) == "2.9e+00"
    @test Ryu.writeexp(2.9, 0) == "3e+00"
    @test Ryu.writeexp(9.9, 1) == "9.9e+00"
    @test Ryu.writeexp(9.9, 0) == "1e+01"
end

@testset "Exponents" begin
    @test Ryu.writeexp(9.99e-100, 2) == "9.99e-100"
    @test Ryu.writeexp(9.99e-99 , 2) == "9.99e-99"
    @test Ryu.writeexp(9.99e-10 , 2) == "9.99e-10"
    @test Ryu.writeexp(9.99e-09 , 2) == "9.99e-09"
    @test Ryu.writeexp(9.99e-01 , 2) == "9.99e-01"
    @test Ryu.writeexp(9.99e+00 , 2) == "9.99e+00"
    @test Ryu.writeexp(9.99e+01 , 2) == "9.99e+01"
    @test Ryu.writeexp(9.99e+09 , 2) == "9.99e+09"
    @test Ryu.writeexp(9.99e+10 , 2) == "9.99e+10"
    @test Ryu.writeexp(9.99e+99 , 2) == "9.99e+99"
    @test Ryu.writeexp(9.99e+100, 2) == "9.99e+100"

    @test Ryu.writeexp(9.99e-100, 1) == "1.0e-99"
    @test Ryu.writeexp(9.99e-99 , 1) == "1.0e-98"
    @test Ryu.writeexp(9.99e-10 , 1) == "1.0e-09"
    @test Ryu.writeexp(9.99e-09 , 1) == "1.0e-08"
    @test Ryu.writeexp(9.99e-01 , 1) == "1.0e+00"
    @test Ryu.writeexp(9.99e+00 , 1) == "1.0e+01"
    @test Ryu.writeexp(9.99e+01 , 1) == "1.0e+02"
    @test Ryu.writeexp(9.99e+09 , 1) == "1.0e+10"
    @test Ryu.writeexp(9.99e+10 , 1) == "1.0e+11"
    @test Ryu.writeexp(9.99e+99 , 1) == "1.0e+100"
    @test Ryu.writeexp(9.99e+100, 1) == "1.0e+101"
end

@testset "PrintDecimalPoint" begin
  # These values exercise each codepath.
    @test Ryu.writeexp(1e+54, 0) == "1e+54"
    @test Ryu.writeexp(1e+54, 1) == "1.0e+54"
    @test Ryu.writeexp(1e-63, 0) == "1e-63"
    @test Ryu.writeexp(1e-63, 1) == "1.0e-63"
    @test Ryu.writeexp(1e+83, 0) == "1e+83"
    @test Ryu.writeexp(1e+83, 1) == "1.0e+83"
end

@testset "Consistency of trimtrailingzeros" begin
    @test Ryu.writeexp(0.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "0e+00"
    @test Ryu.writeexp(1.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "1e+00"
    @test Ryu.writeexp(2.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "2e+00"
end

end # exp

@testset "compact" begin

    stringcompact(x) = sprint(show, x; context=:compact => true)

    @test stringcompact(0.49999999) == "0.5"
    @test stringcompact(0.459999999) == "0.46"
    @test stringcompact(0.20058603493384108) == "0.200586"
    @test stringcompact(0.9999999) == "1.0"
    @test stringcompact(0.1999999) == "0.2"
    @test stringcompact(123.4567) == "123.457"
    @test stringcompact(0.001234567) == "0.00123457"
    @test stringcompact(0.1234567) == "0.123457"
    @test stringcompact(1234567.0) == "1.23457e6"
    @test stringcompact(12345678910.0) == "1.23457e10"
    @test stringcompact(12345678.0) == "1.23457e7"
    @test stringcompact(0.10000049) == "0.1"
    @test stringcompact(22.89825) == "22.8983"
    @test stringcompact(0.646690981531646) == "0.646691"
    @test stringcompact(6.938893903907228e-17) == "6.93889e-17"
    @test stringcompact(1.015625) == "1.01562"
    @test stringcompact(1.046875) == "1.04688"
    @test stringcompact(0.025621074) == "0.0256211"

    # subnormals
    @test stringcompact(eps(0.0)) == "5.0e-324"
    @test stringcompact(eps(0f0)) == "1.0f-45"
    @test stringcompact(eps(Float16(0.0))) == "6.0e-8"
end

end # Ryu
back to top