precision error in nth root of a number in C++

懵懂的女人 提交于 2019-12-13 03:04:40

问题


I know from previous threads on this topic that using float arithmetic causes precision anomalies. But Interestingly I observed that the same function is behaving in two different ways.
Using COUT output is 4 but if I am saving the result into a variable, then result is 3!

#include <iostream>
#include <cmath>
using namespace std;
#define mod 1000000007
long long int fastPower(long long int a, int n){
    long long int res = 1;
    while (n) {
            if (n & 1) res = (res * a) % mod;
            n >>= 1; a = (a * a) % mod;
    }
    return res;
}
int main() {
    int j = 3;
    cout << pow(64, (double)1.0/(double)j) << endl; // Outputs 4
    int root = pow(64, (double)1.0/(double)j);
    cout << root << endl;                           // Outputs 3
    /* As said by "pts", i tried including this condition in my code but including this line in my code resulted in TimeLimitExceeded(TLE). */
    if (fastPower(root+1,j) <= 64) root++;
    cout << root << endl;                           // Outputs 4 :)
    return 0;
}

Code output on Ideone.com
Now, how can we avoid such errors in a programing contest. I do not want to use 'round' function because I need only integer value of root. i.e
63(1/6) = 1, 20(1/2) = 4, etc...
How should I modify my code so that correct result is stored in the root variable.


回答1:


pow returns double. When cout is used, it is rounded(thus, it is 4). When you cast it to int, it just truncates fractional part. Pow returns something like 4 - eps(because of precision issues). When it is just truncated, it is equal to 3. Dirty hack useful in programming contests: int root = (int)(pow(...) + 1e-7)




回答2:


As far as I know, there is no single-line answer in C and C++ for getting the ath root of b rounded down.

As a quick workaround, you can do something like:

int root(int a, int b) {
  return floor(pow(b, 1.0 / a) + 0.001);
}

This doesn't work for every value, but by adjusting the constant (0.001), you may get lucky and it would work for the test input.

As a workaround, use pow as you use it already, and if it returns r, then try r - 1, r and r + 1 by multiplying it back (using fast exponentiation of integers). This will work most of the time.

If you need a solution which works 100% of the time, then don't use floating point numbers. Use for example binary search with exponentiation. There are faster algorithms (such as Newton iteration), but if you use them on integers then you need to write custom logic to find the exact solution as soon as they stop converging.




回答3:


There are two problems with your program:

  1. The pow(int, int) overload is no longer available. To avoid this problem, cast the first parameter to double, float, or long double.

  2. Also, command of cout is rounding off your answer in upper roof (3.something into 4) and saving your data is removing all the decimal part and is accepting only integer part.



来源:https://stackoverflow.com/questions/24110028/precision-error-in-nth-root-of-a-number-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!