当前位置: 首页 > 知识库问答 >
问题:

Python选择舍入到负无穷大的数学原因是什么?

公孙联
2023-03-14

我知道Python//会趋向于负无穷大,而C/会截断,趋向于0。

到目前为止,我知道的是:

-12 / 10  = -1 - 2  // c++
-12 // 10 = -2 + 8  # python

12 / -10  = -1 + 2  // c++
12 // -10 = -2 - 8  # python

12 / 10  = 1 + 2  //both
12 // 10 = 1 + 2 

-12 / -10 = 1 - 2  //both
          = 2 + 8

C++: 
1. m%(-n) == m%n
2. -m%n == -(m%n)
3. (m/n)*n + m%n == m

python:
1. m%(-n) == -8 == -(-m%n)
2. (m//n)*n + m%n == m

但是为什么Python选择向负无穷大进位呢?我没有找到任何资源来解释这一点,只是找到并听到人们含糊其辞地说:“出于数学原因”。

例如,在为什么-1/2在C中计算为0,但在Python中为-1?中:

抽象地处理这些事情的人倾向于认为朝着负无穷大的方向移动更有意义(这意味着它与数学中定义的模函数兼容,而不是%具有某种有趣的含义)。

但是我没有看到C的/与模函数不兼容。在C语言中,(m/n)*n m%n==m也适用。

那么Python选择向负无穷舍入的(数学)原因是什么呢?

共有3个答案

齐涛
2023-03-14

“出于数学原因”

考虑这个问题(在电子游戏中足够常见),你有一个X坐标,它可以是负的,并且要把它转换成一个瓦片坐标(假设16x16瓦片)和一个平铺内的偏移量。

Python的%直接为您提供偏移量,/直接为您提供磁贴:

>>> -35 // 16 # If we move 35 pixels left of the origin...
-3
>>> -35 % 16 # then we are 13 pixels from the left edge of a tile in row -3.
13

(并且divmod同时为您提供这两个选项。)

程天佑
2023-03-14

虽然我不能提供为什么/如何选择舍入模式的正式定义,但是当你认为%不是完全正确的时候,引用关于与%运算符兼容性的引用是有意义的同样的事情在C和Python中。

在C语言中,它是余数运算符,而在Python中,它是模运算符——而且,当两个操作数有不同的符号时,它们不一定是同样的事情。在回答“mod”和“余数”之间的区别时,对这些运算符之间的区别有一些很好的解释?

现在,考虑到这种差异,整数除法的舍入(截断)模式必须与两种语言中的相同,以确保引用的关系(m/n)*n m%n==m保持有效。

下面是两个简短的程序,它们在实际中演示了这一点(请原谅我的Python代码有些幼稚——我是该语言的初学者):

C:

#include <iostream>

int main()
{
    int dividend, divisor, quotient, remainder, check;
    std::cout << "Enter Dividend: ";                        // -27
    std::cin >> dividend;
    std::cout << "Enter Divisor: ";                         // 4
    std::cin >> divisor;

    quotient = dividend / divisor;
    std::cout << "Quotient = " << quotient << std::endl;    // -6
    remainder = dividend % divisor;
    std::cout << "Remainder = " << remainder << std::endl;  // -3

    check = quotient * divisor + remainder;
    std::cout << "Check = " << check << std::endl;          // 27
    return 0;
}

Python:

print("Enter Dividend: ")             # -27
dividend = int(input())
print("Enter Divisor: ")              # 4
divisor = int(input())
quotient = dividend // divisor;
print("Quotient = " + str(quotient))  # -7
modulus = dividend % divisor;
print("Remainder = " + str(modulus))  # 1
check = quotient * divisor + modulus; # -27
print("Check = " + str(check))

请注意,对于不同符号(-27和4)的给定输入,不同语言的商和余数/模都不同,但恢复的检查值在这两种情况下都是正确的。

农英杰
2023-03-14

但是为什么Python//选择舍入到负无穷大?

我不确定最初做出这一选择的原因是否在任何地方都有记录(尽管据我所知,它可以在某个地方的一些PIP中详细解释),但我们肯定可以找到各种理由来解释它的意义。

一个原因很简单,四舍五入为负(或正!)无穷大意味着所有数字都以相同的方式舍入,而向零舍入则使零变得特殊。数学上的说法是,向下舍入−∞是平移不变量,即它满足等式:

round\u down(x k)==round\u down(x)k

对于所有实数x和所有整数k。四舍五入到零不会,因为,例如:

四舍五入到零(0.5-1)!=四舍五入到零(0.5)-1

当然,也存在其他参数,例如基于与%运算符(行为)的兼容性(我们希望如何)引用的参数——下面有更多信息。

事实上,我想说这里真正的问题是为什么Python的int()函数没有被定义为将浮点参数舍入到负无穷大,这样m//n就等于int(m/n)。(我怀疑是“历史原因”。)话说回来,这没什么大不了的,因为Python至少有满足m/n==math.floor(m/n)的math.floor()

但是我没有看到C的/与模函数不兼容。在C语言中,(m/n)*n m%n==m也适用。

是的,但是在将/四舍五入归零的同时保留该标识需要以一种笨拙的方式为负数定义%。特别是,我们失去了Python的%的以下两个有用的数学属性:

  1. 0

这些属性很有用,因为%的主要用途之一是将一个数字m包装到一个有限的长度范围n

例如,假设我们正在尝试计算方向:假设航向是我们当前的罗盘航向,以度为单位(从正北顺时针计算,以0为单位)

heading = (heading + angle) % 360

这在所有情况下都会起作用。

然而,如果我们试图在C中使用这个公式,它有不同的舍入规则和相应的不同的%运算符,我们会发现环绕并不总是像预期的那样工作!例如,如果我们开始面向西北(航向=315)并顺时针旋转90°(角度=90),我们最终确实会面向东北(航向=45)。但是,如果尝试逆时针旋转90°(角=-90),使用C的%运算符,我们不会像预期的那样回到标题=315,而是在标题=-45

为了使用C%运算符获得正确的环绕行为,我们需要将公式写成以下内容:

heading = (heading + angle) % 360;
if (heading < 0) heading += 360;

或作为:

heading = ((heading + angle) % 360) + 360) % 360;

