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
todouble
, and - converting the result of the function from
double
tolong 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:
- 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 evenlong long int
- Use long arithmetic functions, as @rustyx sayed. You can write your own with vector, or find and include library.
- 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
Convert a Vector≪Int≫ to a String
How to Write Std::String to File
Ull Suffix on a Numeric Literal
What Are the Uses of Std::Chrono::High_Resolution_Clock
Cmake: How to Set Up Source, Library and Cmakelists.Txt Dependencies
C++ [] Array Operator With Multiple Arguments
C++ Force Std::Cout Flush (Print to Screen)
Erasing from a Std::Vector While Doing a For Each
"Constructing" a Trivially-Copyable Object With Memcpy
_Builtin_Prefetch, How Much Does It Read
What Does the ≫= Operator Mean
Does Mingw-W64 Support Std::Thread Out of the Box When Using the Win32 Threading Model
How to Specify How Many Characters of a String to Print Out Using Printf()