From 46dc1968ada3e5c2e436df06767ba8d69ad4a87c Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 4 Apr 2018 04:41:23 +0000 Subject: [PATCH] implemented sqrt for fixed-point decimal. fixed a bug in getting sqrt of a negative number --- lib/bigint.c | 29 ++++++++++++++++++++++++++--- lib/number.c | 17 +++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/bigint.c b/lib/bigint.c index 255cb79..8ee9d40 100644 --- a/lib/bigint.c +++ b/lib/bigint.c @@ -3956,7 +3956,14 @@ 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; - + int neg; + + if (!hcl_isint(hcl, x)) + { + hcl_seterrbfmt (hcl, HCL_EINVAL, "parameter not integer - %O", x); + return HCL_NULL; + } + a = hcl->_nil; b = hcl->_nil; m = hcl->_nil; @@ -3967,7 +3974,19 @@ hcl_oop_t hcl_sqrtint (hcl_t* hcl, hcl_oop_t x) hcl_pushtmp (hcl, &b); hcl_pushtmp (hcl, &m); hcl_pushtmp (hcl, &m2); - + + a = hcl_ltints(hcl, x, HCL_SMOOI_TO_OOP(0)); + if (!a) goto oops; + if (a == hcl->_true) + { + /* the given number is a negative number. + * i will arrange the return value to be negative. */ + x = hcl_negateint(hcl, x); + if (!x) goto oops; + neg = 1; + } + else neg = 0; + a = HCL_SMOOI_TO_OOP(1); b = hcl_bitshiftint(hcl, x, HCL_SMOOI_TO_OOP(-5)); if (!b) goto oops; @@ -4001,7 +4020,11 @@ hcl_oop_t hcl_sqrtint (hcl_t* hcl, hcl_oop_t x) } hcl_poptmps (hcl, 5); - return hcl_subints(hcl, a, HCL_SMOOI_TO_OOP(1)); + x = hcl_subints(hcl, a, HCL_SMOOI_TO_OOP(1)); + if (!x) return HCL_NULL; + + if (neg) x = hcl_negateint(hcl, x); + return x; oops: hcl_poptmps (hcl, 5); diff --git a/lib/number.c b/lib/number.c index b9b5448..df2da0f 100644 --- a/lib/number.c +++ b/lib/number.c @@ -352,16 +352,25 @@ hcl_oop_t hcl_sqrtnum (hcl_t* hcl, hcl_oop_t x) } else { - /* TODO: debug this part... this part is buggy. not complete yet */ hcl_oop_t v; - hcl_ooi_t scale; - + hcl_ooi_t i, scale; + scale = HCL_OOP_TO_SMOOI(((hcl_oop_fpdec_t)x)->scale); + v = ((hcl_oop_fpdec_t)x)->value; + for (i = 0; i < scale ; i++) + { + v = hcl_mulints(hcl, v, HCL_SMOOI_TO_OOP(10)); + if (!v) + { + hcl_poptmp (hcl); + return HCL_NULL; + } + } v = hcl_sqrtint(hcl, v); if (!v) return HCL_NULL; - return hcl_makefpdec(hcl, v, scale / 2); + return hcl_makefpdec(hcl, v, scale); } }