Why Is My Integer Math With Std::Pow Giving the Wrong Answer

c++ or c pow giving wrong result

Ignacio's answer already mentions using logarithms. But we ultimately end up using exp() which again is a library function. So if you don't want to use library functions at all, then you have to resort to something like Taylor's expansion of x^y

As direct evaluation of Taylor's expansion for x^y is tedious, as Ignacio mentioned, base^power = exp( power*ln(base) ). And taylor's expansion for e^x is quite simple and that for ln(x) is also very simple. Both of them yield for simple interative/recursive implementation in C

Here is a simple implementation of e^x using the above Taylor's expansion

double pow_x ( double x , unsigned i )
{
double prod=1;
if ( i == 0 )
return 1;
while ( i )
{
prod*=x;
i--;
}
return prod;
}

long long factorial ( unsigned n )
{
if ( n == 0 )
return 1;

return n * factorial (n-1);
}

// Function to calculate e^x. Hence expo(5, 20) is calculating
// e^5 by summing 20 terms from the infinite series expansion
// and NOT a power calculation of 5^20
double expo ( double x, int terms )
{
/* terms tells us how long should we expand the taylor's series */
double sum=0;
unsigned i=0;
while ( i< terms )
{
sum+= pow_x(x,i)/factorial(i);
i++;
}
return sum;
}

exp(5.93,20) gives 376.152869 which Google tends to agree.

I hope, using this example, you can implement ln(x) on your own.

Calculation using power function gave wrong answers for large numbers

The pow function is defined as:

double pow(double x, double y);

Which means that it takes floating point arguments and returns a floating point result. Due to the nature of floating point numbers, some numbers can not be exactly represented. The result you're getting is probably the closest match possible.

Note also that you're doing two (probably lossy) conversions:

  • converting the arguments from long long to double, and
  • converting the result of the function from double to long long.

std::pow does not return the expected int value

The technical aspect: std::pow is not defined for int, only for double and float. Therefor you cannot rely on it returning the exact int value. You have to expect rounding errors.

The algorithm aspect: Calculating the n-th power using the naive algorithm (n multplications) obviously takes linear time. To improve performance for large powers, most implementations of std::pow do not use this naive algorithm. Instead they calculate the power using logarithms. This is much faster, but not as correct as the naive approach.

So if you need exact results, you have to calculate the power using a for loop.

Unexpected result with pow() function in C++

How about reading C++ reference? Here is what you can find about pow():

double pow (double base, double exponent);

float pow (float base, float exponent);

long double pow (long double base, long double exponent);

double pow (Type1 base, Type2 exponent); // additional overload

As you can see, there is no pow() for integer arguments, but you may use casting, like:

int x, n;  
{...}
double result=pow(double(x),double(n));

More informations were written here: Why is my integer math with std::pow giving the wrong answer?

Error while using pow() in C++

The main problem is type conversion. The result of pow is double. The modulo operator does not work for double. You need to take fmod.

Fix your line 3 like this:

int rounddown = (int)(n - fmod(n, pow(10, d +1));

Because your values are all in the domain of integer you can also use:

int rounddown = n - n % (int)(pow(10, d + 1));

as suggested by others.


Just for completeness ... If you are not forced to use an arithmetic approach you can just char compare:

#include<iostream>
#include<string>

using namespace std;

int countOnesInNumber(string s)
{
int res = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '1')
{
res++;
}
}
return res;
}

long countOnes(int upper)
{
long result = 0;
for(int i = 0; i < upper; i++)
{
result += countOnesInNumber(std::to_string(i));
}
return result;
}

int main()
{
string in;
cout << "Please enter a number:";
cin >> in;
cout << endl;
cout << "you choose:" << in << endl;
int n = stoi(in);
cout << "there are " << countOnes(n) << " ones under " << n << endl;

cin.ignore();
cin.get();
}

There is also a more sophisticated approach. The digits repeat for every magnitude. There is 1 one under 10, there are 10 times 1 one under 100 plus another 10 ones for the number 10...19. And so on. You can just calculate the number of ones under a given magnitude with:

int exp = (int)log10(n);
int ones = exp * (int)pow(10, exp - 1);

where n must be a magnitude of 10 (eg. 10, 100, 1000, 10000 ...). If you are good at maths you might even find a complete closed formula.

std::pow with integer parameters, comparing to an integer type

It is funny you should ask, because someone else on StackOverflow had a question that was caused by the very fact that pow applied to small integers did not compute the obvious result on their platform (see also my writeup).

So yes, when applying pow to small integers, both arguments and ideal mathematical result are exactly representable. This does not force the implementation of exp to return the mathematical result, because no standard specifies that pow cannot be inaccurate by more than one ULP. And at least one very popular platform provides by default a pow function that does not compute pow(10, 2) as 100, but you are free to take you chances with pow(2, N) and perhaps it will happen to always return the integer you are entitled to expect.

C++ pow() function changes behaviour when put inside a function

The problem is that the output of pow is a floating point double. In your custom function you convert that output to long long, which will truncate if the value returned by pow is slightly low instead of slightly high. See Is floating point math broken?. When you call pow directly the value is kept as a double even after the multiplication, and output rounding gives you a more accurate result.

You expect the value returned by pow(100,2) to be 10000, but instead it might be 9999.99999999999 because of the way floating point works. When converted to integer, that becomes 9999; multiplied by 68, you have 679932.

On the other hand, 9999.99999999999 multiplied by 68 becomes 679999.999999999. That's close enough to 680000 that the output function << will round it for you. You can get a more exact figure if you apply output formatting.

Loss of precision with pow function when surpassing 10^10 limit?

The main reason of problems is pow() function. It works with double, not int. Loss of accuracy is price for representing huge numbers.
There are 3 way's to solve problem:

  1. For small n you can make your own long long int pow(int x, int pow) function. But there is problem, that we can overflow even long long int
  2. Use long arithmetic functions, as @rustyx sayed. You can write your own with vector, or find and include library.
  3. There is Math solution specific for topic's task. It solves the big numbers problem.
    You can write your formula like
    ((10^n) - 1) * (10^n) - (10^m - 1) * (10^m)) / 2 , (here m = n-1)
    Then multiply numbers in numerator. Regroup them. Extract common multiples 10^(n-1). And then you can see, that answer have a structure:
    X9...9Y0...0 for big enought n, where letter X and Y are constants.
    So, you can just print the answer "string" without calculating.


Related Topics



Leave a reply



Submit