【问题标题】:Python abs() function failing on negative numberPython abs() 函数在负数上失败
【发布时间】:2021-01-08 17:34:09
【问题描述】:

我在 linux 上使用 python3.6 工作,遇到了 abs() 函数的一个非常明显的故障。我的变量x 最终成为一个非常大的负数(可能是-inf),但绝对值abs() 函数仍然返回一个 数,这应该是不可能的。我通过在 abs() 的输入中添加 0.1 来快速修复我的代码,但是....我误解了应该如何使用 abs() 吗?

$> x
-9223372036854775808

$> abs(x)
-9223372036854775808

$> np.abs(x)
-9223372036854775808

$> abs(x+.1)
9.223372036854776e+18

$> np.abs(x+.1)
9.223372036854776e+18

编辑:在下面解决,但归结为 xnumpy.int64 而不仅仅是 int,我不知道。

【问题讨论】:

  • 我无法在 MacOS High Sierra 上的 Python 3.6.3 中重现这一点。
  • 我也尝试使用x= -9223372036854775808 然后abs(x) 重现它并产生了积极的结果
  • 请指定您使用的 shell 和 Python 版本。这不会在 Python 3.8 或 2.7 中重现,无论是命令行执行程序还是 IDLE shell。
  • 在 Ubuntu 20.04 中使用 python 3.8.5 和 ipython 对我来说很好。
  • print(x, type(x)) 显示什么?

标签: python python-3.x numpy python-3.6 absolute-value


【解决方案1】:

您没想过要提及它(我从您使用 np.abs 的测试中推断出来),但重要的是 xnumpy.int64(或等效的有符号 64 位类型)。 two's complement 中的那个特定值没有正等值,所以 abs 只是再次产生相同的值(它可以引发异常,但 numpy 坚持低水平在这种情况下返回原始值的 C 行为)。

首先将其转换为真正的 Python int,例如abs(int(x)) 它会起作用的。


解释为什么会这样工作:

-9223372036854775808 的位模式是0x8000_0000_0000_0000(只设置了最高位,下划线是为了便于阅读)。二进制补码否定是通过翻转所有位然后加一个进位的算法处理的,因此转换将0x8000_0000_0000_0000 更改为0x7fff_ffff_ffff_ffff(所有位翻转),然后添加1,它携带整个字段长度(因为除了高位之外的每一位都已设置),再次产生0x8000_0000_0000_0000。相同的位模式实际上对应于等于9223372036854775808 的无符号 64 位数量的位模式,但鉴于它被解释为有符号,它继续被解释为最负值,而不是比最正值高一个int64 值(不能表示为 int64)。

【讨论】:

  • 这对我来说确实像一个 python 错误,不是很禅
  • @Chris_Rands:这不是 Python,而是numpy; Python abs 信任该类型的 __abs__ 方法来返回正确的值(它无法知道它真的是一个整数并且返回值在逻辑上是错误的)。并且numpy 比核心 Python 更“裸机,不惜一切代价实现性能”(根本不是那样);在这样的情况下检查每一个数学运算是否溢出,2**64 - 1 值不需要它,而一个 也许 需要它(繁重的数字运算代码有时 想要 沉默溢出),减慢速度以获得最小的利益(如果有的话)。
  • @paradox:不是反对者之一,但我明白了; OP 忽略了告诉我们 xnumpy 类型。虽然我的心理调试能力非常棒,在这种情况下,我几乎 100% 确定它们是在目标上(如果我不是,我会限制自己发表评论),省略关键细节的问题(比如图书馆使用和变量的定义)没有提供minimal reproducible example,并且可以说是“坏的”。
  • @ShadowRanger 是的。我同意你的观点,OP 应该做得更好,为我们提供正确的上下文。
  • 非常感谢您的回答!抱歉,我什至没有意识到 xnumpy.int64 而不仅仅是 int。我将编辑原始帖子以反映这一点
猜你喜欢
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多