Skip to content

Instantly share code, notes, and snippets.

@inkydragon
Last active March 30, 2025 18:11
Show Gist options
  • Save inkydragon/a110083883bec45cc3ea902c3e429b35 to your computer and use it in GitHub Desktop.
Save inkydragon/a110083883bec45cc3ea902c3e429b35 to your computer and use it in GitHub Desktop.
IEEE 754 floating-point formatter using the Dragonbox algorithm
f32(%a) uint32 int64 str(f32)
0x1p+25 0x2000000 33554432 33554432.000000
0x1.000008p+25 0x2000010 33554448 33554448.000000
0x1.00008p+25 0x2000100 33554688 33554688.000000
0x1p+26 0x4000000 67108864 67108864.000000
0x1.000008p+26 0x4000020 67108896 67108896.000000
0x1.00000cp+26 0x4000030 67108912 67108912.000000
0x1.00001p+26 0x4000040 67108928 67108928.000000
0x1.000014p+26 0x4000050 67108944 67108944.000000
0x1p+27 0x8000000 134217728 134217728.000000
0x1.000006p+27 0x8000030 134217776 134217776.000000
0x1.000008p+27 0x8000040 134217792 134217792.000000
0x1.00000ap+27 0x8000050 134217808 134217808.000000
0x1.00000cp+27 0x8000060 134217824 134217824.000000
0x1p+28 0x10000000 268435456 268435456.000000
0x1.00001p+28 0x10000100 268435712 268435712.000000
0x1.00002p+28 0x10000200 268435968 268435968.000000
0x1.00003p+28 0x10000300 268436224 268436224.000000
0x1p+29 0x20000000 536870912 536870912.000000
0x1.000008p+29 0x20000100 536871168 536871168.000000
0x1.00001p+29 0x20000200 536871424 536871424.000000
0x1.000018p+29 0x20000300 536871680 536871680.000000
0x1p+30 0x40000000 1073741824 1073741824.000000
0x1.000004p+30 0x40000100 1073742080 1073742080.000000
0x1.000008p+30 0x40000200 1073742336 1073742336.000000
0x1.00000cp+30 0x40000300 1073742592 1073742592.000000
0x1p+31 0x80000000 2147483648 2147483648.000000
0x1.000002p+31 0x80000100 2147483904 2147483904.000000
// Online https://godbolt.org/z/6vqn74jMY
/* https://github.com/ulfjack/ryu/issues/235 */
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <fmt/core.h>
int main() {
std::vector<std::tuple<std::string, float>> items = {
// 0 ~ 2^23: eps=1, good
// 2^24 ~ 2^25-1: eps=2, good
// 2^25 ~ 2^26-1: eps=4, error_count = 1677721
{"0x1p+25", 0x1p+25}, // good
{"0x1.000008p+25", 0x1.000008p+25},
{"0x1.00008p+25", 0x1.00008p+25},
// 2^26 ~ 2^27-1: eps=8, error_count = 5033164
{"0x1p+26", 0x1p+26}, // good
{"0x1.000008p+26", 0x1.000008p+26},
{"0x1.00000cp+26", 0x1.00000cp+26},
{"0x1.00001p+26", 0x1.00001p+26},
{"0x1.000014p+26", 0x1.000014p+26},
// 2^27 ~ 2^28-1: eps=16, error_count = 6710886
{"0x1p+27", 0x1p+27},
{"0x1.000006p+27", 0x1.000006p+27},
{"0x1.000008p+27", 0x1.000008p+27},
{"0x1.00000ap+27", 0x1.00000ap+27},
{"0x1.00000cp+27", 0x1.00000cp+27},
// 2^28 ~ 2^29-1: eps=32, error_count = 6710886
{"0x1p+28", 0x1p+28},
{"0x1.00001p+28", 0x1.00001p+28},
{"0x1.00002p+28", 0x1.00002p+28},
{"0x1.00003p+28", 0x1.00003p+28},
// 2^29 ~ 2^30-1: eps=64, error_count = 7381974
{"0x1p+29", 0x1p+29},
{"0x1.000008p+29", 0x1.000008p+29},
{"0x1.00001p+29", 0x1.00001p+29},
{"0x1.000018p+29", 0x1.000018p+29},
// 2^30 ~ 2^31-1: eps=128, error_count = 8053064
{"0x1p+30", 0x1p+30},
{"0x1.000004p+30", 0x1.000004p+30},
{"0x1.000008p+30", 0x1.000008p+30},
{"0x1.00000cp+30", 0x1.00000cp+30},
// 2^31+: eps=256,
{"0x1p+31", 0x1p+31},
{"0x1.000002p+31", 2147483904.0}
};
fmt::print("IEEE 754 floating-point formatter using the Dragonbox algorithm\n");
fmt::print("{:>15s} {:>10s} {:>12s} {:>20s}\n", "f32(%a)", "uint32", "int64", "str(f32)");
for (const auto& item : items) {
const auto& [text, f32] = item;
fmt::print(
"{:>15s} {:#10x} {:>12d} {:>20f}\n",
text, (uint32_t)f32, (int64_t)f32, f32);
}
return 0;
}
#= Find Ryu(f32) Errors
https://github.com/ulfjack/ryu/issues/235
=#
function gen_test_ranges()
"""
<2^24, eps<=1
2^24+, eps=2
2^25+, eps=4
2^26+, eps=8
2^27+, eps=16
2^28+, eps=32
2^29+, eps=64
2^30+, eps=128
2^31+, eps=256
"""
acc_int_range = StepRange{Int,Int}[
# eps(f32) = 1.0
0:(2^24-1),
]
for i in 24:(31-1)
# NOTE: eps *= 2
step = Int(eps(Float32(2^i)))
start = 2^i
stop = 2^(i+1) - 1
int_range = start:step:stop
push!(acc_int_range, int_range)
end
return acc_int_range
end
function main()
acc_int_range = gen_test_ranges()
test_case_count = 0
all_error_count = 0
for int_range in acc_int_range
test_case_count += length(int_range)
@info (; int_range=int_range)
error_count = 0
# Only print N error msg
PrintLimit = 20
@time for i in int_range
# f32 =Ryu=> str => f64 => int32
u32 = UInt32(i)
f32 = Float32(i)
s32 = string(f32) # <-- Ryu here
f64Out = parse(Float64, s32)
i32Out = Int32(f64Out)
if i != i32Out
error_count += 1
if error_count <= PrintLimit
@info (; u32=u32, i32=i, s32=s32, i32Out=i32Out)
end
end
end
all_error_count += error_count
@info (; error_count=error_count)
println()
end
@info (; all_error_count=all_error_count,
test_case_count=test_case_count,
error_ratio=all_error_count/test_case_count)
end
@time main()
@info VERSION
[ Info: (int_range = 0:1:16777215,)
0.907700 seconds (33.55 M allocations: 2.125 GiB, 1.93% gc time)
[ Info: (error_count = 0,)
[ Info: (int_range = 16777216:2:33554430,)
0.547936 seconds (16.78 M allocations: 1.062 GiB, 1.75% gc time)
[ Info: (error_count = 0,)
[ Info: (int_range = 33554432:4:67108860,)
[ Info: (u32 = 0x02000010, i64 = 33554448, s32 = "3.355445e7", i64Out = 33554450)
[ Info: (u32 = 0x02000028, i64 = 33554472, s32 = "3.355447e7", i64Out = 33554470)
[ Info: (u32 = 0x02000038, i64 = 33554488, s32 = "3.355449e7", i64Out = 33554490)
[ Info: (u32 = 0x02000050, i64 = 33554512, s32 = "3.355451e7", i64Out = 33554510)
[ Info: (u32 = 0x02000060, i64 = 33554528, s32 = "3.355453e7", i64Out = 33554530)
[ Info: (u32 = 0x02000078, i64 = 33554552, s32 = "3.355455e7", i64Out = 33554550)
[ Info: (u32 = 0x02000088, i64 = 33554568, s32 = "3.355457e7", i64Out = 33554570)
[ Info: (u32 = 0x020000a0, i64 = 33554592, s32 = "3.355459e7", i64Out = 33554590)
[ Info: (u32 = 0x020000b0, i64 = 33554608, s32 = "3.355461e7", i64Out = 33554610)
[ Info: (u32 = 0x020000c8, i64 = 33554632, s32 = "3.355463e7", i64Out = 33554630)
[ Info: (u32 = 0x020000d8, i64 = 33554648, s32 = "3.355465e7", i64Out = 33554650)
[ Info: (u32 = 0x020000f0, i64 = 33554672, s32 = "3.355467e7", i64Out = 33554670)
[ Info: (u32 = 0x02000100, i64 = 33554688, s32 = "3.355469e7", i64Out = 33554690)
[ Info: (u32 = 0x02000118, i64 = 33554712, s32 = "3.355471e7", i64Out = 33554710)
[ Info: (u32 = 0x02000128, i64 = 33554728, s32 = "3.355473e7", i64Out = 33554730)
[ Info: (u32 = 0x02000140, i64 = 33554752, s32 = "3.355475e7", i64Out = 33554750)
[ Info: (u32 = 0x02000150, i64 = 33554768, s32 = "3.355477e7", i64Out = 33554770)
[ Info: (u32 = 0x02000168, i64 = 33554792, s32 = "3.355479e7", i64Out = 33554790)
[ Info: (u32 = 0x02000178, i64 = 33554808, s32 = "3.355481e7", i64Out = 33554810)
[ Info: (u32 = 0x02000190, i64 = 33554832, s32 = "3.355483e7", i64Out = 33554830)
0.616850 seconds (16.86 M allocations: 1.068 GiB, 1.48% gc time, 8.06% compilation time)
[ Info: (error_count = 1677721,)
[ Info: (int_range = 67108864:8:134217720,)
[ Info: (u32 = 0x04000008, i64 = 67108872, s32 = "6.710887e7", i64Out = 67108870)
[ Info: (u32 = 0x04000018, i64 = 67108888, s32 = "6.710889e7", i64Out = 67108890)
[ Info: (u32 = 0x04000020, i64 = 67108896, s32 = "6.71089e7", i64Out = 67108900)
[ Info: (u32 = 0x04000030, i64 = 67108912, s32 = "6.710891e7", i64Out = 67108910)
[ Info: (u32 = 0x04000040, i64 = 67108928, s32 = "6.710893e7", i64Out = 67108930)
[ Info: (u32 = 0x04000050, i64 = 67108944, s32 = "6.710894e7", i64Out = 67108940)
[ Info: (u32 = 0x04000058, i64 = 67108952, s32 = "6.710895e7", i64Out = 67108950)
[ Info: (u32 = 0x04000068, i64 = 67108968, s32 = "6.710897e7", i64Out = 67108970)
[ Info: (u32 = 0x04000070, i64 = 67108976, s32 = "6.710898e7", i64Out = 67108980)
[ Info: (u32 = 0x04000080, i64 = 67108992, s32 = "6.710899e7", i64Out = 67108990)
[ Info: (u32 = 0x04000090, i64 = 67109008, s32 = "6.710901e7", i64Out = 67109010)
[ Info: (u32 = 0x040000a0, i64 = 67109024, s32 = "6.710902e7", i64Out = 67109020)
[ Info: (u32 = 0x040000a8, i64 = 67109032, s32 = "6.710903e7", i64Out = 67109030)
[ Info: (u32 = 0x040000b8, i64 = 67109048, s32 = "6.710905e7", i64Out = 67109050)
[ Info: (u32 = 0x040000c0, i64 = 67109056, s32 = "6.710906e7", i64Out = 67109060)
[ Info: (u32 = 0x040000d0, i64 = 67109072, s32 = "6.710907e7", i64Out = 67109070)
[ Info: (u32 = 0x040000e0, i64 = 67109088, s32 = "6.710909e7", i64Out = 67109090)
[ Info: (u32 = 0x040000f0, i64 = 67109104, s32 = "6.71091e7", i64Out = 67109100)
[ Info: (u32 = 0x040000f8, i64 = 67109112, s32 = "6.710911e7", i64Out = 67109110)
[ Info: (u32 = 0x04000108, i64 = 67109128, s32 = "6.710913e7", i64Out = 67109130)
0.548580 seconds (16.78 M allocations: 1.063 GiB, 1.11% gc time)
[ Info: (error_count = 5033164,)
[ Info: (int_range = 134217728:16:268435440,)
[ Info: (u32 = 0x08000000, i64 = 134217728, s32 = "1.3421773e8", i64Out = 134217730)
[ Info: (u32 = 0x08000010, i64 = 134217744, s32 = "1.3421774e8", i64Out = 134217740)
[ Info: (u32 = 0x08000030, i64 = 134217776, s32 = "1.3421778e8", i64Out = 134217780)
[ Info: (u32 = 0x08000040, i64 = 134217792, s32 = "1.342178e8", i64Out = 134217800)
[ Info: (u32 = 0x08000050, i64 = 134217808, s32 = "1.3421781e8", i64Out = 134217810)
[ Info: (u32 = 0x08000060, i64 = 134217824, s32 = "1.3421782e8", i64Out = 134217820)
[ Info: (u32 = 0x08000080, i64 = 134217856, s32 = "1.3421786e8", i64Out = 134217860)
[ Info: (u32 = 0x08000090, i64 = 134217872, s32 = "1.3421787e8", i64Out = 134217870)
[ Info: (u32 = 0x080000a0, i64 = 134217888, s32 = "1.3421789e8", i64Out = 134217890)
[ Info: (u32 = 0x080000b0, i64 = 134217904, s32 = "1.342179e8", i64Out = 134217900)
[ Info: (u32 = 0x080000d0, i64 = 134217936, s32 = "1.3421794e8", i64Out = 134217940)
[ Info: (u32 = 0x080000e0, i64 = 134217952, s32 = "1.3421795e8", i64Out = 134217950)
[ Info: (u32 = 0x080000f0, i64 = 134217968, s32 = "1.3421797e8", i64Out = 134217970)
[ Info: (u32 = 0x08000100, i64 = 134217984, s32 = "1.3421798e8", i64Out = 134217980)
[ Info: (u32 = 0x08000120, i64 = 134218016, s32 = "1.3421802e8", i64Out = 134218020)
[ Info: (u32 = 0x08000130, i64 = 134218032, s32 = "1.3421803e8", i64Out = 134218030)
[ Info: (u32 = 0x08000140, i64 = 134218048, s32 = "1.3421805e8", i64Out = 134218050)
[ Info: (u32 = 0x08000150, i64 = 134218064, s32 = "1.3421806e8", i64Out = 134218060)
[ Info: (u32 = 0x08000170, i64 = 134218096, s32 = "1.342181e8", i64Out = 134218100)
[ Info: (u32 = 0x08000180, i64 = 134218112, s32 = "1.3421811e8", i64Out = 134218110)
0.572096 seconds (16.78 M allocations: 1.063 GiB, 1.19% gc time)
[ Info: (error_count = 6710886,)
[ Info: (int_range = 268435456:32:536870880,)
[ Info: (u32 = 0x10000000, i64 = 268435456, s32 = "2.6843546e8", i64Out = 268435460)
[ Info: (u32 = 0x10000020, i64 = 268435488, s32 = "2.684355e8", i64Out = 268435500)
[ Info: (u32 = 0x10000060, i64 = 268435552, s32 = "2.6843555e8", i64Out = 268435550)
[ Info: (u32 = 0x10000080, i64 = 268435584, s32 = "2.684356e8", i64Out = 268435600)
[ Info: (u32 = 0x100000a0, i64 = 268435616, s32 = "2.6843562e8", i64Out = 268435620)
[ Info: (u32 = 0x100000c0, i64 = 268435648, s32 = "2.6843565e8", i64Out = 268435650)
[ Info: (u32 = 0x10000100, i64 = 268435712, s32 = "2.684357e8", i64Out = 268435700)
[ Info: (u32 = 0x10000120, i64 = 268435744, s32 = "2.6843574e8", i64Out = 268435740)
[ Info: (u32 = 0x10000140, i64 = 268435776, s32 = "2.6843578e8", i64Out = 268435780)
[ Info: (u32 = 0x10000160, i64 = 268435808, s32 = "2.684358e8", i64Out = 268435800)
[ Info: (u32 = 0x100001a0, i64 = 268435872, s32 = "2.6843587e8", i64Out = 268435870)
[ Info: (u32 = 0x100001c0, i64 = 268435904, s32 = "2.684359e8", i64Out = 268435900)
[ Info: (u32 = 0x100001e0, i64 = 268435936, s32 = "2.6843594e8", i64Out = 268435940)
[ Info: (u32 = 0x10000200, i64 = 268435968, s32 = "2.6843597e8", i64Out = 268435970)
[ Info: (u32 = 0x10000240, i64 = 268436032, s32 = "2.6843603e8", i64Out = 268436030)
[ Info: (u32 = 0x10000260, i64 = 268436064, s32 = "2.6843606e8", i64Out = 268436060)
[ Info: (u32 = 0x10000280, i64 = 268436096, s32 = "2.684361e8", i64Out = 268436100)
[ Info: (u32 = 0x100002a0, i64 = 268436128, s32 = "2.6843613e8", i64Out = 268436130)
[ Info: (u32 = 0x100002e0, i64 = 268436192, s32 = "2.684362e8", i64Out = 268436200)
[ Info: (u32 = 0x10000300, i64 = 268436224, s32 = "2.6843622e8", i64Out = 268436220)
0.596139 seconds (16.78 M allocations: 1.063 GiB, 1.13% gc time)
[ Info: (error_count = 6710886,)
[ Info: (int_range = 536870912:64:1073741760,)
[ Info: (u32 = 0x20000000, i64 = 536870912, s32 = "5.368709e8", i64Out = 536870900)
[ Info: (u32 = 0x20000040, i64 = 536870976, s32 = "5.36871e8", i64Out = 536871000)
[ Info: (u32 = 0x200000c0, i64 = 536871104, s32 = "5.368711e8", i64Out = 536871100)
[ Info: (u32 = 0x20000100, i64 = 536871168, s32 = "5.368712e8", i64Out = 536871200)
[ Info: (u32 = 0x20000140, i64 = 536871232, s32 = "5.3687123e8", i64Out = 536871230)
[ Info: (u32 = 0x20000180, i64 = 536871296, s32 = "5.368713e8", i64Out = 536871300)
[ Info: (u32 = 0x20000200, i64 = 536871424, s32 = "5.368714e8", i64Out = 536871400)
[ Info: (u32 = 0x20000240, i64 = 536871488, s32 = "5.368715e8", i64Out = 536871500)
[ Info: (u32 = 0x20000280, i64 = 536871552, s32 = "5.3687155e8", i64Out = 536871550)
[ Info: (u32 = 0x200002c0, i64 = 536871616, s32 = "5.368716e8", i64Out = 536871600)
[ Info: (u32 = 0x20000300, i64 = 536871680, s32 = "5.368717e8", i64Out = 536871700)
[ Info: (u32 = 0x20000340, i64 = 536871744, s32 = "5.3687174e8", i64Out = 536871740)
[ Info: (u32 = 0x20000380, i64 = 536871808, s32 = "5.368718e8", i64Out = 536871800)
[ Info: (u32 = 0x200003c0, i64 = 536871872, s32 = "5.368719e8", i64Out = 536871900)
[ Info: (u32 = 0x20000400, i64 = 536871936, s32 = "5.3687194e8", i64Out = 536871940)
[ Info: (u32 = 0x20000480, i64 = 536872064, s32 = "5.3687206e8", i64Out = 536872060)
[ Info: (u32 = 0x200004c0, i64 = 536872128, s32 = "5.368721e8", i64Out = 536872100)
[ Info: (u32 = 0x20000500, i64 = 536872192, s32 = "5.368722e8", i64Out = 536872200)
[ Info: (u32 = 0x20000540, i64 = 536872256, s32 = "5.3687226e8", i64Out = 536872260)
[ Info: (u32 = 0x20000580, i64 = 536872320, s32 = "5.368723e8", i64Out = 536872300)
0.635360 seconds (16.78 M allocations: 1.063 GiB, 1.13% gc time)
[ Info: (error_count = 7381974,)
[ Info: (int_range = 1073741824:128:2147483520,)
[ Info: (u32 = 0x40000000, i64 = 1073741824, s32 = "1.0737418e9", i64Out = 1073741800)
[ Info: (u32 = 0x40000080, i64 = 1073741952, s32 = "1.073742e9", i64Out = 1073742000)
[ Info: (u32 = 0x40000100, i64 = 1073742080, s32 = "1.0737421e9", i64Out = 1073742100)
[ Info: (u32 = 0x40000180, i64 = 1073742208, s32 = "1.0737422e9", i64Out = 1073742200)
[ Info: (u32 = 0x40000200, i64 = 1073742336, s32 = "1.0737423e9", i64Out = 1073742300)
[ Info: (u32 = 0x40000280, i64 = 1073742464, s32 = "1.0737425e9", i64Out = 1073742500)
[ Info: (u32 = 0x40000300, i64 = 1073742592, s32 = "1.0737426e9", i64Out = 1073742600)
[ Info: (u32 = 0x40000380, i64 = 1073742720, s32 = "1.0737427e9", i64Out = 1073742700)
[ Info: (u32 = 0x40000400, i64 = 1073742848, s32 = "1.0737428e9", i64Out = 1073742800)
[ Info: (u32 = 0x40000480, i64 = 1073742976, s32 = "1.073743e9", i64Out = 1073743000)
[ Info: (u32 = 0x40000500, i64 = 1073743104, s32 = "1.0737431e9", i64Out = 1073743100)
[ Info: (u32 = 0x40000580, i64 = 1073743232, s32 = "1.0737432e9", i64Out = 1073743200)
[ Info: (u32 = 0x40000600, i64 = 1073743360, s32 = "1.0737434e9", i64Out = 1073743400)
[ Info: (u32 = 0x40000680, i64 = 1073743488, s32 = "1.0737435e9", i64Out = 1073743500)
[ Info: (u32 = 0x40000700, i64 = 1073743616, s32 = "1.0737436e9", i64Out = 1073743600)
[ Info: (u32 = 0x40000780, i64 = 1073743744, s32 = "1.0737437e9", i64Out = 1073743700)
[ Info: (u32 = 0x40000800, i64 = 1073743872, s32 = "1.0737439e9", i64Out = 1073743900)
[ Info: (u32 = 0x40000900, i64 = 1073744128, s32 = "1.0737441e9", i64Out = 1073744100)
[ Info: (u32 = 0x40000980, i64 = 1073744256, s32 = "1.0737443e9", i64Out = 1073744300)
[ Info: (u32 = 0x40000a00, i64 = 1073744384, s32 = "1.0737444e9", i64Out = 1073744400)
0.631840 seconds (16.78 M allocations: 1.063 GiB, 1.12% gc time)
[ Info: (error_count = 8053064,)
[ Info: (all_error_count = 35567695, test_case_count = 75497472, error_ratio = 0.4711110724343194)
5.364902 seconds (151.89 M allocations: 9.625 GiB, 1.95% gc time, 6.57% compilation time)
[ Info: 1.10.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment