aba*_*ert 66
其实,这是不正确的3.5 % 0.1是0.1.您可以非常轻松地测试它:
>>> print(3.5 % 0.1)
0.1
>>> print(3.5 % 0.1 == 0.1)
False
Run Code Online (Sandbox Code Playgroud)
实际上,在大多数系统上,3.5 % 0.1是0.099999999999999811.但是,在某些版本的Python上,str(0.099999999999999811)是0.1:
>>> 3.5 % 0.1
0.099999999999999811
>>> repr(3.5 % 0.1)
'0.099999999999999811'
>>> str(3.5 % 0.1)
'0.1'
Run Code Online (Sandbox Code Playgroud)
现在,你可能想知道为什么3.5 % 0.1是0.099999999999999811不是0.0.这是因为通常的浮点舍入问题.如果你还没有读过"每个计算机科学家应该知道的关于浮点算术的内容",你应该 - 或者至少是维基百科关于这一特定问题的简短摘要.
请注意,3.5/0.1不是34,它是35.那么,3.5/0.1 * 0.1 + 3.5%0.1是3.5999999999999996,这是不甚至接近到3.5.这对于模数的定义来说非常重要,而且它在Python中是错误的,而且几乎与其他所有编程语言一样.
但是Python 3在那里得到了拯救.大多数知道的人都知道//你是如何在整数之间进行"整数除法"的,但是没有意识到你是如何在任何类型之间进行模数兼容除法的.3.5//0.1就是34.0这样3.5//0.1 * 0.1 + 3.5%0.1(至少在一个小的舍入误差范围内)3.5.这已经被移植到2.x,因此(取决于您的确切版本和平台)您可以依赖于此.而且,如果没有,你可以使用divmod(3.5, 0.1),它返回(在舍入误差内)(34.0, 0.09999999999999981)一直回到时间的迷雾中.当然你仍然期望这是(35.0, 0.0),(34.0, almost-0.1)但不是,但由于四舍五入错误,你不能这样做.
如果您正在寻找快速解决方案,请考虑使用以下Decimal类型:
>>> from decimal import Decimal
>>> Decimal('3.5') % Decimal('0.1')
Decimal('0.0')
>>> print(Decimal('3.5') % Decimal('0.1'))
0.0
>>> (Decimal(7)/2) % (Decimal(1)/10)
Decimal('0.0')
Run Code Online (Sandbox Code Playgroud)
这不是一个神奇的灵丹妙药 - 例如,只要操作的确切值在基数10中无法有限地表示,你仍然必须处理舍入误差 - 但是舍入误差与人类直觉预期的情况排列得更好有问题.(也有后发优势Decimal过度float的,你可以指定明确的精度,跟踪显著数字等,并且它实际上在所有的Python版本从2.4到3.3的相同,而有关细节float的同时改变了两次.这是只是它不完美,因为那是不可能的.)但是当你事先知道你的数字在10号基础上都可以完全表示,并且它们不需要比你配置的精度更多的数字时,它就会起作用.
Modulo为您提供了rest一个部门.3.5除以0.1你应该给你35剩下的0.但由于浮点数基于2的幂,数字并不准确,你会得到四舍五入的错误.
如果您需要精确划分十进制数,请使用十进制模块:
>>> from decimal import Decimal
>>> Decimal('3.5') / Decimal('0.1')
Decimal('35')
>>> Decimal('3.5') % Decimal('0.1')
Decimal('0.0')
Run Code Online (Sandbox Code Playgroud)
当我被抨击时,我的答案误导了整个故事:
0.1 略大于 0.1
>>> '%.50f' % 0.1
'0.10000000000000000555111512312578270211815834045410'
Run Code Online (Sandbox Code Playgroud)
如果你将浮动3.5除以这个数字,你几乎可以得到其余的0.1.
让我们从数字开始,0.11继续在两个1数字之间添加零,以使其更小,同时保持大于0.1.
>>> '%.10f' % (3.5 % 0.101)
'0.0660000000'
>>> '%.10f' % (3.5 % 0.1001)
'0.0966000000'
>>> '%.10f' % (3.5 % 0.10001)
'0.0996600000'
>>> '%.10f' % (3.5 % 0.100001)
'0.0999660000'
>>> '%.10f' % (3.5 % 0.1000001)
'0.0999966000'
>>> '%.10f' % (3.5 % 0.10000001)
'0.0999996600'
>>> '%.10f' % (3.5 % 0.100000001)
'0.0999999660'
>>> '%.10f' % (3.5 % 0.1000000001)
'0.0999999966'
>>> '%.10f' % (3.5 % 0.10000000001)
'0.0999999997'
>>> '%.10f' % (3.5 % 0.100000000001)
'0.1000000000'
Run Code Online (Sandbox Code Playgroud)
最后一行给出了我们最终达到的印象,0.1但更改格式字符串揭示了真实的本质:
>>> '%.20f' % (3.5 % 0.100000000001)
'0.09999999996600009156'
Run Code Online (Sandbox Code Playgroud)
python的默认浮点格式根本没有显示足够的精度以便3.5 % 0.1 = 0.1和3.5 % 0.1 = 35.0.它真的是3.5 % 0.100000... = 0.999999...和3.5 / 0.100000... = 34.999999.....在分割的情况下,你甚至可以得到确切的结果,因为它34.9999...是最终的四舍五入35.0.
有趣的事实:如果您使用的数字略小于0.1并执行相同的操作,您最终会得到一个略大于的数字0:
>>> 1.0 - 0.9
0.09999999999999998
>>> 35.0 % (1.0 - 0.9)
7.771561172376096e-15
>>> '%.20f' % (35.0 % (1.0 - 0.9))
'0.00000000000000777156'
Run Code Online (Sandbox Code Playgroud)
使用C++,您甚至可以显示除了3.5浮点数0.1不是35更小的东西.
#include <iostream>
#include <iomanip>
int main(int argc, char *argv[]) {
// double/float, rounding errors do not cancel out
std::cout << "double/float: " << std::setprecision(20) << 3.5 / 0.1f << std::endl;
// double/double, rounding errors cancel out
std::cout << "double/double: " << std::setprecision(20) << 3.5 / 0.1 << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在Python中3.5 / 0.1为您提供了确切的结果,35因为舍入错误相互抵消.它确实是3.5 / 0.100000... = 34.9999999....并且34.9999...到目前为止,你最终会完全结束35.C++程序很好地展示了这一点,因为你可以混合double和float并使用浮点数的精度.
| 归档时间: |
|
| 查看次数: |
37472 次 |
| 最近记录: |