全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:13314
推到 Plurk!
推到 Facebook!

變數double轉int以無條件捨去或四捨五入會少1?

答題得分者是:brook
senso
高階會員


發表:5
回覆:126
積分:226
註冊:2003-11-27

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-04-09 18:13:40 IP:124.199.xxx.xxx 訂閱
有點老梗的問題,double值指定給int好像因為浮點數會有問題,
要處理無條件捨去一直鬼檔牆,所以只好上來求助。謝謝。

1. double計算時直接給值做運算可以正常算,值不會少1
可是值改成用變數帶入在指定給int變數的時候就會少1

[code cpp]
i1 = 100.0*1.4; //i1為140
i2 = dd*d1; //i2為139,怎麼用變數會少1
d2 = dd*d1; //d2為140
i2 = d2; //i2為140
[/code]


2. 帶有些值的時候還是會少1

[code cpp]
#include "math.hpp"

dd = 1300.0;
d1 = 2.8;
d2 = dd*d1; //d2為3640
i2 = floor(d2); //i2為3639
i1 = d2; //i1為3639
i1 = (int)d2; //i1為3639
[/code]


3.改用 -0.5取四捨五入當作無條件捨去,還是會少1

[code cpp]
dd = 1300.0;
d1 = 2.8;
d2 = dd* d1; //d2為3640
i1 = FormatFloat("#0",d2).ToInt(); //i1為3640
d3 = d2-0.5; //d3為3639.5
i2 = FormatFloat("#0",d3).ToInt(); //i2為3639,沒進位,少1
i2 = FloatToStrF(d3,ffFixed,12,0).ToInt(); //i2為3639,沒進位,少1
i2 = SimpleRoundTo(d3,0); //i2為3639,沒進位,少1
[/code]
編輯記錄
senso 重新編輯於 2009-04-09 21:32:07, 註解 無‧
senso 重新編輯於 2009-04-09 21:33:05, 註解 改錯字‧
senso 重新編輯於 2009-04-10 11:14:27, 註解 重新編排‧
senso
高階會員


發表:5
回覆:126
積分:226
註冊:2003-11-27

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-05-05 15:42:38 IP:61.219.xxx.xxx 訂閱
浮點數誤差真麻煩,設中斷點或丟到Edit1->Text來看都不會有問題,可是之後跑捨去或四捨五入就會有少
後來試著先轉成AnsiString再轉double在做捨去小數位,目前跑起來還滿正常的
[code cpp]
#include "math.hpp"
double dd,d1,d2;
int i1;
dd = 1300.0;
d1 = 2.8;
d2 = dd*d1; //d2為3640
// d2 = AnsiString(dd*d1).ToDouble();
// 好像直接改這行就可以,可是d2如果有在做其他的處理可能還是會有浮點數誤差的問題
// 建議還是最後再轉換比較好
i1 = floor(d2); //i2為3639
i1 = d2; //i1為3639
i1 = AnsiString(d2).ToDouble(); //i1為3640
i1 = FloatToStr(d2).ToDouble(); //i1為3640

//四捨五入
i1 = SimpleRoundTo(d2-0.5,0); //3639
i1 = SimpleRoundTo(AnsiString(d2-0.5).ToDouble(),0); //3640

SetRoundMode(rmDown); //設定第幾位後捨去
i1 = RoundTo(d2,0); //3639
i1 = RoundTo(AnsiString(d2).ToDouble(),0); //3640
[/code]
編輯記錄
senso 重新編輯於 2009-05-05 15:47:41, 註解 無‧
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-05-07 15:02:18 IP:114.32.xxx.xxx 訂閱
為什麼要用 -0.5 呢?
通常的作法是 0.5 如下:

整數 = 浮點數 0.5;

這樣,就有所謂的 四捨五入 的效果。而

整數 = 浮點數;

則是無條件捨去。至於,您提到的把 ( 100.0 * 1.4 ) 給到整數變數內,變成 139,
是因為電腦在儲存 1.4 時,如果是用 1.3999999999999~,那 * 100 就是 139.9999999999~

整數 = 139.999999999; --> 整數值為 139

使用 0.5 的作法:

整數 = 139.999999999 0.5; --> 整數值為 140
------
http://www.ViewMove.com
senso
高階會員


