Enamul Hassan
Enamul Hassan

Reputation: 5445

Does the implementation of pow() function in C/C++ vary with platform or compiler?

It took a day to debug the built-in pow() function's output. The output differed between my compiler and an online compiler. That is a long story. I have written the following Minimal, Complete, and Verifiable example reproduce the situation.

Code:

#include <bits/stdc++.h>
using namespace std;

// This function just prints the binary representation as it is in memory
// A modified version of Lightness Races in Orbit's code given here: https://stackoverflow.com/a/37861479/3555000
// I thank Lightness Races in Orbit for the contribution
void print_binary(long double y)
{
    const long double x = y;
    unsigned char     a[sizeof(long double)];

    copy(
        reinterpret_cast<const unsigned char*>(&x),
        reinterpret_cast<const unsigned char*>(&x) + sizeof(long double),
        &a[0]
    );
    for (auto el : a)
    {
        bitset<8>k(el);
        cout << k.to_string() ;
    }

    cout << endl;
}

int main()
{
    int a[] = {20,29,31}, res=0; //Took three numbers and initialized the result
    for(int i = 0; i<3; i++)
    {
        cout<<"i = "<<i<< ", a["<<i<< "] = "<<a[i]<<"\npow(" << a[i] <<","<<i+1 << "):\nBinary: ";
        long double temp = pow(a[i],i+1);
        print_binary(temp);
        res+=temp;
        cout<<setprecision(50)<<fixed<< "Decimal: " <<temp <<", Result = "<<res<<endl;
    }
    return 0;
}

Output in my Code::Blocks:

i = 0, a[0] = 20
pow(20,1):
Binary: 000000000000000000000000000000000000000000000000000000001010000000000011010000000110100000000000
Decimal: 20.00000000000000000000000000000000000000000000000000, Result = 20
i = 1, a[1] = 29
pow(29,2):
Binary: 111111011111111111111111111111111111111111111111001111111101001000001000010000000110100000000000
Decimal: 840.99999999999999983346654630622651893645524978637695, Result = 860
i = 2, a[2] = 31
pow(31,3):
Binary: 111111101111111111111111111111111111111111111111101111011110100000001101010000000110100000000000
Decimal: 29790.99999999999999644728632119949907064437866210937500, Result = 30650

Output in Ideone:

i = 0, a[0] = 20
pow(20,1):
Binary: 000000000000000000000000000000000000000000000000000000001010000000000011010000000000000000000000
Decimal: 20.00000000000000000000000000000000000000000000000000, Result = 20
i = 1, a[1] = 29
pow(29,2):
Binary: 000000000000000000000000000000000000000000000000010000001101001000001000010000000000000000000000
Decimal: 841.00000000000000000000000000000000000000000000000000, Result = 861
i = 2, a[2] = 31
pow(31,3):
Binary: 000000000000000000000000000000000000000000000000101111101110100000001101010000000000000000000000
Decimal: 29791.00000000000000000000000000000000000000000000000000, Result = 30652

I thought that pow() function gives wrong output sometimes, but the implementation of it is the same in all compilers. Because I thought it has an established standard.

My Questions:

Upvotes: 3

Views: 979

Answers (3)

ZachB
ZachB

Reputation: 15366

Quite simply, the C++ standard explicitly imposes no requirements on the accuracy of floating-point operations or the numeric library functions like std::pow. They are implementation-specific.

The various standard library implementations1 (glibc, musl, etc.) can and do use different approximations of numeric functions. Here are a few implementations of pow for example:

If you need deterministic behavior, you need to use the same standard library on all platforms/with all compilers.


1Not to be confused with compiler or platform. Usually the standard library is provided by the compiler, but not necessarily.

Upvotes: 0

kangshiyin
kangshiyin

Reputation: 9771

A lot of factors affect the result of floating-point arithmetic, such as rounding, order of the operations. Even using same code of pow(), different hardware, different compilers or even different compiling options may give different results, that's why binary comparison is meaningless.

There's standard on std::pow and floating point numbers.

http://en.cppreference.com/w/cpp/numeric/math/pow

https://en.m.wikipedia.org/wiki/IEEE_floating_point

But as pointed by some of the question comments, the standard does not specify everything and compiler/code sometimes does not even follow the standard. Most of the time, it's a balance between precision and speed.

Numerical error / floating-point precision error / accuracy error - not sure. Undefined behavior is usually unexpected and far away from correct. But all results from different pow() are correct.

Upvotes: 3

Joel H
Joel H

Reputation: 1

First thing I'd like to point out is that you are using res to print out your result, you are also adding result together multiple times in the loop, meaning by the second iteration your result is wrong.

Move res = 0 into the for loop.

Upvotes: -4

Related Questions