C++
#include <math.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int main()
{
int cubo = 0;
cubo = pow(5, 3);
cout << "POW a traves de la variable 'cubo': " << cubo << endl; // me devuelve 124 (mal)
cout << "POW directamente a consola: " << pow(5, 3); // me devuelve 125 (bien)
return 0;
}
I have only detected it, for the moment, with 5, both squared and cubed. In the first case, squared, it returns 24 per variable (bad), and 25 directly to the console (good)
I have continued messing around with this "problem", and I have devised a code to detect which number raised to which power gives a different result, if it is passed through a variable or if it goes directly to the console.
I explain myself after the code:
C++
#include <math.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int main()
{
int resultado_variable = 0;
int cantidad = 0;
float potencia = 0;
cout << "\nEscribe la cantidad de numeros a elevar a partir del 1: ";
cin >> cantidad;
cout << "Escribe la potencia a elevar: ";
cin >> potencia;
for (int i = 1; i <= cantidad; i++)
{
resultado_variable = pow(i, potencia);
if (resultado_variable != pow(i, potencia))
{
cout << "\n" << i << "^" << potencia << endl;
cout << "POW a traves de la variable: " << resultado_variable << endl;
cout << "POW directamente a consola: " << pow(i, potencia) << endl;
}
}
cout << "\n";
return 0;
}
Whether the variable or the iterator of the FOR loop are declared as as
float
far as I have tested, the code does not detect differences, which would be a satisfactory solution to avoid this phenomenon, and perform a calculation of some precision.
But if the variable or the iterator is declared as an integerint
, that is when some very curious results appear. That is, the same numbers on the screen that the code detects as different.
In fact, I don't like the rounding, since it seems that when faced with a result like 24.99999999..., which would still be 25 when rounded, C++ doesn't take decimals into account and keeps the integer, in this case 24 Logical thing
, I think, when declaring the variable asint
.
But I don't quite understand why that affects the loop iterator.
<math.h>
The ,<stdlib.h>
and headers<stdio.h>
are from c and should not be used in c++ .There is a C++-friendly version of each of those headers, they are respectively
<cmath>
,<cstdlib>
and<cstdio>
, you should use those and not the C ones to compile C++ code.Not only that, you should also avoid including headers that you don't use, your shortcode doesn't use anything that
<stdlib.h>
neither provides<stdio.h>
. That said, let's see the differences between<math.h>
and<cmath>
.<math.h>
Since C does not allow function overloading, there are three versions of the function for three parameter doublets and a macro to simulate function overloading:
double pow(double, double)
.float powf(float, float)
.long double powl(long double, long double)
.#define pow(base, exponent)
.Since there are no namespaces in C, all functions are in the global namespace.
<cmath>
As in the C header, the same three versions of the function exist, along with an integer exponent version and a template version that covers all combinations of arithmetic arguments not covered by the non-template versions:
double pow(double, double)
.float powf(float,float)
.long double powl(long double, long double)
.double pow(double, int)
.float pow(float, int)
.long double pow(long double, int)
.tipo_promovido pow(tipo_aritmetico_1, tipo_aritmetico_2)
.All of these functions are in the
std
.Now that we know the differences between both headers, let's see what happened:
<math.h>
.pow
with integer parameters, so the macro is executed.pow
with integer parameters (int
).int
, it is calledpow
converting the arguments and the result todouble
.double
as an integer, losing the decimal part.The rounding error does not occur when printing directly as you do not store the temporary result in an integer variable, but that is dependent on how the compiler and system have the rounding type configured.
The most normal thing is that it is a rounding error. Do not store a float in a
int
or you will lose the whole decimal part.For some reason the program will be returning a result similar to 24.999999999999... when printing that result the system automatically rounds it to 25, but if you convert it to an integer, as the decimals are truncated, the result obtained is 24
For more information on the subject you can read the answers to this other question
Why can't my programs do arithmetic correctly?
A rounding error in an operation as simple as 5 to the power of 2 is shocking. You might think that it would
pow()
implement that operation by multiplying 5 by 5, in which case it should give 25. And even if the 5 is being represented as a floating point there is no way to account for round-off errors in the 5*5 operation, since both 5.0 and 25.0 are exactly representable in the IEEE-754 standard (both singlefloat
-precision and double-precisiondouble
).So what is going on here?
It just so happens that it
pow(a, b)
supports both parameters of typefloat
ordouble
, to allow you to do operations like raising 5 to fractional numbers. For example 5 raised to 0.5 would be the square root.In order to be able to raise
a
tob
beingb
an arbitrary real number, the easiest way to achieve this is to use logarithms. That is, multiply the logarithm ofa
byb
, and then undo the logarithm. In shortexp(log(a)*b)
:This can certainly explain rounding errors. In fact, check out the following experiment I've done with python:
So now we know why you get 24 if you put it in a variable of type
int
. As for why it outputs 25.0 instead of 24.999999999999996 when you directly print the result ofpow()
is because, unlike the python REPL, C++ tries to give a "friendly" representation of float numbers, rounding them to a reasonable number of decimal places, instead of showing up to the last decimal. In fact python does it too if you use the equivalent of "printf":