Re: [語法] 在寫程式時 遇到將浮點數轉換成整數的問題

看板C_and_CPP作者時間14年前 (2009/09/16 10:49), 編輯推噓22(22038)
留言60則, 5人參與, 最新討論串7/7 (看更多)
: -- : ※ 發信站: 批踢踢實業坊(ptt.cc) : ◆ From: 123.193.12.79 : 推 VictorTom:您提了我才發現, 為什麼ceil/floor回傳都是浮點數啊@_@" 09/15 22:31 : → VictorTom:這兩個不就一個round up一個round down嗎@_@" 09/15 22:31 : → pttfly:yes @@" 09/15 22:31 : 推 holymars:不然要回傳int嗎..要是超過int範圍不就炸了XD 09/15 22:58 : → VictorTom:有道理說, 我忘了浮點數值域遠大得多; 可是這樣一來把浮 09/15 23:52 : → VictorTom:點誤差考慮進來, 搞不好傳回來的又是個錯的結果啊@_@" 09/15 23:53 考慮一下float的格式就知道這種事不會發生 float的數字都能表達成 (M) * 2^N 這種格式 單精度的話M由23個bit組成 如果N >=0 float一定是個整數 回傳值沒有誤差問題 如果N <= -23 float一定是個0~1中間的數 回傳值也不會有誤差問題 如果N是-1~-22 M的bit表達一定能分為「整數部」和「小數部」兩個部份 把小數部丟掉 回傳值一樣不會有誤差問題 XD 有的指令集會有ceil和floor的指令 在x86上的話你可以用SSE硬幹一個出來 http://gcc.gnu.org/ml/gcc-patches/2006-10/msg01468.html -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.32.15.163

09/16 11:54, , 1F
整數->浮點數會有誤差, 浮點數->整數不會有誤差吧? @@
09/16 11:54, 1F

09/16 11:55, , 2F
浮點數->整數 指的是 cast (round) 成 int
09/16 11:55, 2F

09/16 12:09, , 3F
小弟我倒是忘了考慮表示法vs整數的特性會不會剛好在這段
09/16 12:09, 3F

09/16 12:10, , 4F
不產生誤差了Orz 回l大, 我說的誤差是浮點數->浮點數後
09/16 12:10, 4F

09/16 12:10, , 5F
面那個浮點數, 因為floor/ceil的回傳值都是浮點數@_@"
09/16 12:10, 5F

09/17 00:16, , 6F
float(4294967295) = ? XD, 另外 x87 有 fisttp 可以用
09/17 00:16, 6F

09/17 11:32, , 7F
浮點數->整數也有可能發生誤差的情形,請看下例:
09/17 11:32, 7F

09/17 11:32, , 8F
float x = 1.801; int y = (int)(x * 1000.0);
09/17 11:32, 8F

09/17 11:33, , 9F
這樣在 x86 上, y的結果會變成1800,而不是1801
09/17 11:33, 9F

09/17 11:34, , 10F
但是在其他的processer,就能得到正確的1801
09/17 11:34, 10F

09/17 11:48, , 11F
樓上那個是乘法的誤差 不是cast的誤差吧
09/17 11:48, 11F

09/17 11:57, , 12F
這不單純是乘法的誤差,可以看看下例:
09/17 11:57, 12F

09/17 11:58, , 13F
int y = (int)(1.801 * 1000.0);
09/17 11:58, 13F

09/17 11:59, , 14F
以及 float x = 1.801; int y; x *= 1000.0; y = (int)x;
09/17 11:59, 14F

09/17 11:59, , 15F
以上這兩例都可以在x86上取得正確的1801
09/17 11:59, 15F

09/17 12:01, , 16F
這變因又更多了 剛剛忘了還有10進位轉二進位的誤差
09/17 12:01, 16F

09/17 12:01, , 17F
你要就直接給一個浮點數的binary表示法, 證明它轉成int
09/17 12:01, 17F

09/17 12:02, , 18F
會錯. 要不然就證明這些多餘的動作不會影響結果
09/17 12:02, 18F

09/17 12:35, , 19F
順便一題 你的第一個例子和後兩個的差別在
09/17 12:35, 19F

09/17 12:35, , 20F
第一個是double->int, 後面是double->float->int
09/17 12:35, 20F

09/17 12:38, , 21F
提^
09/17 12:38, 21F

09/17 12:54, , 22F
不知道你有沒有親身驗證過這個問題... 上述的code你可以改
09/17 12:54, 22F

