為什麼這篇C語言 取 小數點鄉民發文收入到精華區:因為在C語言 取 小數點這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者tropical72 (藍影)看板C_and_CPP標題Re: [問題] 取小數點時間Mon M...
※ 引述《s4399》之銘言:
: EX:n=1.000056
: 我該如何利用printf("%.f",n)的指令來取得56這兩個數值?
: 或是這麼說……
: 如果a/b=1.0026595698...
: 我該如何只取出1.00後面的數據丟給n
: 又如果我只要取出2659這四位數的話,該怎麼做?
先假設變數名稱
typedef unsigned long long uint64;
double d1 = 1.000056; // 10^6
double d2 = 1.0026595698; // 10^10
double d3 = 1.123456789012345; // 10^15
1. 先去看 十三戒之十一 ,連結一起看的話大概 30~60 mins 左右。
>> a/b=1.0026595698
由於這句話,認為你是在計算過程中要求得小數後之非零數字,
2. 一般數字小的時候可確實可這樣做
d1 = d1 - (int)d1; /* 先只取小數部份 */
uint64 i1 = d1*1000000 - (uint64)d1*1000000ULL; /* 再將小數化為整數 */
因雙精度浮點數之 matissa 54 bits, 有效位數約 15.22 位,
用 unsigned int 去存,會爆掉的機率太大了,於是直接給 64 bits 去存
接著其它的 d2, d3, 分別以上述做法,去乘 10^10, 10^15 來做。
其中若用 unsigned int 去接,d3 必爆 (d2 也快了),這裡可再去試試。
優點:速度快
缺點:調整後容易有誤差、要指定該魔數數字。
3. 較普遍性的作法
我不是很清楚為何要把小數點後的零全都拿掉,即使要調整,
我認為也是該保留零較佳,這樣到時要比較大小、再合併回浮點數時也較方法,
於是可以把這個寫成副函式呼叫
uint64 get_matissa(double x)
{
double x_float = x - (int)x;
return x_float * 1000000000000000ULL; /* 精度 15.22 */
}
優點:呼叫方便、魔數數字只要用一次
缺點:調整後仍有誤差。
4. 較準確的作法
我認為較準確應是下面這種作法
uint64 get_matissa2(double x)
{
uint64 ret, t;
char buffer[50], Zero[20];
sprintf(buffer, "%.15lf", x);
sscanf(buffer, "%*llu%[^1-9]%llu", Zero, &ret);
return ret;
}
會用 .15lf 是因 double 有效位數約 15.22 位, 第 16 位開始便沒參考價值。
先用 sprintf 到一 buffer 裡面去,再直接 parse ,
但這麼做效能會「特慢」, 因 sprintf 、sscanf 都是速度超慢的函式,
但這麼做拿到的數值應是最準的。
5. 其它方式
有種方式還沒實做,但也不確定可行 - 直接去分析 IEEE 754 欄位,
直接抽出小數部份。之所以「不確定」,是因我不甚確定每套 compiler
是否都從 IEEE 754 (據悉,部份 compiler 在數值極小的時候會有所「手腳」),
若不是的話那這部份就可以不用做。
--
YouLoveMe() ? LetItBe() : LetMeFree();
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.73.222