diff --git a/lib/bigint.c b/lib/bigint.c index beef8ad..255cb79 100644 --- a/lib/bigint.c +++ b/lib/bigint.c @@ -3952,6 +3952,62 @@ oops_einval: return HCL_NULL; } +hcl_oop_t hcl_sqrtint (hcl_t* hcl, hcl_oop_t x) +{ + /* TODO: find a faster and more efficient algorithm??? */ + hcl_oop_t a, b, m, m2, t; + + a = hcl->_nil; + b = hcl->_nil; + m = hcl->_nil; + m2 = hcl->_nil; + + hcl_pushtmp (hcl, &x); + hcl_pushtmp (hcl, &a); + hcl_pushtmp (hcl, &b); + hcl_pushtmp (hcl, &m); + hcl_pushtmp (hcl, &m2); + + a = HCL_SMOOI_TO_OOP(1); + b = hcl_bitshiftint(hcl, x, HCL_SMOOI_TO_OOP(-5)); + if (!b) goto oops; + b = hcl_addints(hcl, b, HCL_SMOOI_TO_OOP(8)); + if (!b) goto oops; + + while (1) + { + t = hcl_geints(hcl, b, a); + if (!t) return HCL_NULL; + if (t == hcl->_false) break; + + m = hcl_addints(hcl, a, b); + if (!m) goto oops; + m = hcl_bitshiftint(hcl, m, HCL_SMOOI_TO_OOP(-1)); + if (!m) goto oops; + m2 = hcl_mulints(hcl, m, m); + if (!m2) goto oops; + t = hcl_gtints(hcl, m2, x); + if (!t) return HCL_NULL; + if (t == hcl->_true) + { + b = hcl_subints(hcl, m, HCL_SMOOI_TO_OOP(1)); + if (!b) goto oops; + } + else + { + a = hcl_addints(hcl, m, HCL_SMOOI_TO_OOP(1)); + if (!a) goto oops; + } + } + + hcl_poptmps (hcl, 5); + return hcl_subints(hcl, a, HCL_SMOOI_TO_OOP(1)); + +oops: + hcl_poptmps (hcl, 5); + return HCL_NULL; +} + hcl_oop_t hcl_inttostr (hcl_t* hcl, hcl_oop_t num, int radix, int ngc) { hcl_ooi_t v = 0; diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index 92672d6..2cdbef9 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -940,6 +940,11 @@ hcl_oop_t hcl_leints ( hcl_oop_t y ); +hcl_oop_t hcl_sqrtint ( + hcl_t* hcl, + hcl_oop_t x +); + hcl_oop_t hcl_strtoint ( hcl_t* hcl, const hcl_ooch_t* str, @@ -1038,6 +1043,13 @@ hcl_oop_t hcl_nenums ( hcl_oop_t x, hcl_oop_t y ); + +hcl_oop_t hcl_sqrtnum ( + hcl_t* hcl, + hcl_oop_t x +); + + /* ========================================================================= */ /* comp.c */ /* ========================================================================= */ diff --git a/lib/number.c b/lib/number.c index e8575e9..b9b5448 100644 --- a/lib/number.c +++ b/lib/number.c @@ -335,7 +335,6 @@ hcl_oop_t hcl_lenums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) return comp_nums(hcl, x, y, hcl_leints); } - hcl_oop_t hcl_eqnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) { return comp_nums(hcl, x, y, hcl_eqints); @@ -344,3 +343,25 @@ hcl_oop_t hcl_nenums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y) { return comp_nums(hcl, x, y, hcl_neints); } + +hcl_oop_t hcl_sqrtnum (hcl_t* hcl, hcl_oop_t x) +{ + if (!HCL_IS_FPDEC(hcl, x)) + { + return hcl_sqrtint(hcl, x); + } + else + { + /* TODO: debug this part... this part is buggy. not complete yet */ + hcl_oop_t v; + hcl_ooi_t scale; + + scale = HCL_OOP_TO_SMOOI(((hcl_oop_fpdec_t)x)->scale); + v = ((hcl_oop_fpdec_t)x)->value; + + v = hcl_sqrtint(hcl, v); + if (!v) return HCL_NULL; + + return hcl_makefpdec(hcl, v, scale / 2); + } +} diff --git a/lib/prim.c b/lib/prim.c index 87e6f28..6c4e048 100644 --- a/lib/prim.c +++ b/lib/prim.c @@ -499,6 +499,16 @@ static hcl_pfrc_t pf_number_rem (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) return HCL_PF_SUCCESS; } +static hcl_pfrc_t pf_number_sqrt (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) +{ + hcl_oop_t ret; + ret = hcl_sqrtnum(hcl, HCL_STACK_GETARG(hcl, nargs, 0)); /*TODO: change to hcl_sqrtnum()*/ + if (!ret) return HCL_PF_FAILURE; + + HCL_STACK_SETRET (hcl, nargs, ret); + return HCL_PF_SUCCESS; +} + static hcl_pfrc_t pf_number_gt (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) { hcl_oop_t ret; @@ -585,6 +595,7 @@ static pf_t builtin_prims[] = { 1, HCL_TYPE_MAX(hcl_oow_t), pf_number_div, 1, { '/' } }, { 1, HCL_TYPE_MAX(hcl_oow_t), pf_number_quo, 3, { 'q','u','o' } }, { 2, HCL_TYPE_MAX(hcl_oow_t), pf_number_rem, 3, { 'm','o','d' } }, + { 1, 1, pf_number_sqrt, 4, { 's','q','r','t' } }, { 2, 2, pf_number_gt, 1, { '>' } }, { 2, 2, pf_number_ge, 2, { '>','=' } },