Visual Studio 2022 17.4.3 是否破坏了 std::round 函数?

5

(注意:只有当编译器开关/arch:AVX被设置时,我才会遇到这个问题。更多信息请见底部)

我的gtest单元测试已经做了7年了。

ASSERT_EQ(-3.0, std::round(-2.5f));  // (Note the 'f' suffix)

根据cpp-reference,std::round应该是向远离零的方向四舍五入,对吗?然而,在当前版本中,这个测试刚刚开始失败了。我错过了什么吗?我所做的就是将我的Visual Studio 2022更新到17.4.3。我的同事使用的是17.3.3,他没有这个问题。
编辑:我不知道问题是GTEST及其宏还是我的单元测试对相等性的假设。我在我的测试中加入了以下两行代码。
std::cerr << "std::round(-2.5) = " << std::round(-2.5) << std::endl;
std::cerr << "std::round(-2.5f) = " << std::round(-2.5f) << std::endl;

它们产生以下输出。第二个是错误的,不是吗?

std::round(-2.5) = -3
std::round(-2.5f) = -2

编辑 #2:如我上面所述,只有当我设置编译器标志/arch:AVX时才会出现这个问题。如果只是创建一个控制台应用程序而不设置标志,或者明确将其设置为/arch:IA32,问题就会消失。但问题随之而来:这是一个错误还是我不应该使用该选项?


3
如果这确实是一个 bug,我认为你应该向 Visual Studio 工程师报告,并且可以通过向他们提供 [mcve](可能不使用 gtest,而是直接使用 assert())来证明。 - PaulMcKenzie
2
@franji1,没有针对double返回doublestd::round重载。 - user17732522
1
17.4.x相当臭名昭著,但破坏round()将是一项相当了不起的壮举,而且没有其他人抱怨它。确保协处理器仍在使用预期的舍入模式运行。使用Debug> Windows> Registers,右键单击该窗口并选中SSE。确保MXCSR寄存器仍包含00001F80。 - Hans Passant
2
确实,在 MS STL 中最近进行了相对较大的更改,转而使用编译器内置函数。因此,这可能会导致新问题的出现并非那么不可能。请参见 https://github.com/microsoft/STL/commit/26bbe2ad50cd7003b8220cfec2bff16dbc032ca8,尽管他们在 https://github.com/microsoft/STL/issues/1234#issuecomment-682091126 中考虑了潜在的舍入模式问题。 - user17732522
2
似乎是最近引入的内在函数中,std::round(float)被转发到其中,但库的实现并没有这样做:https://godbolt.org/z/898eE1es9(我认为这是一个bug,但也不确定)。 - user17732522
显示剩余15条评论
1个回答

1

这是一个已知的漏洞,请查看开发者社区上的漏洞报告,它已经处于“待发布”状态。

为了完整性/独立性起见,在那里的最小示例是(godbolt):

int main()
{
    std::cout << "MSVC version: " << _MSC_FULL_VER << '\n';
    std::cout << "Round 0.5f: " << std::round(0.5f) << '\n';
    std::cout << "Round 0.5: " << std::round(0.5) << '\n';
}

使用AVX或AVX2编译。 例如,使用MSVC 19.33的正确输出为

MSVC version: 193331631
Round 0.5f: 1
Round 0.5: 1

在最新的MSVC 19.34输出中

MSVC version: 193431931
Round 0.5f: 0
Round 0.5: 1

1
他们已经关闭了我的开发者社区问题,支持那个问题。他们说在17.5中已经解决了。 - Joe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接