發表:5
回覆:126
積分:226
註冊:2003-11-27

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-05-08 11:37:59 IP:61.219.xxx.xxx 訂閱
dllee你好,
因為我原本是要取整數(無條件捨去),但直接轉為整數有時候會因為那誤差少1
有時候浮點數就剛好140(.0)再 0.5,四捨五入變成141,會失去原本取整數的目的
所以我才-0.5,變139.5,四捨五入140
編輯記錄
senso 重新編輯於 2009-05-08 11:38:46, 註解 無‧
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-05-09 22:20:32 IP:59.105.xxx.xxx 訂閱
整數 = 139.49999999 0.5; --> 整數值為 139
整數 = 139.5 0.5; --> 整數值為 140
整數 = 139.99999999 0.5; --> 整數值為 140
整數 = 140.0 0.5; --> 整數值為 140
整數 = 140.4 0.5; --> 整數值為 140
整數 = 140.49999999 0.5; --> 整數值為 140

以上算式的右邊的是「浮點數」,如我一開始的回覆,

整數 = 浮點數;

就是已經是無條件捨去。

------
http://www.ViewMove.com
senso
高階會員


發表:5
回覆:126
積分:226
註冊:2003-11-27

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-05-11 11:51:07 IP:61.219.xxx.xxx 訂閱
當x.5~x.9 0.5不就多1了? 我不要進位阿
但整數 = 139.99999999~ 沒做處理的話又不一定能取140
那我還要寫其他的判斷條件?

另外AnsiString(d2).ToDouble()
是因為AnsiString(d2)已經把 .99999999~ 自動把最後一位四捨五入了? 所以剛好就變成整數了?
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-05-11 15:44:27 IP:114.32.xxx.xxx 訂閱
您可以試試看,把 #2 的宣告變數 double 改成 long double
double dd,d1,d2;
改成 long double dd,d1,d2;
------
http://www.ViewMove.com
senso
高階會員


發表:5
回覆:126
積分:226
註冊:2003-11-27

發送簡訊給我
#8 引用回覆 回覆 發表時間:2009-05-12 14:51:38 IP:61.219.xxx.xxx 訂閱
改用long double後

有誤差的部分還是有誤差,好像沒什麼差別,
除了AnsiString()的overloaded沒有long double會跳error,
不過FloatToStr(d2).ToDouble()還是能正常跑就是了
wubelin
一般會員


發表:2
回覆:14
積分:18
註冊:2007-10-04

發送簡訊給我
#9 引用回覆 回覆 發表時間:2009-06-04 09:02:45 IP:61.60.xxx.xxx 未訂閱
dllee說過  當 整數 = 浮點數 時 是以無條件捨去的
也就是說x.5-x.9 給整數後,會變成 x 不用擔心會多1
會多1的話 139.999999早就可以正常變成140了
===================引 用 senso 文 章===================
當x.5~x.9 0.5不就多1了? 我不要進位阿
但整數 = 139.99999999~ 沒做處理的話又不一定能取140
那我還要寫其他的判斷條件?

另外AnsiString(d2).ToDouble()
是因為AnsiString(d2)已經把 .99999999~ 自動把最後一位四捨五入了? 所以剛好就變成整數了?
brook
資深會員


發表:57
回覆:323
積分:371
註冊:2002-07-12

發送簡訊給我
#10 引用回覆 回覆 發表時間:2009-07-16 17:12:26 IP:60.251.xxx.xxx 訂閱
// hpp
//#define FIST_MAGIC ((((65536.0 * 65536.0 * 16) (65536.0 * 0.5))* 65536.0))

//可避免少1的情況
__int32 DoubleToInt32(double inval)
{
double dtemp = FIST_MAGIC inval;
return ((*(__int32 *)&dtemp) - 0x80000000);
}
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#11 引用回覆 回覆 發表時間:2009-07-17 14:30:40 IP:114.32.xxx.xxx 訂閱
感謝 brook 分享

上 google 查一下 FIST_MAGIC 才知道,原來這是給快速轉換使用,
此快速轉換內含小數點後 4 捨 5 入的功能
------
http://www.ViewMove.com
系統時間:2024-04-24 3:40:37
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!