C 和 Python - 模数(%)运算的不同行为[重复]

2025-03-05 09:14:00
admin
原创
63
摘要:问题描述:我发现相同的 mod 运算根据所使用的语言产生不同的结果。在 Python 中:-1 % 10 产生9在 C 语言中它产生-1!哪一个是正确的模数?如何使 C 中的 mod 运算与 Python 中的相同?解决方案 1:两种变体都是正确的,但是在数学(尤其是数论)中,Python 的模数是最常用的。...

问题描述:

我发现相同的 mod 运算根据所使用的语言产生不同的结果。

在 Python 中:

-1 % 10

产生9

在 C 语言中它产生-1

  1. 哪一个是正确的模数?

  2. 如何使 C 中的 mod 运算与 Python 中的相同?


解决方案 1:

  1. 两种变体都是正确的,但是在数学(尤其是数论)中,Python 的模数是最常用的。

  2. 在 C 中,您可以获得((n % M) + M) % M与 Python 相同的结果。例如((-1 % 10) + 10) % 10。请注意,它仍然适用于正整数:((17 % 10) + 10) % 10 == 17 % 10,以及 C 实现的两种变体(正余数或负余数)。

解决方案 2:

Python 具有“真正的”模运算,而 C 具有余数运算。

它与负整数除法的处理方式有直接关系,即向 0 或负无穷方向舍入。Python 向负无穷方向舍入,而 C(99) 向 0 方向舍入,但在这两种语言中(n/m)*m + n%m == n,% 运算符都必须在正确的方向上进行补偿。

Ada 更加明确,具有 和 两种mod功能rem

解决方案 3:

在 C89/90 中,除法运算符和余数运算符对负数的操作的行为是实现定义的,这意味着根据实现,您可以获得任一行为。 只需要求运算符彼此一致:froma / b = qa % b = rfollowing a = b * q + r。 如果行为严重依赖于结果,请在代码中使用静态断言来检查行为。

在 C99 中您观察到的行为已成为标准。

事实上,这两种行为都有一定的逻辑。Python 的行为实现了真正的模运算。您观察到的 C 行为与向 0 舍入一致(这也是 Fortran 行为)。

在 C 中,倾向于向 0 舍入的原因之一是,期望 的结果与-a / b相同是很自然的-(a / b)。在真模数行为的情况下,-1 % 10的计算结果为 9,这意味着-1 / 10必须为 -1。这可能被视为相当不自然,因为-(1 / 10)是 0。

解决方案 4:

两个答案都是正确的,因为-1 modulo 10与 相同9 modulo 10

r = (a mod m)
a = n*q + r

您可以确定|r| < |n|,但不能确定 的值r是多少。答案有两个,否定和肯定。


在 C89 中,虽然答案始终是正确的,但模运算的确切值(他们称之为余数)是未定义的,这意味着它可能是负数结果,也可能是正数结果。在 C99 中,结果是定义的。

但是,如果您想要肯定的答案,那么如果发现答案是否定的,您只需加 10 即可。

为了使模运算符在所有语言上发挥相同的作用,只需记住:

n mod M == (n + M) mod M

总体而言:

n mod M == (n + X * M) mod M

解决方案 5:

执行欧几里得除法a = b*q + r,就像将分数a/b四舍五入为整数商q,然后计算余数r

您看到的不同结果取决于用于对商进行四舍五入的惯例......

如果向零舍入(截断),则会得到围绕零的对称性,就像在 C 中一样:

truncate(7/3) = 2
7 = 3*2 + 1

truncate(-7/3) = -2
-7 = 3* -2 - 1

truncate(7/-3) = -2
7 = -3* -2 + 1

如果向负无穷大(向下舍入)舍入,则会得到类似 Python 中的余数:

floor(7/3) = 2
7 = 3*2 + 1

floor(-7/3) = -3
-7 = 3* -3 + 2

floor(7/-3) = -3
7 = -3* -3 - 2

如果你四舍五入到最接近的整数(与你想要的任何数字相等,四舍五入到偶数,或者远离零),你会得到一个中心模数:

round(7/3) = 2
7 = 3*2 + 1

round(8/3) = 3
8 = 3*3 - 1

round(-7/3) = -2
-7 = 3* -2 - 1

round(7/-3) = -2
7 = -3* -2 + 1

您可以尝试实现自己的模数,并向正无穷大(ceil)舍入,您会发明一种相当非常规的模数,但它仍然是一种模数......

解决方案 6:

从 python 3.7 开始您还可以使用.remainder()内置math模块。

Python 3.7.0a0 (heads/master:f34c685020, May  8 2017, 15:35:30)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> math.remainder(-1, 10)
-1.0

来自文档:

返回 x 对 y 的 IEEE 754 样式余数。对于有限 x 和有限非零 y,这是差值x - n*y,其中 n 是最接近商的精确值的整数x / y。如果x / y恰好位于两个连续整数的中间,则将最接近的偶数用作n。因此余数r = remainder(x, y)始终满足abs(r) <= 0.5 * abs(y)

特殊情况遵循 IEEE 754:特别是,remainder(x, math.inf)对于任何有限的 x,都是 x,并且remainder(x, 0)对于remainder(math.inf, x)任何非 NaN x,都会引发 ValueError。如果余数运算的结果为零,则该零将具有与 x 相同的符号。

在使用 IEEE 754 二进制浮点的平台上,此运算的结果始终可以精确表示:不会引入舍入误差。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3998  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2749  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   85  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   96  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   83  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用