#include <config.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
int
bc_sqrt (bc_num *num, int scale)
{
int rscale, cmp_res, done;
int cscale;
bc_num guess, guess1, point5, diff;
cmp_res = bc_compare (*num, BCG(_zero_));
if (cmp_res < 0)
return 0;
else
{
if (cmp_res == 0)
{
bc_free_num (num);
*num = bc_copy_num (BCG(_zero_));
return 1;
}
}
cmp_res = bc_compare (*num, BCG(_one_));
if (cmp_res == 0)
{
bc_free_num (num);
*num = bc_copy_num (BCG(_one_));
return 1;
}
rscale = MAX (scale, (*num)->n_scale);
bc_init_num(&guess);
bc_init_num(&guess1);
bc_init_num(&diff);
point5 = bc_new_num (1,1);
point5->n_value[1] = 5;
if (cmp_res < 0)
{
guess = bc_copy_num (BCG(_one_));
cscale = (*num)->n_scale;
}
else
{
bc_int2num (&guess,10);
bc_int2num (&guess1,(*num)->n_len);
bc_multiply (guess1, point5, &guess1, 0);
guess1->n_scale = 0;
bc_raise (guess, guess1, &guess, 0);
bc_free_num (&guess1);
cscale = 3;
}
done = FALSE;
while (!done)
{
bc_free_num (&guess1);
guess1 = bc_copy_num (guess);
bc_divide (*num, guess, &guess, cscale);
bc_add (guess, guess1, &guess, 0);
bc_multiply (guess, point5, &guess, cscale);
bc_sub (guess, guess1, &diff, cscale+1);
if (bc_is_near_zero (diff, cscale))
{
if (cscale < rscale+1)
cscale = MIN (cscale*3, rscale+1);
else
done = TRUE;
}
}
bc_free_num (num);
bc_divide (guess,BCG(_one_),num,rscale);
bc_free_num (&guess);
bc_free_num (&guess1);
bc_free_num (&point5);
bc_free_num (&diff);
return 1;
}