铸造和分配真的会去除浮动的任何额外精度吗
Does casting and assignment really strip away any extra precision of floats?
我正在阅读新的C++常见问题解答,我发现即使x == y
用于double x, y;
,也可能用于:
std::cos(x) == std::cos(y)
以评估为CCD_ 3。这是因为机器可以具有支持扩展精度的处理器,因此==
的一部分是64位数字,而另一部分是80位数字。
然而,下一个例子似乎是不正确的:
void foo(double x, double y)
{
double cos_x = cos(x);
double cos_y = cos(y);
// the behavior might depend on what's in here
if (cos_x != cos_y) {
std::cout << "Huh?!?n"; // You might end up here when x == y!!
}
}
据我在en.cppreference.com上读到的内容:
铸造和赋值去掉了任何无关的范围和精度:这为存储扩展精度值的操作建模FPU寄存器到标准大小的存储器位置。
因此,分配:
double cos_x = cos(x);
double cos_y = cos(y);
应该去掉任何额外的精度,使程序完全可预测。
那么,谁是对的呢?C++常见问题解答或en.cppreference.com?
ISOCPP常见问题解答和cppreference都不是权威来源。cpprreference本质上相当于wikipedia:它包含很好的信息,但任何人都可以添加任何没有来源的内容——你必须谨慎阅读。以下三种说法正确吗:
你抓到了吗?您的特定安装可能会将其中一个cos()调用的结果存储到RAM中,在过程中截断它,然后稍后将截断的值与第二个cos(()调用未截断的结果进行比较。根据许多细节,这两个值可能不相等。
这是因为机器可以具有支持扩展精度的处理器,因此
==
的一部分是64位数字,而另一部分是80位数字。Cast和赋值去掉了任何无关的范围和精度:这模拟了将扩展精度FPU寄存器中的值存储到标准大小的内存位置的操作。
也许吧。它取决于平台、编译器、编译器选项或任何数量的东西。实际上,上述语句仅适用于32位模式下的GCC,默认为传统x87 FPU(内部所有内容都是80位),存储在内存中时四舍五入为64位。64位使用SSE,因此双临时总是64位。可以使用mfpmath=sse
和-msse2
强制SSE。无论哪种方式,组件都可能看起来像这样:
movsd QWORD PTR [rsp+8], xmm1
call cos
movsd xmm1, QWORD PTR [rsp+8]
movsd QWORD PTR [rsp], xmm0
movapd xmm0, xmm1
call cos
movsd xmm2, QWORD PTR [rsp]
ucomisd xmm2, xmm0
正如您所看到的,这里没有任何类型的截断,也没有使用80位寄存器。
我希望赋值或强制转换能去掉额外的精度。我曾与"聪明"的编译器合作过,但这并没有发生。很多都是这样,但如果你想要真正独立于机器的代码,你需要做额外的工作。
通过用"volatile"关键字声明变量,可以强制编译器始终使用具有预期精度的内存中的值。
有些编译器在寄存器中而不是在堆栈中传递参数。对于这些编译器,x或y可能具有意外的额外精度。为了完全安全,你可以做
volatile double db_x = x, db_y = y;
volatile double cos_x = cos(db_x), cos_y = cos(db_y);
if (cos_x != cos_y)...
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 正在将csv文件读取为双精度矢量
- 如何在不产生任何垃圾的情况下获得C中的像素
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 如何在C++中的同一函数中使用字符串和双精度
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- C++映射有2个键,这样任何1个键都可以用来获取值
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- RtlCaptureStackBackTrace未捕获任何帧
- f 是指向函数的指针,该函数采用 int,并返回指向不带任何内容并返回双精度的函数的指针
- 铸造和分配真的会去除浮动的任何额外精度吗
- 为什么从浮点返回方法返回双精度不会在 c++ 中导致任何错误/警告
- 用浮点任意精度C++库改造现有代码,任何成功的机会
- 如何在64位(而不是任何80位寄存器)中强制所有双精度