(更简单的公式标题=(标题角度360)%360只有在我们总是能保证标题角度的情况下才会起作用

这是为除法使用非平移不变舍入规则,并因此使用非平移不变的%运算符而付出的代价。

 类似资料:
  • 我知道Python向负无穷大舍入,而在C中,它正在截断,向0舍入。 到目前为止,我知道的是: 但是为什么Python选择向负无穷大进位呢?我没有找到任何资源来解释这一点,只是找到并听到人们含糊其辞地说:“出于数学原因”。 例如,为什么C中的-1/2计算为0,而Python中的-1 抽象地处理这些事情的人倾向于认为朝着负无穷大前进更有意义(这意味着它与数学中定义的模函数相兼容,而不是%具有某种有趣的

  • 我明白了为什么C中的-1/2计算为0,而Python中的-1?在Python中表示整数除法向无穷大舍入,即,应用于结果。 我原以为也会像那样,但实际上我得到了,这在我心目中应该是。 所以问题是:为什么和函数之间的规则不一致?有什么合理的解释吗?

  • 问题内容: 我们如何在代码中使用它们,什么会导致NaN(不是数字)? 问题答案: 如果您想了解有关Java中浮点数的更多信息,这可能是一个很好的参考。 正无穷大是一个正数,以至于无法正常表示。负无穷大是一个负数,以至于无法正常表示。NaN的意思是“不是数字”,它是由数学运算产生的,该数学运算不会产生数字,例如将0除以0。 在Java中,Double和Float类都具有代表三种情况的常量。它们是PO

  • 问题内容: 我看过一些D3代码,它们带有类似这样的模式,用于附加元素: 我真的不明白这个片段。为什么选择null?我对D3的理解方式是,如果要添加圆,则应为: 同样,如果要追加HTML段落,则应该为: 类也是如此:如果将元素添加到类中foo,则应该为。 但是, 确实有效!元素被追加。那么,这是什么意思null呢?我在这里想念什么? 注意:这是一个自我回答的问题,试图提供一个针对该主题的“规范”问答

  • 本文向大家介绍为什么选择茉莉而不是开玩笑是什么原因?,包括了为什么选择茉莉而不是开玩笑是什么原因?的使用技巧和注意事项,需要的朋友参考一下 没有充分的理由选择茉莉而不是开玩笑。两者都是优秀的库,已经存在了一段时间,并且以一种自以为是的方式来处理非常相似的事情。笑话是建立在茉莉花之上的。 选择茉莉而不是开玩笑的原因之一是它更快。(https://github.com/facebook/jest/is

  • 问题内容: 根据Wikipedia的说法,在四舍五入一个负数时,您对绝对数进行了四舍五入。因此,根据这种推理,-3.5将四舍五入为-4。但是当我使用java.lang.Math.round(-3.5)时返回-3。有人可以解释一下吗? 问题答案: 根据javadoc 返回最接近参数的long。通过将结果加1/2,将结果取底,并将结果强制转换为long类型,将结果舍入为整数。换句话说,结果等于表达式的