【问题标题】:Different behavior of double and int64_t conversion on new Apple silicon (arm64) vs. x86_64新 Apple 芯片 (arm64) 与 x86_64 上 double 和 int64_t 转换的不同行为
【发布时间】:2021-12-07 10:47:32
【问题描述】:

环境:码头工人。 arm64 debian 中的 gcc10。 x86_64 debian 中的 gcc7。

#include <cstdio>
#include <limits>
#include <cstdint>

int main(int args, char *argv[]) {
        double d = std::numeric_limits<int64_t>::max();
        int64_t t = static_cast<int64_t>(d);
        printf("%lld\n", t);
        return 0;
}

输出:

  • arm64: 9223372036854775807
  • x86_64:-9223372036854775808

谁能帮我理解为什么会有差异?

【问题讨论】:

  • 您的 int64_t 溢出。疯狂猜测:std::numeric_limits&lt;int64_t&gt;::max() 无法正确表示为 double 并四舍五入到一个整数,转换为 int64 然后溢出。您应该打印出 d 包含的内容。
  • 当然剩下的一个问题是,为什么行为会有所不同——是在 CPU 之间还是在 GCC 版本之间?只有上帝会告诉你。
  • 在 x86-64 上溢出的 FP->int 转换产生“整数不定”值,MSB 设置,所有其他清除。 ARM64 是不同的(可能是饱和的),或者你启用了优化和常量传播删除了实际的运行时转换。
  • stackoverflow.com/q/25857843/1716339 -- 这里部分回答了,因为结果是实现定义的。

标签: c++ x86-64 arm64 floating-point-conversion


【解决方案1】:

答案是 ARM 体系结构在转换中溢出的不同行为(在本例中为 int64_t)。它记录在这里(对于 ARMv7):https://developer.arm.com/documentation/ddi0403/d/Application-Level-Architecture/Application-Level-Programmers--Model/The-optional-Floating-point-extension/Floating-point-data-types-and-arithmetic?lang=en

TL:DR:在 ARM 上使用最大可表示值(9223372036854775807 用于 int64_t)。 (正如@PeterCordes 猜测的那样)

编辑: 对于 x86 / x64,溢出将导致只有 MSB 集的整数(在 int64_t 的情况下等于 -9223372036854775808)。

【讨论】:

  • 该链接适用于 ARMv7,但在 ARMv8 / ARM64 上是相同的。
  • 您在答案中遗漏的其他难题(仅在 cmets 中提到)是 double d = ... 向上取整,因为它不能准确表示那么大的整数。这就是转换完全溢出的原因。而在 x86 上,行为是产生一个设置了 MSB 的整数,其余的很清楚。 (英特尔称之为“整数不定”值:felixcloutier.com/x86/cvtsd2si
  • @PeterCordes 我忽略了所有这些,因为它已经在 cmets 中提到(包括您的评论);-) 也许我应该编辑答案?
  • 在 Stack Overflow 上,答案应该完全回答问题。不要假设未来的读者在得到您的答案之前会阅读任何 cmets(或其他答案)。版主甚至可能会出现并移动 cmets 进行聊天。您当然可以提及 cmets,例如“正如@Raildex 在 cmets 中提到的那样”,如果这不会使您的答案过于混乱的话。 (如果这是您自己想到的事情,就可以省略归因,例如该主题中大多数知识渊博的人都知道的事情,尤其是如果这会使您的答案陷入困境。)
猜你喜欢
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
  • 2021-04-10
  • 2020-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
相关资源
最近更新 更多