for 循環為什麼不支持小數?
半夜終極大更新。。。。。
已附帶9.9在32位機器上的精確值
一句話版本:google IEEE754 有真相
詳細版本:
s是符號位 n bits那一部分是指數位 E m bits 那一部分是significand位 M任何一個浮點數數學上的精確值是對於32bit和64bit而言
s都是1bit,而E和M長度部分是IEEE規定的。。。
32bit E長度為8bit64bit E長度為11bit下面來通過9.9的binary representation來算一下其精確值利用這一段代碼(在小端機上!!)#include&
using namespace std;
int main(){
float test{ 9.9f };
unsigned char *print{ (unsigned char *)test };
unsigned int mask{ 1 };
for (int i = sizeof(float) - 1; i &>= 0; --i){
unsigned int temp{ print[i] };
for (int i = 7; i &>= 0; --i)
cout &<&< ((temp (mask &<&< i)) &>&> i);
}
cout &<&< endl;
return 0;
}
獲得binary representation
sign bit是0 所以第一部分是1exp bit是128+2-127, 注意這裡的-127是自帶的偏移位,所以第二部分的值是8significand bit更tricky一點,這裡所有的位都是小數點後的位,而且還自帶1作為整數部分
所以這一部分是算出來是=1.2374999523162841796875把以上三個部分乘起來就得到:9.8999996185302734375(喪心病狂的不等於9.9)最後扯一點浮點數和資訊理論的關係
浮點數為什麼叫浮點數?因為上邊那一坨的精確值算出來小數點具體在哪兒是浮動的浮點數說是可以表示10^38範圍(32bit 少年們可以算一下當家庭作業)但是有個根據資訊理論我們知道 32bit只能表達2^32個不同的值 所以回到樓主的問題來上說你隨手選一個實數剛好能被精確表達的概率是0(不是很小,是0,浮點數的集合測度是0,不管用多少位表達,不理解請回憶高數)
So 如果要想精確表達你要的數,請使用自己實現定點數類
BTW 浮點數至少弄炸過兩次飛船,還導致過一次美國本土被導彈轟炸,so,少年,古往今來的仁人志士與你同在我認為這個問題跟浮點數運算過程中的截斷誤差是兩碼事,雖然這裡面的確出現了截斷誤差。我們重新看一下程序:
現在我們在腦海里建立一個運算過程:有一個實數0,它每次增加0.1,最後增加到不大於9.9的一個數為止。#include &
int main(){
for(double i = 0;i &<= 9.9;i=i+0.1){
std::cout&<&
沒這個需求
此問題與for無關,與浮點數的計算精度有關。樓主你要記住一件事,浮點數是不能判相等的,比如你要判斷someVar的值是不是等於0,要這樣寫
abs(someVar - 0.0) &< 1e-6
someVar &<= 9.9怎麼寫?
someVar &< 9.9 || abs(someVar - 9.9) &< 1e-6
someVar &< 9.9 + 1e-6
如此類推
你自己看看你用浮點數循環出來的彙編就會發現浮點數最好不要用於循環的控制整數的循環控制很簡單,一個inc 一個cmp,一個jz或者jnz足矣 浮點就麻煩得多
除了浮點數判等誤差的原因之外,請思考下for的語義是什麼?你今天吃了三頓飯,你會不會對人描述為:第0.1頓: 早飯,油條豆漿第0.2頓: 午飯,回鍋肉和米飯第0.3頓: 晚飯,臊子面這不符合人類計數的習慣。而for就是個循環計數器,蛋疼才會每次自增01.
浮點數在計算到最後一位的時候都會累積誤差,但是除非數值接近0,否則cout默認輸出都不會精確到那麼多。同樣的現象在excel裡面也可以實現
因為浮點數在內存中的表示問題
當i初始化為0時,i的真實值為0,所以以0.1為間隔自增,到9.9時再自增0.1,退出循環
但是當i被初始化為9.9時,i的值並不精確等於9.9,所以到了0.1的時候,自減仍舊大於0顯然for只是條件循環語句,第二從句的表達式為真就繼續執行。跟小數還是大樹沒關係
————————————————最後一次運算貌似是 i(此時值為0.1)減0.1等於0,但實際上i不等於0.1,而是0.1+(1.87905e-14),減去0.1之後等於1.87905e-14。這是個極小的數。浮點數的存儲方式決定了部分運算會不精確。你可以這樣來理解:它的存儲位一部分用來存底數,一部分用來存指數。當指數那部分過大,就會擠佔一部分底數的存儲位置。不同底數和指數的數字之間的精度必然不同,因此運算可能會留下一些不幹凈的小數。———————————————— @題主 用PHP跑了一下,有類似的結果:浮點數比較不要用常規運算符,應該設定一個閾值epsilon去比較,具體原因請深究浮點數的儲存表示方式。
不明所以 上個圖供大家分析---------------------------------------
這不是for的問題,是計算機精度問題。數字在計算機中是以二進位表示。如double a=0.2;doubleb=0.1;你可以試著列印一下a+b,並不等於0.3;但是如果a=0.15;b=0.15;a+b就等於0.3了建議你看看《計算機組成原理》就明白了
第一張圖
真的沒看出來哪裡不對 不知道你問題在哪第二張圖
浮點數是沒有那麼高的精確度的 理解一下精度的概念想像一下 i初始化的時候 = 9.00000001 (某個比9大一點點的正數)如果你懂C 把cout&<&printf ( "%.1f " , i ) ; 最後就不會出現那個奇怪數字了第三張圖 你想像一下 i初始化的時候 = 0.00000001 (某個很小的正數) 最後就會輸出9.9了推薦閱讀:
※Scala以cascade的方式調用函數有什麼不妥嗎?
※遊戲的數值系統的實現和演化
※電腦語言「0,1」的蘊涵的數理邏輯知識 到底是什麼樣的?如何後天將其與思維模式結合?
※極樂技術周報(第二十七期)
※FizzBuzz