以下文章轉(zhuǎn)載自http://www.voidcn.com/blog/crazysillynerd/article/p-3592545.html
時間限制:3.000秒
題目鏈接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=830&page=show_problem&problem=2909
算是個數(shù)學(xué)題吧,雖然在AOAPC上面給放到象征水題的第三章里面了臣镣。
這個題基本就是幫著你復(fù)習(xí)了一遍浮點數(shù)的存儲方式了厂抽。浮點數(shù)在計算機里是分三部分表示的妻导,最前面一位表示符號,后面一部分是尾數(shù)抛丽,最后一部分是階碼,表示方法類似于科學(xué)記數(shù)法,不過是二進制的巍扛,尾數(shù)是M階碼是E的話那么表示起來就是M × 2^E了。然后對于M還有一個要求乏德,就是1/2 ≤ M < 1撤奸,所以用二進制表示M的話就應(yīng)該是0.1XX……,用計算機表示的時候就把最前面的“0.1”這個永遠不變的部分給省略掉喊括,只表示可能變化的部分胧瓜。階碼部分則是只用二進制表示E。
上面的圖就給出了一個例子郑什,前面的0表示是正數(shù)府喳。后面8位表示尾數(shù)m,這里是0.111111111(注意后面是9個1蹦误,因為頭一個省略了)劫拢。之后那個0表示分割,最后面6位表示e的二進制為111111强胰。所以這個數(shù)就是
。
這個如果直接去算的話相當(dāng)麻煩黎休,當(dāng)E很大的時候數(shù)會直接超出上限浓领。這個時候可以反過來想,最大的時候M和E的每一位肯定都是1势腮,并且又有0 ≤ M ≤ 9且1 ≤ E ≤ 30的限定联贩,所以一共只有300種情況,自然就想到了打表捎拯,先用二重循環(huán)枚舉M和E可能出現(xiàn)位數(shù)的所有情況打一張表泪幌,然后輸入的時候倒回去找即可。
假設(shè)當(dāng)前一層M和E的值為m和e署照,它們的位數(shù)分別為i和j祸泪。
首先計算m的值,用二進制表示的話藤树,m的值為0.11…浴滴,也就是m = 2^(-1) + 2^(-2) + … + 2^(-1 - i)(i比實際1的個數(shù)少1個),也就是m = 1 - 2^(-1 - i)岁钓。
接下來就是計算e的值升略,不難得出,e = 2^j - 1屡限。
那么也就有m * 2^e = A * 10^B品嚣,似乎可以直接計算了。然而钧大,直接這樣算的話是不行的翰撑,因為當(dāng)e太大的話(e最大可以是1073741823,注意這還只是2的指數(shù))啊央,等號左邊的數(shù)就會超出上限眶诈,所以要想繼續(xù)算下去,就得自己去想辦法再寫出滿足要求的類來瓜饥,這顯然太麻煩了逝撬。所以,這個時候我們對等式兩邊同時取對數(shù)乓土,這個時候就有 log10(m) + e × log10(2) = log10(A) + B宪潮。因為此時m和e的值都是確定的,所以不妨令等式左邊為t趣苏,也就有t = log10(A) + B狡相。
這個時候就有問題了,A和B怎么算食磕。
寫題解的時候突然意識到了這個問題尽棕,讀題的時候很多人,包括我彬伦,都把AeB默認(rèn)為了科學(xué)記數(shù)法滔悉,在ACM協(xié)會群里面討論的時候很多人也都說這是科學(xué)計數(shù)法蟀悦。先來看如果是科學(xué)記數(shù)法的時候應(yīng)該怎么辦。
如果是科學(xué)記數(shù)法的話氧敢,那么對于A,就有1 ≤ A < 10询张。那么0 < log10(A) < 1孙乖。所以t的小數(shù)部分就是log10(A),整數(shù)部分就是B份氧,即B = ?t?唯袄,A = 10^(t - B)。那么接下來蜗帜,我們只需要開出兩個二維數(shù)組來恋拷,分別記錄對應(yīng)i和j下A和B的大小,之后從輸入里提取出A和B的大小厅缺,去二維數(shù)組里面查找對應(yīng)的i和j即可蔬顾。
這種辦法在UVA上面是可以直接AC的,但是我卻感覺這題這樣A了有點數(shù)據(jù)太水的感覺湘捎,秉著處女座+強迫癥死磕到底的精神诀豁,我們看下哪里有問題。
其實回頭讀下題窥妇,我們發(fā)現(xiàn)科學(xué)記數(shù)法1 ≤ A < 10的條件是我們腦補出來的舷胜,題目里面根本沒有提及,只是簡單交待0 < A < 10活翩。也就是說烹骨,對于確定的M和E的位數(shù),十進制的表示可以有多種材泄,例如樣例中的5.699141892149156e76沮焕,下面的數(shù)據(jù)應(yīng)當(dāng)也是完全可能的,而且結(jié)果應(yīng)當(dāng)與樣例的結(jié)果是相同的(當(dāng)然是在保證精度可以計算出結(jié)果的前提下):
0.569914189214915e770.056991418921491e780.005699141892149e790.000569914189214e80
帶著這個想法我分別拿著上面的數(shù)據(jù)去UVA toolkit和uDebug上試了試脸爱, UVA toolkit依舊能夠輸出“5 8”的結(jié)果來遇汞,但是uDebug告訴我我的輸入不合法……果真是我想多了么……
不過這個問題也好辦,還是看上面的數(shù)據(jù)簿废,忽略掉后面幾位精度丟失的問題的話空入,上面的幾個數(shù)完全可以通過“A *= 10, B -= 1”或者“A /= 10, B += 1”的操作來相互轉(zhuǎn)化。那么對于0 < A < 1的A的值族檬,我們就可以通過“A *= 10, B -= 1”的操作來使其滿足科學(xué)記數(shù)法的條件歪赢。
另外,在查表的時候還應(yīng)該注意精度的問題单料,15位有效數(shù)字對于double來說精度似乎也不夠埋凯,而且計算出所需要的整數(shù)值其實需要的精度也沒有那么高点楼,所以這里的精度就只用到了1e-4的程度。