Python 对浮点数取模[重复]

2025-02-11 09:50:00
admin
原创
58
摘要:问题描述:有人能解释一下 Python 中模数运算符的工作原理吗?我不明白为什么3.5 % 0.1 = 0.1。解决方案 1:事实上,事实并非如此3.5 % 0.1。0.1你可以很容易地测试这一点:>>> print(3.5 % 0.1) 0.1 >>> print(3.5...

问题描述:

有人能解释一下 Python 中模数运算符的工作原理吗?我不明白为什么3.5 % 0.1 = 0.1


解决方案 1:

事实上,事实并非如此3.5 % 0.10.1你可以很容易地测试这一点:

>>> print(3.5 % 0.1)
0.1
>>> print(3.5 % 0.1 == 0.1)
False

实际上,在大多数系统上,3.5 % 0.10.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'

现在,您可能想知道为什么3.5 % 0.10.099999999999999811而不是0.0。这是因为常见的浮点舍入问题。如果您还没有阅读《每个计算机科学家都应该知道的浮点运算》,您应该阅读一下——或者至少阅读一下关于这个特定问题的简短维基百科摘要。

还要注意的3.5/0.1是 不是34,而是35。所以3.5/0.1 * 0.1 + 3.5%0.1是,3.5999999999999996相差甚远。这几乎是模数定义的基础,但在 Python 以及几乎所有其他编程语言中,这都是错误的。3.5

但是 Python 3 可以解决这个问题。大多数知道 的人都//知道它是如何在整数之间进行“整数除法”,但没有意识到它是如何在任意类型之间进行模数兼容除法。3.5//0.134.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')

这不是万能的灵丹妙药——例如,当操作的精确值不能以十进制有限表示时,您仍然必须处理舍入误差——但舍入误差与人类直觉认为有问题的情况更吻合。(还有优势,您可以指定明确的精度、跟踪有效数字等,并且它实际上在从 2.4 到 3.3 的所有 Python 版本中都是相同的,而有关的细节在同一时间更改了两次。只是它并不Decimal完美,因为那是不可能的。)但是,当您事先知道您的数字都可以以十进制精确表示,并且它们不需要比您配置的精度更多的数字时,它就会起作用。float`float`

解决方案 2:

取模运算rest后,除以,结果为。3.5除以 ,0.1结果为。但由于浮点数基于 2 的幂,因此数字并不精确,并且会产生舍入误差。35`0`

如果您需要精确地对十进制数进行除法,请使用十进制模块:

>>> from decimal import Decimal
>>> Decimal('3.5') / Decimal('0.1')
Decimal('35')
>>> Decimal('3.5') % Decimal('0.1')
Decimal('0.0')

当我被批评我的回答具有误导性时,下面是整个故事:

Python 浮点数0.1略大于十分之一:

>>> '%.50f' % 0.1
'0.10000000000000000555111512312578270211815834045410'

如果将浮点数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'

最后一行给人的印象是我们终于达到了目的,0.1但改变格式字符串却揭示了真正的本质:

>>> '%.20f' % (3.5 % 0.100000000001)
'0.09999999996600009156'

python 默认的浮点格式根本无法显示足够的精度,因此和3.5 % 0.1 = 0.13.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'

使用 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;
}

http://ideone.com/fTNVho

在 Python 中,3.5 / 0.1会给出 的精确结果,35因为舍入误差相互抵消。它确实是3.5 / 0.100000... = 34.9999999...。并且34.9999...最终非常长,因此您最终得到的正好是35。C++ 程序很好地展示了这一点,因为您可以混合使用 double 和 float 并使用浮点数的精度。

解决方案 3:

这与浮点运算的不精确性有关。3.5 % 0.1我明白了0.099999999999999811,所以 Python 认为 0.1 最多能被 3.5 整除 34 次,剩下 0.0999999999999999811。我不确定到底用什么算法来实现这个结果,但这就是要点。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用