Search code examples
c++floating-pointpow

Why are pow(x,1/p) and pow(x,1.0/p) not equal even though printing their values gives the same result


The question is:

You are given 2 numbers (N , M); the task is to find N√M (Nth root of M).

Input:

The first line of input contains an integer T denoting the number of test cases. Then T test cases follow. Each test case contains two space separated integers N and M.

Output:

For each test case, in a new line, print an integer denoting Nth root of M if the root is an integer else print -1.

Now my solution to this problem was:

#include <math.h>
#include <iostream>
#include <math.h>
using namespace std;

int main() {
    int t;
    float x, p;
    cin>>t;
    for(int i=0;i<t;i++)
    {
        cin>>p>>x;
        if(p==0)
        {
            cout<<"1"<<endl;

        }
        
        else
        {
            float res=pow(x,(1/p));
            cout<<"res="<<res<<endl;
            if(res==int(res))
                cout<<res<<endl;
            else
                cout<<"-1"<<endl;
        }    
    }
    return 0;
}

This caused a problem in the test case :

1
3
1000

Although when I printed res, I got 10 as a result, during the condition checking if(res==int(res)) turned out to be false.

Also I noticed that changing from float res=pow(x,(1/p)); to float res=pow(x,(1.0/p)); was giving the correct answer. I'm guessing its something related to getting 0.33333 when the evaluation of 1/p is done, but I cannot understand why the printed value is 10 but not matching in the condition checking.


Solution

  • Why are pow(x,1/p) and pow(x,1.0/p) not equal even though printing their values gives the same result (?)

    Computations differ due to precision. Computations are not mathematically exact: pow() did not receive an exact 1/3.

    With float p, 1/p can differ from 1.0/p as the first is done using float (or wider) math and the second uses double (or wider) as 1.0 is a double.

    This in turn calls either a float or double pow(). Thus there are potentially different res results.

    In OP's case: pow(1000.0f,(1/3.0f)) performed a float precision calculation something like pow(1000, near_one_third) and not cbrt(1000.0) - the result was not exactly 10.0f. pow(1000.0f,(1.0/3.0f)) performed a like-wise double precision computation that when rounded to float was exactly 10.0f.

    why the printed value is 10 but not matching in the condition checking.

    Should res have a computed value a wee more or less than 10.0f, then == is not true.

    Print with sufficient precision to see differences in the final output. Recommend at least 9 significant digits for float res.


    At a minimum, I suggest using the same floating point types and math throughout. (Use 1.0f with float.) Further recommend to use double.

    Final outputs may still not be the exact expected integer (from a math analysis) as pow() though.