简体   繁体   English

C++ / GCC 4.8 中的“round()”与“std::round()”和“fabs()”与“std::fabs()”

[英]'round()' vs 'std::round()' and 'fabs()' vs 'std::fabs()' in C++ / GCC 4.8

By accident I was calling round() and fabs() instead of std::round() and std::fabs() and for the largest integer a long double can hold without loosing precision there was a difference.意外的是,我调用的是round()fabs()而不是std::round()std::fabs() ,对于最大的 integer 来说,一个long double可以保持而不会失去精度,这是有区别的。

Consider this test program round.cpp :考虑这个测试程序round.cpp

#include <iostream>
#include <iomanip>
#include <cstdint>
#include <limits>
#include <cmath>

using std::cout;
using std::endl;
using std::setw;
using std::setprecision;

void print(const char* msg, const long double ld)
{
    cout << msg << setprecision(20) << ld << endl;
}

void test(const long double ld)
{
    const long double ldRound = round(ld);
    const long double ldStdRound = std::round(ld);
    const long double ldFabs = fabs(ld);
    const long double ldStdFabs = std::fabs(ld);

    print("Rounding using 'round()':                     ", ldRound);
    print("Rounding using 'std::round()':                ", ldStdRound);
    print("Absolute value using 'fabs()':                ", ldFabs);
    print("Absolute value using 'std::fabs()':           ", ldStdFabs);
}

int main()
{
    const int maxDigits = std::numeric_limits<long double>::digits;
    const int64_t maxPosInt = 0xffffffffffffffff >> (64 - maxDigits + 1);
    const long double maxPosLongDouble = (long double) maxPosInt;

    cout << setw(20);
    cout << "Max decimal digits in long double:            " << maxDigits << endl;
    cout << "Max positive integer to store in long double: " << maxPosInt << endl;
    print("Corresponding long double:                    ", maxPosLongDouble);

    test(maxPosLongDouble);

    return 0;
}

When compiling with g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36.0.1)使用g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36.0.1)编译时

/usr/bin/g++ -std=c++11 round.cpp -o round

and then running it, the results are one larger for the non- std function compared to the std functions:然后运行它,与std函数相比,非std function 的结果要大一个:

Max decimal digits in long double:            64
Max positive integer to store in long double: 9223372036854775807
Corresponding long double:                    9223372036854775807
Rounding using 'round()':                     9223372036854775808 <== one larger
Rounding using 'std::round()':                9223372036854775807
Absolute value using 'fabs()':                9223372036854775808 <== one larger
Absolute value using 'std::fabs()':           9223372036854775807

I get the exact same output (including 64 bits for long double) when I compile for 32 bits using option -m32 .当我使用选项-m32编译 32 位时,我得到完全相同的 output (包括长双精度的 64 位)。 Looking at the disassembly (using gbd on the 32 bit executable) for function test() I get:查看 function test()的反汇编(在 32 位可执行文件上使用gbd )我得到:

(gdb) disassemble test(long double) 
Dump of assembler code for function _Z4teste:
   0x080488c0 <+0>: push   %ebp
   ...
   0x080488d2 <+18>:    call   0x8048690 <round@plt>
   ...
   0x080488ee <+46>:    call   0x8048b59 <_ZSt5rounde> (demangled: std::round(long double))
   ...
   0x080488ff <+63>:    fabs   
   ...
   0x08048918 <+88>:    call   0x8048b4f <_ZSt4fabse> (demangled: std::fabs(long double))

   ...
   0x080489a4 <+228>:   leave  
   0x080489a5 <+229>:   ret    
End of assembler dump.

So it seems different function are called for round() and std::round() .因此,对于round()std::round()调用 function 似乎不同。 For fabs() a floating point instruction is emitted whereas for std::fabs() a function call is emitted.对于fabs()发出浮点指令,而对于std::fabs()发出 function 调用。

Can someone explain what is causing this difference and please tell me whether using std::round() and std::fabs() is the preferred portable choice?有人可以解释造成这种差异的原因,请告诉我使用std::round()std::fabs()是否是首选的便携式选择?

As @Praetorian explains in the comments to the question above, the answer is very simple.正如@Praetorian 在对上述问题的评论中所解释的那样,答案非常简单。

When including the C++ header <cmath> GCC brings a number of C++ math functions in the std namespace with appropriate overloads, for example: When including the C++ header <cmath> GCC brings a number of C++ math functions in the std namespace with appropriate overloads, for example:

float std::round(float)
double std::round(double)
long double std::round(long double)

float std::fabs(float)
double std::fabs(double)
long double std::fabs(long double)

However, it also brings into global scope the corresponding old C functions (same names) and as C does not support overloading these functions are only taking double as argument and returning double :但是,它也将相应的旧 C 函数(同名)和 C 不支持double载这些函数只作为参数和返回double载引入全局 scope

double round(double)
double fabs(double)

Therefore, the calls to round() and fabs() with no explicit namespace (and no using namespace std in the program) are calls to ::round() and ::fabs() which are the C functions that will then truncate the argument of type long double (64 bit precision) to double (53 bit precision) which explains the incorrect results.因此,没有显式命名空间(并且程序中没有using namespace std )对 round( round()fabs() () 的调用是对::round()::fabs()的调用,它们是 C 函数,然后将截断long double (64 位精度)到double (53 位精度)类型的参数,这解释了不正确的结果。

Therefore, in C++ always ensure you either prefix with std:: or have an appropriate using declaration.因此,在 C++ 中始终确保您以std::为前缀或具有适当的using声明。 I would recommend to be explicit calling std::round() and std::fabs() .我建议明确调用std::round()std::fabs()

PS In C there are also these functions if you need to handle float or long double : PS在 C 中,如果您需要处理floatlong double ,还有这些功能:

float roundf(float)
long double roundl(long double)

float fabsf(float)
long double fabsl(long double)

PPS In C++-14 you can also use std::abs() for any floating point type whereas in C++-11 std::abs() in only for integer types and std::fabs() is for floating point types. PPS在 C++-14 中,您还可以将std::abs()用于任何浮点类型,而在 C++-11 中, std::abs()仅用于 integer 类型,而std::fabs()用于浮点类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM