昨天晚上久违地去打了次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
的填补以方便运算。
至于这个算法具体的优化过程不得而知,想来与现在的结论应该是大相径庭吧,只能留待日后有机会再研究了。