【问题标题】:Multiplication of two integers in C++C++中两个整数的乘法
【发布时间】:2015-10-18 05:04:07
【问题描述】:

我有一个非常基本的问题,但我不确定我是否理解这个概念。假设我们有:

int a = 1000000;
int b = 1000000;
long long c = a * b;

当我运行它时,c 显示负值,所以我也将 ab 更改为 long long,然后一切都很好。那么,当ab 的值在int 的范围内并且它们的产品分配给c(即long long)时,为什么我必须更改它们?

我正在使用 C/C++

【问题讨论】:

  • 整数在乘法之前很久没有提升,它们仍然是整数和乘积。然后将产品浇铸到长长,但为时已晚,溢流已经袭来。拥有 a 或 b long long 中的一个应该也可以,因为另一个会被提升。
  • 您应该标记您正在使用的编程语言,因为不同的语言可能会引入不同的行为;)
  • 根据您使用的 C 的机器和版本,'int' 的大小也可能会发生变化。
  • long long c = ((long long)a*(long long)b);
  • 这是我之前的问题之一的重复stackoverflow.com/questions/29579112/…

标签: c++ int range long-integer


【解决方案1】:

ints 在乘法之前不会提升为 long long,它们仍然是 ints 和乘积。然后将产品转换为long long,但为时已晚,溢出来了。

拥有ab long long 之一应该也可以,因为另一个会被提升。

【讨论】:

    【解决方案2】:

    对于算术运算符,结果的类型不取决于您将结果分配给什么,而是取决于操作数的类型。对于算术运算符,usual arithmetic conversions 在操作数上执行。这用于将操作数转换为通用类型,这意味着对于小于 unsigned/signed int 的类型,如果值适合,则将它们提升为 unsigned/signed int,在这种情况下,它们都已经是 int,因此不需要转换。有关原因的详细信息,请参阅Why must a short be converted to an int before arithmetic operations in C and C++?

    我们现在的行为是未定义的,因为有符号整数溢出是未定义的行为,这在草案 C++ 标准部分 5 [Expr] 中有介绍:

    如果在计算表达式期间,结果未在数学上定义或不在 其类型的可表示值,行为是未定义的。 [注意:大多数现有的 C++ 实现 忽略整数溢出。除以零的处理,使用零除数形成余数,以及所有 浮点异常因机器而异,通常可以通过库函数进行调整。 ——尾注]

    现在我们有清理程序来捕获这些类型的未定义行为,并且将 -fsanitize=undefined 与 clang 和 gcc 一起使用将在运行时捕获此错误,并出现以下错误 (see it live):

    运行时错误:有符号整数溢出:1000000 * 1000000 不能 以“int”类型表示

    供参考部分5.6 [expr.mul] 说:

    [...]通常的算术转换是在操作数上执行的 并确定结果的类型。

    5 部分说:

    否则,应在两个操作数上执行积分提升 (4.5)。61 然后以下 规则应应用于提升的操作数

    • 如果两个操作数的类型相同,则无需进一步转换。

    【讨论】:

      【解决方案3】:

      这有点荒谬,因为汇编指令总是计算

      int * int -> 64 位长

      因此,如果您查看机器代码,您会看到: 模拟 将 64 位存储到 eax edx 然后 cdq 将 eax 的位符号放入 edx (从而丢失完整的 64 位结果) 然后将eax edx存入64位变量

      如果在乘法之前将 32 位值转换为 64 位,则会无缘无故地调用 64 位乘法函数

      (我查过:代码优化时不是这样)

      【讨论】:

      • 我同意 100%。我在 1992 年的第一份工作中了解了整数提升规则,但 C/C++ 的这种行为有时仍然让我感到困惑。 FWIW,ARM 汇编程序的行为类似于您描述的 Intel 汇编行为。当目标是 64 位时,乘以 2 个 32 位操作数可以正常工作。破坏数学的只是语言规则。
      猜你喜欢
      • 1970-01-01
      • 2020-06-12
      • 2022-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多