带有vs.而没有额外变量的奇怪的浮点行为,为什么呢? [英] Bizarre floating-point behavior with vs. without extra variables, why?

查看:64
本文介绍了带有vs.而没有额外变量的奇怪的浮点行为,为什么呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在VC ++ 2013(32位,无优化)中运行以下代码时:

When I run the following code in VC++ 2013 (32-bit, no optimizations):

#include <cmath>
#include <iostream>
#include <limits>

double mulpow10(double const value, int const pow10)
{
    static double const table[] =
    {
        1E+000, 1E+001, 1E+002, 1E+003, 1E+004, 1E+005, 1E+006, 1E+007,
        1E+008, 1E+009, 1E+010, 1E+011, 1E+012, 1E+013, 1E+014, 1E+015,
        1E+016, 1E+017, 1E+018, 1E+019,
    };
    return pow10 < 0 ? value / table[-pow10] : value * table[+pow10];
}

int main(void)
{
    double d = 9710908999.008999;
    int j_max = std::numeric_limits<double>::max_digits10;
    while (j_max > 0 && (
        static_cast<double>(
            static_cast<unsigned long long>(
                mulpow10(d, j_max))) != mulpow10(d, j_max)))
    {
        --j_max;
    }
    double x = std::floor(d * 1.0E9);
    unsigned long long y1 = x;
    unsigned long long y2 = std::floor(d * 1.0E9);
    std::cout
        << "x == " << x << std::endl
        << "y1 == " << y1 << std::endl
        << "y2 == " << y2 << std::endl;
}

我知道

x  == 9.7109089990089994e+018
y1 == 9710908999008999424
y2 == 9223372036854775808

在调试器中.

我快疯了.有人可以向我解释一下 y1 y2 到底有何不同值吗?

I'm mindblown. Can someone please explain to me how the heck y1 and y2 have different values?

这似乎只发生在/Arch:SSE2 /Arch:AVX 下,而不是/Arch:IA32 /拱门:SSE .

This only seems to happen under /Arch:SSE2 or /Arch:AVX, not /Arch:IA32 or /Arch:SSE.

推荐答案

您正在将超出范围的 double 值转换为 unsigned long long .这在标准C ++中是不允许的,并且Visual C ++在SSE2模式下似乎对确实的对待很差:它在FPU堆栈上留下了一个数字,最终使它溢出并使使用FPU的更高版本的代码失败.真的很有趣.

You are converting out-of-range double values to unsigned long long. This is not allowed in standard C++, and Visual C++ appears to treat it really badly in SSE2 mode: it leaves a number on the FPU stack, eventually overflowing it and making later code that uses the FPU fail in really interesting ways.

减少的样本是

double d = 1E20;
unsigned long long ull[] = { d, d, d, d, d, d, d, d };
if (floor(d) != floor(d)) abort();

如果 ull 具有八个或更多元素,则中止,但如果具有七个或更多元素,则通过.

This aborts if ull has eight or more elements, but passes if it has up to seven.

解决方案是不要将浮点值转换为整数类型,除非您知道该值在范围内.

The solution is not to convert floating point values to an integer type unless you know that the value is in range.

4.9浮点整数转换[conv.fpint]

浮点类型的prvalue可以转换为整数类型的prvalue.转换被截断;即,小数部分被丢弃.如果无法在目标类型中表示截断的值,则该行为是不确定的.[注意:如果目标类型是 bool ,请参见4.12.-尾注]

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type. [ Note: If the destination type is bool, see 4.12. -- end note ]

转换为无符号类型时超出范围的换行规则仅适用于该值已经是某种整数类型的情况.

The rule that out-of-range values wrap when converted to an unsigned type only applies if the value as already of some integer type.

尽管如此,这似乎不是故意的,因此即使标准允许这种行为,仍然值得将其报告为错误.

For whatever it's worth, though, this doesn't seem like it's intentional, so even though the standard permits this behaviour, it may still be worth reporting this as a bug.

这篇关于带有vs.而没有额外变量的奇怪的浮点行为,为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