HOWTO · C
How to Print Numbers in Scientific Notation in C
This article introduces how to print numbers in scientific notation in C.
On this page
Use the %e or %E conversion in printf to display a floating-point value in scientific notation. The lowercase conversion prints a lowercase exponent marker; the uppercase conversion prints an uppercase one. A precision such as %.3e sets the number of digits after the decimal point in the significand.
Run this example:
#include <stdio.h>
int main(void) {
double values[] = {123456.789, -0.000012345};
printf("lowercase: %.3e\n", values[0]);
printf("uppercase: %.3E\n", values[1]);
return 0;
}
How Scientific Notation Works in C
Scientific notation writes a nonzero value as a significand multiplied by a power of ten. The significand has one nonzero digit before the decimal point; the exponent records how far the decimal point moves. For example, 123456 can be written as 1.23456 × 10^5, while 0.0000123 can be written as 1.23 × 10^-5.
This notation changes how a value is displayed, not how the underlying float or double stores it. Binary floating-point types have finite precision, so many decimal fractions are approximations in memory. Printing more digits can reveal more of the stored approximation; it does not make the stored value more precise.
Print Scientific Notation with printf
The e and E conversions format a double argument in scientific notation. The exponent marker’s case follows the conversion: %e uses e, and %E uses E. The exponent includes a sign, and implementations print enough digits to represent it. Use %f when you want fixed-point notation for comparison. The POSIX fprintf specification defines the e and E conversions and their precision behavior.
In the opening example, %.3e and %.3E each show three digits after the decimal point in the significand. The sign of the value remains part of the formatted number. For values outside the range where fixed-point output is easy to read, scientific notation keeps the significand compact while the exponent carries the scale.
The conversion expects a double argument. A float passed through printf is promoted to double, but an integer is not. To format an integer value scientifically, convert it explicitly, for example with (double)count, and use %e or %E. Large integers may lose low-order digits during conversion if they exceed the precision that double can represent.
Control the Number of Digits After the Decimal Point
For %e and %E, the precision counts digits after the decimal point, not the total significant digits. Thus %.2e prints two fractional significand digits, usually three significant digits in all. If you omit the precision, the default is six digits after the decimal point. The value is rounded for display to the requested precision; its stored value is unchanged. The POSIX fprintf specification states the precision rule and six-digit default.
Choose precision for the display or interchange format your application needs. More printed digits do not guarantee that a decimal string is an exact representation of the binary floating-point value. If you need a particular number of significant digits, account for the leading significand digit when selecting the precision.
Format Scientific-Notation Strings Safely
When the formatted number must be stored or passed to another function, use snprintf with a buffer capacity. Its capacity includes the terminating null character. It returns the number of characters that would have been written, not counting that terminator; a return value greater than or equal to the capacity means the output was truncated. A negative return value indicates a formatting error. The POSIX fprintf specification defines snprintf’s return value and truncation behavior.
Run this self-contained example:
#include <stdio.h>
int main(void) {
double measurement = 0.000012345;
char text[64];
int length = snprintf(text, sizeof text, "%.3e", measurement);
if (length < 0) {
puts("formatting error");
return 1;
}
if ((size_t)length >= sizeof text) {
puts("buffer too small");
return 1;
}
printf("value: %s\n", text);
return 0;
}
snprintf writes at most the available capacity and terminates the buffer when its capacity is greater than zero. Check its return value before treating the buffer as a complete formatted result. Avoid unbounded sprintf when the buffer size is not guaranteed to fit.
Should You Write a Custom Scientific-Notation Function?
Usually, no. %e and %E already handle the significand, exponent, sign, rounding, and a value of zero according to the C library’s formatting rules. A hand-written conversion needs to handle zero separately and normalize values below one as well as values at or above ten. It must also consider negative values, rounding that changes the significand, and the limits of the numeric type. A loop that only divides positive values by ten does not correctly cover those cases.
Prefer printf for direct display and snprintf for bounded string formatting. Write a custom formatter only when you need a specific representation that the standard conversions cannot provide, and define and check its behavior for the full input range. For ordinary scientific notation, the standard conversions are shorter and less error-prone.