#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
void
bc_raise (bc_num num1, bc_num num2, bc_num *result, int scale TSRMLS_DC)
{
bc_num temp, power;
long exponent;
int rscale;
int pwrscale;
int calcscale;
char neg;
if (num2->n_scale != 0)
bc_rt_warn ("non-zero scale in exponent");
exponent = bc_num2long (num2);
if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
bc_rt_error ("exponent too large in raise");
if (exponent == 0)
{
bc_free_num (result);
*result = bc_copy_num (BCG(_one_));
return;
}
if (exponent < 0)
{
neg = TRUE;
exponent = -exponent;
rscale = scale;
}
else
{
neg = FALSE;
rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
}
power = bc_copy_num (num1);
pwrscale = num1->n_scale;
while ((exponent & 1) == 0)
{
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale TSRMLS_CC);
exponent = exponent >> 1;
}
temp = bc_copy_num (power);
calcscale = pwrscale;
exponent = exponent >> 1;
while (exponent > 0)
{
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale TSRMLS_CC);
if ((exponent & 1) == 1) {
calcscale = pwrscale + calcscale;
bc_multiply (temp, power, &temp, calcscale TSRMLS_CC);
}
exponent = exponent >> 1;
}
if (neg)
{
bc_divide (BCG(_one_), temp, result, rscale TSRMLS_CC);
bc_free_num (&temp);
}
else
{
bc_free_num (result);
*result = temp;
if ((*result)->n_scale > rscale)
(*result)->n_scale = rscale;
}
bc_free_num (&power);
}