簡體   English   中英

C 浮點數中的精度

[英]Precision in C floats

通常我們說浮點數的精度為小數點后 6 位。 但是如果我們存儲大量 10^30 的順序,我們將不會得到小數點后的 6 位數字。 那么說浮點數的小數點后精度為 6 位是正確的嗎?

“小數點后 6 位數字”是無稽之談,你的例子很好地證明了這一點。

float數據類型的精確規范。

float的精度為24位。 根據在線消息來源,有 23 位表示二進制小數點后的小數,另外還有一個“隱式前導位”。 這總共給出了 24 個有效位。

因此,在十進制數字中,這大約是:

24 * 日志(2)/日志(10)= 7.22

聽起來您問的是小數點精度(小數點后的數字),而有效數字(不包括前導零和尾隨零的總位數)是描述數字准確性的更好方法。

你是對的,當數字較大時,小數點后的位數會改變 - 但如果我們談論精度,當數字較大時,有效數字的數量不會改變。 然而,十進制數的答案並不簡單:


現在大多數系統都使用IEE 浮點格式來表示 C 中的數字。但是,如果您正在處理一些不尋常的事情,那么值得檢查一下。 單精度 IEE float由三部分組成:

  • 符號位(這個數字是正數還是負數)
  • (通常也有符號的)指數
  • 分數(應用指數之前的數字)

正如我們所料,這一切都以二進制形式存儲。


有多少有效數字?

如果您使用的是 IEE-754 數字,“有多少有效數字”可能不是一個簡單的思考方式,因為精度是以二進制有效數字而不是十進制來衡量的 float的小數部分只有 23 位精度,但因為有一個隱式前導位(除非小數部分全為零,這表示最終值為 1),所以有 24 位有效精度。

這意味着有 24 個有效的二進制數字,不能轉換為精確的十進制有效數字。 您可以使用公式 24 * log(2) / log(10) 來確定有 7.225 位十進制精度,這不是您問題的一個很好的答案,因為有 24 個有效二進制數字的數字僅有 6 位有效的十進制數字。

因此,單精度浮點數具有6-9 位精度的有效十進制數字,具體取決於數字。

有趣的是,您還可以使用此精度計算出可以成功表示為單精度浮點數的最大連續整數(從零開始計數)。 它是 2^24,或 16,777,216。 您可以准確地存儲更大的整數,但前提是它們可以用 24 位有效二進制數字表示。


進一步的瑣事:分數組件的有限大小與在 Javascript 中導致此問題的原因相同:

> console.log(9999999999999999);
10000000000000000

Javascript 數字始終表示為雙精度浮點數,其精度為 53 位。 這意味着在 2^53 和 2^54 之間,只能表示偶數,因為任何奇數的最后一位都丟失了。

浮點數的精度應該用二進制數字來衡量,而不是十進制數字 這是因為計算機對二進制數進行運算,而一個二進制分數只能近似一個十進制分數。

語言律師會說 C 標准未指定float的確切寬度,因此取決於實現,但在任何平台上,您都可能遇到 C float表示IEEE754 單精度數。

IEEE754 規定浮點數采用科學記數法:(-1) s ×2 e × m
其中s為 1 位寬, e為 8 位寬, m為 23 位寬。 在數學上, m是 24 位寬,因為它總是假設最高位是 1。

因此,可以用這種表示近似的最大十進制數字數是: log 10 (2 24 ) = 7.22 這近似於七個有效的十進制數字,以及一個從 2 -126到 2 127的指數。

請注意,指數是單獨測量的。 這就像您使用普通的科學記數法一樣,例如“一個人重 72.3 公斤 = 7.23×10 4克”。 注意這里有三位有效數字,代表數字只精確到100克以內。 但也有一個完全不同的指數 你可以有一個非常大的指數,但有效數字很少,比如“太陽的重量是 1.99×10 33克”。 大數字,幾位數。

簡而言之,浮點數可以存儲大約 7-8 個有效十進制數字 讓我用一個例子來說明這一點:

1234567001.00
         ^
         +---------------- this information is lost

.01234567001
           ^ 
           +-------------- this information is lost

基本上,浮點數存儲兩個值: 1234567和小數點的位置。

現在,這是一個簡化的示例。 浮點數存儲二進制值而不是十進制值。 一個32 位的 IEEE 754 浮點數有 23 個“有效位”(加上第一個總是假定為 1 的位)的空間,它對應於大約 7-8 個十進制數字。

 1234567001.00 (dec) =

 1001001100101011111111101011001.00 (bin)  gets rounded to

 1001001100101011111111110000000.00 =
  |    23 bits           |

 1234567040.00 (dec)

這正是 C 產生的:

void main() {
    float a = 1234567001;
    printf("%f", a);      // outputs 1234567040
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM