How to raise a number to a power without using the math.h library?

11

How can I raise a number to a power without using the math.h library?

Example:

potencia = x ^ 1/2;

How do I do this in C ++?

    
asked by anonymous 11.02.2014 / 16:03

8 answers

13

If the goal is to learn how the function works, a good way is to read the source code of some libc implementation, for example glibc .

The function powf (internally called __powf ) is defined in /math/w_powf.c . Its operation boils down to calling __ieee754_powf doing the actual operation and then dealing with edge cases . This second is defined in /sysdeps/ieee754/flt-32/e_powf.c . It's not an easy code to read, but it might be worth the effort. The interesting thing about this code is that it computes in constant time. There are no loops or recursions.

In another implementation, dietlibc , the function is in the file /libm/pow.c . It has an optimization for integers that calculates in a loop. The non-integer pow is calculated as exp(log(mant)*expo) , delegating to other functions. The exp and log function are implemented in assembly using appropriate FPU instructions that do the calculation on hardware. See /i386/log.S and /i386/exp.S .

I recommend caution if you want to implement your own version of any of these functions. Do this only if it is really necessary (you are in an extremely limited resource environment and can not afford to include a libc next to your application). Writing an equivalent function can be very interesting for studies, but not for production.

    
11.02.2014 / 17:37
8

Welcome to the world of computational mathematics where various functions like Pi, square root, sine and cosine are implemented as the summation of infinite convergent series.

There is an equal question in StackOverflow in English that is worth reading:

link

It may also be interesting to visit the fast inverse square root wiki that talks about the performative (and least precise) implementation of the algorithm.

link

Remembering that all these algorithms offer values with some degree of precision, never an exact value because an "infinite" precision would require infinite processing and infinite memory.

    
12.02.2014 / 11:28
8

My attempt, based on @Guilherme Bernal. Certainly you have problems with extreme values, accumulation of rounding errors etc. etc. but for "well-behaved" values it seemed to work fine.

#include <stdio.h>
#include <math.h>

double epsilon = 1e-15;

double myexp(double x) {
    double old_r = 0;
    double r = 1 + x;
    double div = 1;
    double i = 1;
    double m = x;
    while (fabs(1 - r / old_r) > epsilon) {
       div *= ++i;
       m *= x;
       old_r = r;
       r += m / div;
    }

    return r;
}

double mylog(double x) {
    static const double e = 2.718281828459045;
    int n = 0;
    while (fabs(x) >= 1) {
        x /= e;
        ++n;
    }

    x -= 1;
    double r = x;
    double m = x;
    double old_r = 0;
    double div = 1;
    double signal = 1;
    while (fabs(1 - r / old_r) > epsilon) {
       m *= x;
       old_r = r;
       signal *= -1;
       r += signal * m / ++div;
    }   
    return n+r;
}

int main() {
    printf("exp(1) = %.15f\n", exp(1));
    printf("exp(10) = %.15f\n", exp(10));
    printf("log(exp(10)) = %.15f\n", log(exp(10)));
    printf("sqrt(2) = %.15f\n", exp(0.5*log(2)));
    printf("--\n");
    printf("exp(1) = %.15f\n", myexp(1));
    printf("exp(10) = %.15f\n", myexp(10));
    printf("log(exp(10)) = %.15f\n", mylog(myexp(10)));
    printf("sqrt(2) = %.15f\n", myexp(0.5*mylog(2)));
}

Demo: Coliru

exp(1) = 2.718281828459045
exp(10) = 22026.465794806717895
log(exp(10)) = 10.000000000000000
sqrt(2) = 1.414213562373095
--
exp(1) = 2.718281828459046
exp(10) = 22026.465794806710619
log(exp(10)) = 10.000000000000002
sqrt(2) = 1.414213562373096
    
12.02.2014 / 17:18
6

Only way to do this is by approximation

(1+x)^(1/2) ~ 1 + x/2 

When x is too small, or creating a routine for the complete series

(1+x)^(1/2) = 1 + x/2 - 3x/4 + 15x/8 - ... 

thing that the sqrt () function already does efficiently. So you just have no reason to use it if you are studying numerical computing or want to create some better algorithm.

    
11.02.2014 / 16:47
2

Think about how you would do this on a math test. x^(1/2) is equal to sqrt(x) . With that in mind, the rest of the implementation is pretty smooth.

Note: As you remembered, in fact x^(1/2) is equivalent to sqrt(x) and not 1/x^2 , as my colleagues reminded me. The implementation of a square root is a bit more complicated than I had planned, but the intent of the initial response is still valid - just see how you would do the implementation (or rather, the algorithm).

    
11.02.2014 / 16:06
0

Good afternoon, the program with the function will look like this:

float paw (float x, float y);

main()
{

float a, b, res;

    printf("Entre com o base:");
    scanf("%f", &a);
    printf("\n\nEntre com o expoente:");
    scanf("%f", &b);
    res= paw(a,b);
    printf("O resultado sera:%f\n\n", res);
    system("pause");


}

float paw ( float x, float y)

{

float i;

float a;

if(y== 0 && x!=0)

return 1;

else if(y>=0)

{

a=1;

for( i=0 ; i<=y-1 ; i++)

a = x*a;

return a;

}
else

{

y = -1*y;

a=1;

for( i=0 ; i<=y-1 ; i++)

a = x*a;

a = 1.0/a;

return a;

}

}
    
04.03.2016 / 18:53
0

The simplest possible without the math.h library

//Tomás Louraco 19/02/18
//Programa que escreve a potencia
#include <iostream>
using namespace std;

int main()
{
setlocale(LC_ALL,"portuguese");
int b, a, i, c=1;
cout << "\t\tIntroduza o valor de A : ";
cin >> a;
cout << "\t\tIntroduza o expoente : ";
cin >> b;
for (i=0;i<=b;i++)
{
c=c*a;
}
cout << "\n\n\n\t\tResultado : " << c;
return 0;
}
    
19.02.2018 / 10:53
-1

I imagine it looks something like this:

#include <stdio.h>
main(){
int b,c,d,n,x,y,z;
double p;
printf("Lembrando que: base ^ (numerador/denominador) = potencia\n\n"); //Linha opcional
printf("Digite o valor da base: ");
scanf("%d",&b);
printf("Digite o numerador da fracao do expoente: ");
scanf("%d",&n);
printf("Digite o denominador da fracao do expoente: ");
scanf("%d",&d);
x=1;
z=n;
while (z>0)
{
    z=z-1;
    x=x*b;
}
p=0;
y=0;
while (y<x)
{
    p=p+0.00001;
    c=0;
    y=1;
    while (c<d)
    {
        c=c+1;
        y=y*p;
    }
}
printf("\n\nPotencia: %d ^ (%d/%d) = %.4lf",b,n,d,p);
getchar();
}
    
01.02.2016 / 03:08