Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Zig
Javascript
GIMPLE
Ygen
sway
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.88.0
rustc 1.89.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
x86-64 GCCRS 15.2 (GCC assertions)
x86-64 GCCRS 15.2 (GCC)
Options
Source code
#![feature(ascii_char)] #![feature(maybe_uninit_slice)] #![feature(numfmt)] use core::fmt; use core::str; use core::mem::MaybeUninit; use core::num::fmt as numfmt; pub fn main(x: u64, b: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt_fn::<b'E'>(x, b, f) } pub fn fmt_fn<const LETTER_E: u8>( n: u64, is_nonnegative: bool, f: &mut fmt::Formatter<'_> ) -> fmt::Result { assert!(LETTER_E.is_ascii(), "single-byte character"); // Print the integer as a coefficient in range (-10, 10). let mut exp = n.checked_ilog10().unwrap_or(0) as usize; debug_assert!(n / (10 as u64).pow(exp as u32) < 10); // Precisison is counted as the number of digits in the fraction. let mut coef_prec = exp; // Keep the digits as an integer (paired with its coef_prec count). let mut coef = n; // A Formatter may set the precision to a fixed number of decimals. let more_prec = match f.precision() { None => { // Omit any and all trailing zeroes. while coef_prec != 0 && coef % 10 == 0 { coef /= 10; coef_prec -= 1; } 0 }, Some(fmt_prec) if fmt_prec >= coef_prec => { // Count the number of additional zeroes needed. fmt_prec - coef_prec }, Some(fmt_prec) => { // Count the number of digits to drop. let less_prec = coef_prec - fmt_prec; assert!(less_prec > 0); // Scale down the coefficient/precision pair. let scale = match (10 as u64).checked_pow(less_prec as u32) { Some(pow_of_ten) => pow_of_ten, None => { // SAFETY: Any precision less than coef_prec will // cause a power of ten below the coef value. unsafe { core::hint::unreachable_unchecked() } }, }; let floor = coef / scale; // Round half to even conform documentation. let over = coef % scale; let half = scale / 2; let round_up = if over < half { 0 } else if over > half { 1 } else { floor & 1 // round odd up to even }; // Adding one to a scale down of at least 10 won't overflow. coef = floor + round_up; coef_prec = fmt_prec; // The round_up may have caused the coefficient to reach 10 // (which is not permitted). For example, anything in range // [9.95, 10) becomes 10.0 when adjusted to precision 1. if round_up != 0 && coef.checked_ilog10().unwrap_or(0) as usize > coef_prec { debug_assert_eq!(coef, (10 as u64).pow(coef_prec as u32 + 1)); coef /= 10; // drop one trailing zero exp += 1; // one power of ten higher } 0 }, }; // Allocate a text buffer with lazy initialization. const MAX_DEC_N: usize = u64::MAX.ilog10() as usize + 1; const MAX_COEF_LEN: usize = MAX_DEC_N + ".".len(); const MAX_TEXT_LEN: usize = MAX_COEF_LEN + "e99".len(); let mut buf = [MaybeUninit::<u8>::uninit(); MAX_TEXT_LEN]; // Encode the coefficient in buf[..coef_len]. let (lead_dec, coef_len) = if coef_prec == 0 && more_prec == 0 { (coef, 1_usize) // single digit; no fraction } else { buf[1].write(b'.'); let fraction_range = 2..2 + coef_prec; // Consume the least-significant decimals from a working copy. let mut remain = coef; #[cfg(feature = "optimize_for_size")] { for i in fraction_range.clone().rev() { let digit = (remain % 10) as usize; remain /= 10; buf[i].write(b'0' + digit as u8); } } #[cfg(not(feature = "optimize_for_size"))] { // Write digits per two at a time with a lookup table. for i in fraction_range.clone().skip(1).rev().step_by(2) { let pair = (remain % 100) as usize; remain /= 100; buf[i - 1].write(DECIMAL_PAIRS[pair * 2 + 0]); buf[i - 0].write(DECIMAL_PAIRS[pair * 2 + 1]); } // An odd number of digits leave one digit remaining. if coef_prec & 1 != 0 { let digit = (remain % 10) as usize; remain /= 10; buf[fraction_range.start].write(b'0' + digit as u8); } } (remain, fraction_range.end) }; debug_assert!(lead_dec != 0 || coef == 0, "significant digits only"); // SAFETY: The coef_prec is kept one digit below the total number of // digits from coef at all times. unsafe { core::hint::assert_unchecked(lead_dec < 10) } buf[0].write(DECIMAL_PAIRS[lead_dec as usize * 2 + 1]); // SAFETY: The number of decimals is limited, captured by MAX. unsafe { core::hint::assert_unchecked(coef_len <= MAX_COEF_LEN) } // Encode the scale factor in buf[coef_len..text_len]. buf[coef_len].write(LETTER_E); let text_len: usize = match exp { ..10 => { buf[coef_len + 1].write(b'0' + exp as u8); coef_len + 2 }, 10..100 => { #[cfg(feature = "optimize_for_size")] { buf[coef_len + 1].write(b'0' + (exp / 10) as u8); buf[coef_len + 2].write(b'0' + (exp % 10) as u8); } #[cfg(not(feature = "optimize_for_size"))] { buf[coef_len + 1].write(DECIMAL_PAIRS[exp * 2 + 0]); buf[coef_len + 2].write(DECIMAL_PAIRS[exp * 2 + 1]); } coef_len + 3 }, _ => { // SAFETY: A `u256::MAX` would get exponent 77. unsafe { core::hint::unreachable_unchecked() } } }; assert!(text_len > coef_len); assert!(text_len <= MAX_TEXT_LEN); // SAFETY: All bytes up until text_len have been set. let text = unsafe { buf[..text_len].assume_init_ref() }; // SAFETY: Text is set with ASCII exclusively: either a decimal, // or a LETTER_E, or a dot. ASCII implies valid UTF-8. let as_str = unsafe { str::from_utf8_unchecked(text) }; f.pad_integral(is_nonnegative, "", as_str) } static DECIMAL_PAIRS: &[u8; 200] = b"\ 0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ 6061626364656667686970717273747576777879\ 8081828384858687888990919293949596979899";
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree