HOWTO · C
用 C 的科學計數法列印數字
本文介紹如何在 C 語言中以科學計數法列印數字
本頁內容
使用 printf 中的 %e 或 %E 轉換,將浮點值顯示為科學記數法。小寫轉換會輸出小寫指數標記,大寫轉換則會輸出大寫標記。像 %.3e 這樣的精度設定,會指定有效數字小數點後的位數。
執行此範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#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;
}
C 語言中的科學記數法原理
科學記數法會將非零值表示為有效數字乘以 10 的某次方。有效數字的小數點前有一位非零數字;指數則表示小數點移動了幾位。例如,123456 可寫成 1.23456 × 10^5,而 0.0000123 可寫成 1.23 × 10^-5。
這種記法改變的是數值的顯示方式,不會改變底層 float 或 double 的儲存方式。二進位浮點型別的精度有限,因此許多十進位小數在記憶體中只能以近似值表示。輸出更多位數可能會顯示出更多儲存值的近似細節,但不會提高儲存值本身的精度。
使用 printf 列印科學記數法
e 和 E 轉換會將 double 引數格式化為科學記數法。指數標記的大小寫會依轉換方式而定:%e 使用 e,%E 使用 E。指數會包含正負號,實作也會輸出足以表示指數的位數。若要以固定小數格式顯示以便比較,可使用 %f。POSIX fprintf 規格定義了 e 和 E 轉換及其精度行為。
在前面的範例中,%.3e 和 %.3E 都會在有效數字的小數點後顯示三位數。數值的正負號會保留在格式化結果中。對於不適合以固定小數格式閱讀的數值,科學記數法能讓有效數字保持精簡,並以指數表示數值的尺度。
這些轉換預期收到 double 引數。透過 printf 傳入的 float 會提升為 double,但整數不會。若要以科學記數法格式化整數值,請先明確轉型,例如使用 (double)count,再搭配 %e 或 %E。若大型整數超出 double 可表示的精度,轉型時可能會失去低位數字。
控制小數點後的位數
對 %e 和 %E 而言,精度計算的是小數點後的位數,不是有效數字總數。因此,%.2e 會輸出兩位有效數字小數,通常合計為三位有效數字。若省略精度,預設會在小數點後輸出六位。數值會依指定精度四捨五入後顯示;儲存的值則不會改變。POSIX fprintf 規格說明了精度規則與六位數的預設值。
請依照應用程式所需的顯示格式或交換格式選擇精度。輸出更多位數,不代表十進位字串就能精確表示二進位浮點值。若需要特定位數的有效數字,選擇精度時也要計入有效數字開頭的那一位。
安全地格式化科學記數法字串
若要儲存格式化後的數字或將它傳給其他函式,請使用 snprintf 並指定緩衝區容量。容量包含結尾的空字元。snprintf 傳回原本會寫入的字元數,但不包含結尾空字元;若傳回值大於或等於容量,表示輸出遭到截斷。負的傳回值則表示格式化錯誤。POSIX fprintf 規格定義了 snprintf 的傳回值與截斷行為。
執行這個自足範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
#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 最多只會寫入可用容量,且容量大於零時會以空字元結束緩衝區。在將緩衝區視為完整的格式化結果之前,請先檢查傳回值。若無法確定緩衝區大小足以容納輸出,請避免使用沒有長度限制的 sprintf。
是否該自行撰寫科學記數法格式化函式?
通常不需要。依照 C 函式庫的格式化規則,%e 和 %E 已能處理有效數字、指數、正負號、四捨五入以及零值。手寫轉換函式必須另外處理零,並將小於 1 的數值,以及大於或等於 10 的數值正規化。它也必須考慮負值、四捨五入導致有效數字改變的情況,以及數值型別的範圍限制。只會將正值反覆除以 10 的迴圈,無法正確涵蓋這些情況。
直接顯示時優先使用 printf,需要有界的字串格式化時則使用 snprintf。只有在標準轉換無法提供所需表示方式時,才自行撰寫格式化函式,並明確定義及檢查它對完整輸入範圍的處理方式。一般的科學記數法格式化使用標準轉換即可,程式碼較短,也較不容易出錯。