enhanced the multiplication function to truncate the resulting fixed-point decimal to the equal precision to the operands
This commit is contained in:
parent
e466c6b68a
commit
8df5087b9d
41
lib/number.c
41
lib/number.c
@ -96,6 +96,26 @@ static hcl_ooi_t equalize_scale (hcl_t* hcl, hcl_oop_t* x, hcl_oop_t* y)
|
|||||||
return xs;
|
return xs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static hcl_oop_t truncate (hcl_t* hcl, hcl_oop_t iv, hcl_ooi_t cs, hcl_ooi_t ns)
|
||||||
|
{
|
||||||
|
/* this function truncates an existing fixed-point decimal.
|
||||||
|
* it doesn't create a new object */
|
||||||
|
|
||||||
|
if (cs > ns)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* TODO: optimizatino... less divisions */
|
||||||
|
iv = hcl_divints(hcl, iv, HCL_SMOOI_TO_OOP(10), 0, HCL_NULL);
|
||||||
|
if (!iv) return HCL_NULL;
|
||||||
|
cs--;
|
||||||
|
}
|
||||||
|
while (cs > ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iv;
|
||||||
|
}
|
||||||
|
|
||||||
hcl_oop_t hcl_addnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
hcl_oop_t hcl_addnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
||||||
{
|
{
|
||||||
if (!HCL_IS_FPDEC(hcl, x) && !HCL_IS_FPDEC(hcl, y))
|
if (!HCL_IS_FPDEC(hcl, x) && !HCL_IS_FPDEC(hcl, y))
|
||||||
@ -156,7 +176,7 @@ hcl_oop_t hcl_subnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
|||||||
|
|
||||||
hcl_oop_t hcl_mulnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
hcl_oop_t hcl_mulnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
||||||
{
|
{
|
||||||
hcl_ooi_t xs, ys, scale;
|
hcl_ooi_t xs, ys, cs, ns;
|
||||||
hcl_oop_t nv;
|
hcl_oop_t nv;
|
||||||
hcl_oop_t xv, yv;
|
hcl_oop_t xv, yv;
|
||||||
|
|
||||||
@ -189,16 +209,21 @@ hcl_oop_t hcl_mulnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
|||||||
nv = hcl_mulints(hcl, xv, yv);
|
nv = hcl_mulints(hcl, xv, yv);
|
||||||
if (!nv) return HCL_NULL;
|
if (!nv) return HCL_NULL;
|
||||||
|
|
||||||
scale = xs + ys;
|
cs = xs + ys;
|
||||||
if (scale > HCL_SMOOI_MAX)
|
if (cs <= 0) return nv; /* the result must be an integer */
|
||||||
{
|
|
||||||
/* TODO: limit scale */
|
|
||||||
}
|
|
||||||
|
|
||||||
return hcl_makefpdec(hcl, nv, scale);
|
ns = (xs > ys)? xs: ys;
|
||||||
|
|
||||||
|
/* cs may be larger than HCL_SMOOI_MAX. but ns is guaranteed to be
|
||||||
|
* equal to or less than HCL_SMOOI_MAX */
|
||||||
|
HCL_ASSERT (hcl, ns > 0 && ns <= HCL_SMOOI_MAX);
|
||||||
|
|
||||||
|
nv = truncate(hcl, nv, cs, ns);
|
||||||
|
if (!nv) return HCL_NULL;
|
||||||
|
|
||||||
|
return hcl_makefpdec(hcl, nv, ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
hcl_oop_t hcl_divnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
hcl_oop_t hcl_divnums (hcl_t* hcl, hcl_oop_t x, hcl_oop_t y)
|
||||||
{
|
{
|
||||||
hcl_ooi_t xs, ys, i;
|
hcl_ooi_t xs, ys, i;
|
||||||
|
@ -260,12 +260,14 @@ static hcl_oop_t string_to_fpdec (hcl_t* hcl, hcl_oocs_t* str, const hcl_ioloc_t
|
|||||||
return HCL_NULL;
|
return HCL_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scale > 0) HCL_MEMMOVE (&str->ptr[pos], &str->ptr[pos + 1], scale * HCL_SIZEOF(str->ptr[0]));
|
HCL_ASSERT (hcl, scale > 0);
|
||||||
|
/*if (scale > 0)*/ HCL_MEMMOVE (&str->ptr[pos], &str->ptr[pos + 1], scale * HCL_SIZEOF(str->ptr[0]));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v = hcl_strtoint(hcl, str->ptr, str->len - 1, 10);
|
v = hcl_strtoint(hcl, str->ptr, str->len - 1, 10);
|
||||||
if (scale > 0) HCL_MEMMOVE (&str->ptr[pos + 1], &str->ptr[pos], scale * HCL_SIZEOF(str->ptr[0]));
|
/*if (scale > 0)*/ HCL_MEMMOVE (&str->ptr[pos + 1], &str->ptr[pos], scale * HCL_SIZEOF(str->ptr[0]));
|
||||||
if (!v) return HCL_NULL;
|
if (!v) return HCL_NULL;
|
||||||
|
|
||||||
return hcl_makefpdec (hcl, v, scale);
|
return hcl_makefpdec (hcl, v, scale);
|
||||||
@ -1156,7 +1158,8 @@ retry:
|
|||||||
GET_CHAR_TO (hcl, c);
|
GET_CHAR_TO (hcl, c);
|
||||||
if (!is_digitchar(c))
|
if (!is_digitchar(c))
|
||||||
{
|
{
|
||||||
hcl_setsynerrbfmt (hcl, HCL_SYNERR_NUMLIT, TOKEN_LOC(hcl), TOKEN_NAME(hcl), "invalid numeric literal with no digit after fixed-point");
|
/* the first character after the decimal point is not a decimal digit */
|
||||||
|
hcl_setsynerrbfmt (hcl, HCL_SYNERR_NUMLIT, TOKEN_LOC(hcl), TOKEN_NAME(hcl), "invalid numeric literal with no digit after decimal point");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user