09/17 12:55, , 23F
成double試看看,結果我就不說明了.
09/17 12:55, 23F

09/17 12:58, , 24F
測過了 你想表達什麼
09/17 12:58, 24F

09/17 13:00, , 25F
float改成double後,結果有什麼差異否?
09/17 13:00, 25F

09/17 13:01, , 26F
全部是1801 所以呢
09/17 13:01, 26F

09/17 13:01, , 27F
你又舉了三個*完全不同*的case 這有又什麼影響
09/17 13:01, 27F

09/17 13:05, , 28F
1801是哪一段啊?
09/17 13:05, 28F

09/17 13:07, , 29F
我實在不想和你戰,覺得沒什麼意義,我只不過想提醒大家可能
09/17 13:07, 29F

09/17 13:08, , 30F
會被乎略的錯誤而已. x86 的浮點有一些特性會產生和其他
09/17 13:08, 30F

09/17 13:10, , 31F
CPU不同的結果,如此而已.
09/17 13:10, 31F

09/17 13:10, , 32F
不要越扯越遠 你一開始是說浮點數->整數可能會有誤差
09/17 13:10, 32F

09/17 13:11, , 33F
你是你舉的例子誤差是在double->float的四捨五入 就這樣
09/17 13:11, 33F

09/17 13:11, , 34F
但^
09/17 13:11, 34F

09/17 13:16, , 35F
其實我不是很懂我說的這個跟你說的有什麼關係耶...
09/17 13:16, 35F

09/17 13:17, , 36F
或許你用你的想法解釋為何會有1800的結果會比較理想
09/17 13:17, 36F

09/17 13:18, , 37F
1000.0是double, 1000.0f才是float
09/17 13:18, 37F

09/17 13:18, , 38F
所以你所有運算會被先cast成double算
09/17 13:18, 38F

09/17 13:19, , 39F
(int)(x*1000.0)是double直接變成int
09/17 13:19, 39F

09/17 13:19, , 40F
x*=1000.0; (int)x是做完double乘法後轉float再轉int
09/17 13:19, 40F

09/17 13:19, , 41F
double x; int y = (int)(x * 1000.0); 請問你的結果?
09/17 13:19, 41F

09/17 13:21, , 42F
1800啊= = 有什麼就直說好嗎 這樣很煩
09/17 13:21, 42F

09/17 13:21, , 43F
啊看錯 1801..
09/17 13:21, 43F

09/17 13:22, , 44F
不好意思,我剛x忘了給初值,應該要double x = 1.801;
09/17 13:22, 44F

09/17 13:23, , 45F
我用x86 32bit Linux執行的結果是1800
09/17 13:23, 45F

09/17 13:23, , 46F
在ARM Linux上跑,結果卻是1801,而1801也是我們所希望的
09/17 13:23, 46F

09/17 13:24, , 47F
x*1000.0在x是float跟double時算出來會有一點誤差
09/17 13:24, 47F

09/17 13:24, , 48F
在cast成int前就有差了
09/17 13:24, 48F

09/17 13:26, , 49F
再來 float x = 1.801; int y = (int)(x * 1000.0f);
09/17 13:26, 49F

09/17 13:26, , 50F
上面這樣寫,x86 -> 1800, ARM->1801
09/17 13:26, 50F

09/17 13:31, , 51F
乘法的實作方式不同吧..
09/17 13:31, 51F

09/17 13:32, , 52F
你的意思是compiler還是CPU?
09/17 13:32, 52F

09/17 13:32, , 53F
cpu
09/17 13:32, 53F

09/17 13:33, , 54F
可以用 cout << (unsigned int&)(x * 1000.0f);
09/17 13:33, 54F

09/17 13:33, , 55F
看有沒有不一樣
09/17 13:33, 55F

09/17 13:34, , 56F
那原先的double->float四捨五入之說應該....
09/17 13:34, 56F

09/17 13:35, , 57F
啊? 那是同機器上不同code的比較啊...
09/17 13:35, 57F

09/17 13:36, , 58F
有一篇文章是一個日本人寫的,可能有點久了,我暫時找不到
09/17 13:36, 58F

09/17 13:37, , 59F
大意是說x86的浮點有一個擴張精度,會讓指數部份變成15bit
09/17 13:37, 59F

09/17 13:37, , 60F
而不是一般所認知的11bit
09/17 13:37, 60F
文章代碼(AID): #1Ai58jCA (C_and_CPP)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 7 之 7 篇):
文章代碼(AID): #1Ai58jCA (C_and_CPP)