enhanced the multiplication function to truncate the resulting fixed-point decimal to the equal precision to the operands
This commit is contained in:
		
							
								
								
									
										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; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user