先看一個比較有趣的程式...
/*************************************************************/
# include <stdio.h>
int main()
{
float x;
int i;
printf("Input a real number...\n");
if (scanf("%f", &x) < 1)
exit(1);
for (i = sizeof x * 8 - 1; i >= 0; i--)
putchar((*(int *)&x & 1 << i) ? '1' : '0');
putchar('\n');
return 0;
}
/*************************************************************/
上面那是個小小的程式.
用來印出一個 IEEE 754 浮點數所具有的二進位格式.
好比說
1.53 - 00111111110000111101011100001010
早上我看到大部分的同學都卡在一個問題上頭...
『實數要怎麼對另一個實數取餘數?』
然而, 實數是不能取餘數的(就數學上來說, 那沒有意義. )
在數學裡頭只有整數對整數才會有餘數(餘數的定義).
因此...
% (modulus operator) 這個運算子只能用在整數上頭.
也就是 (int) % (int) 才可以.
像是 19 % 4 == 3, 3 % 2 == 1 等等...
而 3.7 % 1.2, 5.54 % 0.37 都是不對的.
所以, 當我們要把 180.00cm 轉成 5ft 10.87in 的時候.
要考慮到的是倍數關係...
海豹弄了個好玩的寫法...
因為題目中所有的值放大一百倍之後都會變成整數.
於是他先把 180.00(cm) 乘上 100.
對 3048 取餘數之後再除以 100...
這個值就當作英呎.
實際上這種作法的確行得通...
在電腦裡頭, 所有『有限位數』的實數(像是 Ex.3, 都為兩位小數)...
在實作上頭都是用整數表示.
只要記得輸出的時候把放大倍率(此例為 100)除回來.
不過這裡不用這麼費工夫... :)
ANSI C 『規定』, 浮點數轉換為整數的時候, 是『捨去』小數部份.
(int)3.142 == 3
(int)sqrt(2) == 1
這一些... 沒有例外.
以今天的練習來說...
int h_ft;
h_cm = 180;
h_ft = h_cm / 30.48;
隨便到哪一台電腦上得到的答案都一樣是 h_ft == 5.
順帶提到一點: 這種寫法, VC++ 會給 warning...
它會希望你寫
h_ft = (int)(h_cm / 30.48);
不過實際上這只是違反了 C++ 的原則(不是 C).
VC++ 在這點做得很爛, 它把 C 跟 C++ 全搞在一起了...
C 跟 C++ 在很多地方有著根本性的衝突...
不像一般人想的那麼簡單: C++ == Advanced C.
請千萬記得: Visual C++ 的 C warning 有劇毒.
那反過來說...
如果把 h_ft 由 int 改為 double 好不好?
我看到有同學是這樣寫的...
double h_ft;
h_ft = (int)(h_cm / 30.48);
printf("%.0fft %.2fin\n", h_ft, h_in);
這個答案會對哦...
而它主要是因為 IEEE 754 的緣故(這回就不是 C 的規定了. :P)
浮點數的整數部份, 在不溢位的轉換過程當中, 剛好會被保留下來...
但是! 只有整數的部份不變而已, 小數部份可是會變動的.
不過在前面那個例子當中, 恰巧我們要捨棄小數點以下的數字.
所以答案會對...
可以的話, 最好還是用整數...
除了效率問題(浮點運算比較慢).
最主要是設計哲學上的考量.
『應該是甚麼, 它就要是甚麼. 』
這裡的英呎都是整數, 那麼它表現起來就要有整數的樣子.
不過提到這個哲學嘛, 要等底子好一點才談得起來了... :)
--
新詩練習:新鮮。踩破初春裡的狗大便;不經意的滄桑,滿溢著嫩黃的喜悅。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.224.161.253
※ 編輯: Muscovy 來自: 61.224.161.253 (03/20 17:43)