昨天晚上久違地去打了次div2
一年沒打,掛得很慘
早上起來試着用python寫一遍唯一寫出來的a題
然后發現了一個奇怪的現象
代碼如下(為了方便觀察已經改過了,不是解題的代碼)
import sys
x=1
y=100000000
k=100000000
a=k*y+k-1
ans=a/1
print(sys.maxsize)
print(int(a))
print(int(ans))
結果如下:
9223372036854775807 10000000099999999 10000000100000000
輸出的第一行是int的最大值,是為了驗證異常不是由於溢出導致的。
看到第二個輸出,一個算是比較大的數字,第三個輸出應當是其除以1的結果。
用小學生的腦子想一想,任意一個數字除以1結果應當不變吧。
但輸出告訴我們,我不僅變,我還給你剛好+1。
但如果在這里使用整除的話,第二和第三個結果是一致的。
那么問題大約出在python的浮點數除法的算法上了。
如果將除數改為2,可以看到第三個輸出變為
5000000050000000
也就是說,在除法過程中依然出現了+1現象。
如果減小量級呢?
import sys x=1 y=100000000 k=100000000 a=k+k-1 ans=a/1print(sys.maxsize) print(int(a)) print(int(ans))
結果如下:
9223372036854775807 199999999 199999999
可以看到,+1現象消失了。
那么推測,+1現象的成因是在浮點運算中為了方便較大數字運算而引入的一個一般情況下可以忽略的填補量。
那么引入這個+1的臨界范圍是什么?
使用while循環,粗略地探究一下:
import sys x=1 y=100000000 k=100000000 a=k+k-1 ans=a/1; while a==ans: print(int(a)) a*=10 ans=a/1print(sys.maxsize) print(int(a)) print(int(ans))
結果是:
199999999 1999999990 19999999900 199999999000 1999999990000 19999999900000 199999999000000 1999999990000000 19999999900000000 199999999000000000 1999999990000000000 9223372036854775807 19999999900000000000 19999999900000002048
不對勁啊,為什么是在比int范圍還有大的時候才跳出循環,明明之前產生偏差的數值比范圍要小。
猜測,這個偏差的產生條件不只是數字的位數,還有其他的條件
觀察最開始的那個數據,以及1的特殊性,猜測這個+1的偏差可能和數據的末尾9的個數有關
那么選取一個較小的9結尾的數字開始循環
import sys
a=199999
ans=a/1
while a==ans:
print(a)
a=a*10+9
ans=a/1
print(sys.maxsize)
print(int(a))
print(int(ans))
結果是:
199999 1999999 19999999 199999999 1999999999 19999999999 199999999999 1999999999999 19999999999999 199999999999999 1999999999999999 9223372036854775807 19999999999999999 20000000000000000
可以看到,位數與最初那個有偏差數據一樣。
實驗到此結束,暫時的結論是,在被除數大到一定程度(暫定17位)且末尾有一定數量9時,在除法運算中會進行一個+1
的填補以方便運算。
至於這個算法具體的優化過程不得而知,想來與現在的結論應該是大相徑庭吧,只能留待日后有機會再研究了。