題目
解讀
其實(shí)這題是一題數(shù)學(xué)題摩钙,核心是電腦儲(chǔ)存浮點(diǎn)數(shù)的方式。
從我們的科學(xué)記數(shù)法說(shuō)起坯钦。對(duì)于任意一個(gè)實(shí)數(shù)(十進(jìn)制),都可以用A*10^B 來(lái)表示侈玄。但是電腦只能用二進(jìn)制來(lái)儲(chǔ)存東西(0,1)吟温,所以在計(jì)算機(jī)就變成了m*2^e序仙。m我們稱(chēng)之為尾數(shù),e稱(chēng)之為階碼鲁豪。同時(shí)我們也就得到等式:
A*10^B = m*2^e
但還沒(méi)完潘悼,就這樣還遠(yuǎn)遠(yuǎn)不夠。
下面先求對(duì)于位數(shù)下 m 和 e 的最大值
對(duì)于小數(shù)爬橡,10進(jìn)制可以用 a1*10^(-1) + a2*10^(-2) + ... + an*10^(-n)的方式表示治唤。2進(jìn)制的情況顯然相似(對(duì)于用 i 位進(jìn)行儲(chǔ)存):
m = 2^(-1) + 2^(-2) + ... + 2^(-1 - i)
= 1 - 2^(-1 - i)
e 則好辦多了:
e = 2^j - 1
題目給出了0 ≤ M ≤ 9,1 ≤ E ≤ 30(M糙申,E分別為尾數(shù)和階碼的位數(shù))宾添,所以最多共有300種表示方法,進(jìn)而聯(lián)想到打表柜裸。用兩個(gè)二維數(shù)組缕陕,分別儲(chǔ)存對(duì)應(yīng)位數(shù)時(shí)的尾數(shù)和階碼的最大值,分別記為M[i][j]和E[i][j]疙挺。
然后接下來(lái)到計(jì)算對(duì)應(yīng) M 和 E 的值扛邑。還記得剛剛的等式嗎?對(duì)铐然,我們需要借助那個(gè)蔬崩。對(duì)兩邊取十為底的對(duì)數(shù)lg:
lg(A) + B = lg(m) + e*lg(2) = t
由于A小于10,所以lg(A)就是 t 的小數(shù)部分搀暑,自然 B 就是 t 的整數(shù)部分沥阳。
所以,我們的 E[i][j] 只需在計(jì)算出 t 之后取整即可险掀。M[i][j] 則為:
10^( t - E[i][j] )
即可沪袭。(取10的冪是為了方便與A比較,就無(wú)需計(jì)算lg(A)了 )
搞定了M和E樟氢,就到讀入 A 和 B 了冈绊。
因?yàn)檩斎氲母袷且粋€(gè)字符串,所以考慮先當(dāng)成字符串儲(chǔ)存再進(jìn)行處理埠啃。觀(guān)察結(jié)構(gòu)可以把e換成空格死宣,然后用函數(shù)sscanf()進(jìn)行輸入。
最后進(jìn)行遍歷匹配即可碴开。不過(guò)因?yàn)楦↑c(diǎn)數(shù)自身精確度的問(wèn)題毅该,會(huì)存在誤差博秫,所以還需設(shè)一個(gè)誤差范圍。此題誤差設(shè)為 1e-4 效果最好眶掌。
代碼
#include <stdio.h>
#include <math.h>
#include <string.h>
//多層循環(huán)用函數(shù)更容易跳出
void solve(double m, int e);
double M[12][33]; //儲(chǔ)存尾數(shù)表
long long E[12][33]; //儲(chǔ)存階數(shù)表
int main() {
#ifdef TEST
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif // TEST
//打表
int i, j;
char str[25];
for (i = 0; i <= 9; ++i) for (j = 1; j <= 30; ++j) {
double m = 1 - pow(2, -1 - i), e = pow(2, j) - 1;
double t = log10(m) + e * log10(2);
E[i][j] = t, M[i][j] = pow(10, t - E[i][j]);
}
//讀入處理
while (scanf("%s", str) == 1 && strcmp(str, "0e0")) {
double A; int B;
* (strchr(str, 'e')) = ' ';
sscanf(str, "%lf %d", &A, &B);
while (A < 1) A *= 10, B -= 1;
solve(A, B);
}
return 0;
}
void solve(double m, int e) {
for (int i = 0; i <= 9; i++)
for (int j = 1; j <= 30; j++)
if (e == E[i][j] && (fabs(m - M[i][j]) < 1e-4 || fabs(m / 10 - M[i][j]) < 1e-4)) {
printf("%d %d\n", i, j);
return;
}
}