为什么std::abs输出在MSVC2015上不正确

why std::abs output is incorrect on MSVC2015

本文关键字:MSVC2015 不正确 输出 std abs 为什么      更新时间:2023-10-16

我有不正确的结果从std::abs与MSVC和GCC

#include <cmath>
#include <iostream>
#include <complex>
int main()
{
  std::cerr << std::sqrt((-6.)*(-6.) + 288.*288.) << "n";
  std::cerr << std::abs( std::complex<float>(-6, 288) ) << std::endl;
  return 0L;
}

以上代码在vc++ (MSVS 2015 CE与更新)和gcc 4.9.2上产生不同的结果

与MSVC

288.062
288.063
与GCC

288.062
288.062

现在实际的结果是288.062,这在gcc上使用std::abs和std::sqrt是正确的。但是当使用std::sqrt和std::abs时,msvc有不同的结果,这可能是msvc2015中的一个bug。

但是看xcomplex的代码,我不理解_Fabs()的实现。有人能帮我理解这段具体的代码,并分析一下代码是如何以这样的错误结束的吗?

"现在实际结果是288.062[…]" -实际结果是288.06249...,或类似的东西,不能用floatdouble精确地表示。

两个编译器实际上返回相同的值,您可以通过打印更多的数字来检查:

double re = -6, im = 288;
std::cout << "sqrt: " << 'n'
          << std::setprecision(6) << std::sqrt(re * re + im * im) << 'n'
          << std::setprecision(30) << std::sqrt(re * re + im * im) << 'n';
std::cout << "abs:  " << 'n'
          << std::setprecision(6) << std::abs(std::complex<float>(im, re)) << 'n'
          << std::setprecision(30) << std::abs(std::complex<float>(im, re)) << 'n';

输出(使用VC 19.0和GCC 4.9.3):

sqrt: 
288.062
288.062493219787313591950805858
abs:  
288.062
288.0625

两个编译器实际上返回288.0625std::abs 1,但GCC输出288.62(地板)和VC 288.063 (ceil) -这不是一个"问题"在std::abs,但一个"问题"的方式输出格式化2

1两个编译器都返回std::abs的近似值,因为您正在使用std::absfloat,而您正在使用doublestd::sqrt。将6.288.替换为6.f288.f或将std::complex<float>替换为std::complex<double>,您将获得与std::sqrtstd::abs相同的结果。

2据我所知,标准在使用std::ostream时没有定义浮点值的舍入方式,实际规范来自printf格式转换%f,其中只有推荐一种舍入方式(我认为,这是gcc使用"四舍五入"的方式)。