What Numeric Formatting Algorithms Does {fmt} Use?
The {fmt} library uses the Dragonbox algorithm (also known as Schubfach) for all floating-point formatting and a custom high-speed integer-to-string conversion for integral types, having fully removed the experimental Grisu3 implementation in favor of Dragonbox’s superior performance and round-trip correctness.
The {fmt} library (fmtlib/fmt) is a widely adopted open-source C++ formatting library that serves as the foundation for Rust’s format! macro and Python’s f-strings. Understanding the numeric formatting algorithms embedded in its source code explains how it achieves faster performance than standard library alternatives while guaranteeing correctly rounded decimal output for every input.
Dragonbox: The Primary Floating-Point Algorithm
{fmt} implements the Dragonbox algorithm (also referred to as the Schubfach algorithm) to convert binary IEEE-754 floating-point values into decimal strings. This algorithm guarantees the shortest correctly rounded decimal representation that round-trips back to the original binary value, ensuring deterministic output across platforms.
In include/fmt/format-inl.h, the core implementation resides within the dragonbox namespace. The entry point function dragonbox::to_decimal transforms a binary floating-point number into a decimal representation using pre-computed power-of-10 tables. This table-driven approach avoids high-precision integer arithmetic during the hot path, significantly reducing CPU cycles compared to traditional printf implementations or digit-by-digit conversion.
Source Location and Implementation Details
The Dragonbox implementation is contained entirely within the internal header file:
- File:
include/fmt/format-inl.h(references around lines 207-208 document the Dragonbox adoption) - Namespace:
dragonbox - Key Function:
dragonbox::to_decimal
This implementation handles both float and double types uniformly, ensuring that scientific, fixed, and general formatting modes all leverage the same core conversion logic without falling back to system libraries.
Custom Integer Conversion Routine
For all integral types (int, long, long long, etc.), {fmt} does not use Dragonbox or standard library conversion functions. Instead, it employs a custom integer-to-string conversion optimized for throughput and minimal memory overhead defined in src/format.cc.
The algorithm is explicitly instantiated for both char and wchar_t character types. It bypasses locale-dependent processing entirely, using arithmetic decomposition and lookup tables to convert integers to character sequences without dynamic allocation or global locale locks. This design choice ensures consistent high performance when formatting millions of integers per second.
Historical Context: The Removal of Grisu3
Prior to standardizing on Dragonbox, {fmt} experimented with the Grisu3 algorithm for floating-point formatting. According to doc/ChangeLog-old.md (lines 1158-1169), Grisu3 was available as an experimental feature but could not guarantee the shortest representation for all inputs and occasionally failed round-trip correctness tests.
The transition to Dragonbox is documented in doc/ChangeLog.md (lines 1711-1791), which notes the complete removal of Grisu remnants. The changelog cites Dragonbox’s superior performance characteristics and its mathematical guarantee of optimal, correctly rounded output as the primary reasons for eliminating Grisu3 from the codebase.
Practical Code Examples
The following program demonstrates both numeric formatting algorithms in action:
#include <fmt/core.h>
int main() {
// Integer formatting uses the custom conversion routine in src/format.cc
int count = 123456;
fmt::print("Iterations: {}\n", count);
// Floating-point formatting uses Dragonbox via format-inl.h
double pi = 3.141592653589793238;
fmt::print("Pi (shortest): {}\n", pi); // Dragonbox shortest representation
fmt::print("Pi (fixed): {:.10f}\n", pi); // Dragonbox with fixed precision
// Scientific notation also invokes Dragonbox::to_decimal
float avogadro = 6.02214076e23f;
fmt::print("Avogadro: {:e}\n", avogadro);
}
When compiled, this code invokes the dragonbox::to_decimal function for the double and float arguments, while the integer argument triggers the custom itoa-style routine defined in src/format.cc.
Summary
- Floating-point numbers are formatted using the Dragonbox algorithm (Schubfach) via
dragonbox::to_decimalininclude/fmt/format-inl.h, ensuring correct rounding and optimal performance through pre-computed power-of-10 tables. - Integers are processed by a custom conversion routine in
src/format.ccthat avoids locale overhead and standard library dependencies. - Grisu3 was previously implemented as an experimental alternative but has been completely removed from the library, as documented in
doc/ChangeLog.md, leaving Dragonbox as the sole algorithm for floating-point output. - The library achieves its speed by eliminating high-precision arithmetic from the formatting hot path and instantiating templates for both narrow and wide character types.
Frequently Asked Questions
Does fmt use Dragonbox or Grisu for floating-point formatting?
{fmt} uses the Dragonbox algorithm exclusively for floating-point formatting. The Grisu3 implementation was experimental and has been fully removed from the codebase because Dragonbox offers better performance and guarantees the shortest correctly rounded decimal representation for every binary floating-point input.
Where is the Dragonbox implementation located in the fmt source code?
The Dragonbox implementation resides in include/fmt/format-inl.h within the dragonbox namespace. The critical dragonbox::to_decimal function and its supporting power-of-10 lookup tables are defined in this internal header, which is included by the main format.h header during compilation.
How does fmt handle integer formatting differently than floating-point formatting?
While floating-point values use the Dragonbox algorithm, integers use a custom integer-to-string conversion defined in src/format.cc. This routine performs direct arithmetic decomposition into decimal digits without using locales or the C standard library’s printf family, resulting in faster conversion speeds for int, long, and other integral types.
Why was Grisu removed from the fmt library?
Grisu was removed because the Dragonbox algorithm provides strictly superior characteristics: it guarantees both the shortest and correctly rounded decimal representation that round-trips back to the original binary value, whereas Grisu occasionally produced longer strings or failed edge-case rounding tests. The removal is documented in doc/ChangeLog.md around lines 1711-1791.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →