00001 /* Copyright (C) 2000 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #line 18 "decimal.c" 00018 00019 /* 00020 ======================================================================= 00021 NOTE: this library implements SQL standard "exact numeric" type 00022 and is not at all generic, but rather intentinally crippled to 00023 follow the standard :) 00024 ======================================================================= 00025 Quoting the standard 00026 (SQL:2003, Part 2 Foundations, aka ISO/IEC 9075-2:2003) 00027 00028 4.4.2 Characteristics of numbers, page 27: 00029 00030 An exact numeric type has a precision P and a scale S. P is a positive 00031 integer that determines the number of significant digits in a 00032 particular radix R, where R is either 2 or 10. S is a non-negative 00033 integer. Every value of an exact numeric type of scale S is of the 00034 form n*10^{-S}, where n is an integer such that -R^P <= n <= R^P. 00035 00036 [...] 00037 00038 If an assignment of some number would result in a loss of its most 00039 significant digit, an exception condition is raised. If least 00040 significant digits are lost, implementation-defined rounding or 00041 truncating occurs, with no exception condition being raised. 00042 00043 [...] 00044 00045 Whenever an exact or approximate numeric value is assigned to an exact 00046 numeric value site, an approximation of its value that preserves 00047 leading significant digits after rounding or truncating is represented 00048 in the declared type of the target. The value is converted to have the 00049 precision and scale of the target. The choice of whether to truncate 00050 or round is implementation-defined. 00051 00052 [...] 00053 00054 All numeric values between the smallest and the largest value, 00055 inclusive, in a given exact numeric type have an approximation 00056 obtained by rounding or truncation for that type; it is 00057 implementation-defined which other numeric values have such 00058 approximations. 00059 00060 5.3 <literal>, page 143 00061 00062 <exact numeric literal> ::= 00063 <unsigned integer> [ <period> [ <unsigned integer> ] ] 00064 | <period> <unsigned integer> 00065 00066 6.1 <data type>, page 165: 00067 00068 19) The <scale> of an <exact numeric type> shall not be greater than 00069 the <precision> of the <exact numeric type>. 00070 00071 20) For the <exact numeric type>s DECIMAL and NUMERIC: 00072 00073 a) The maximum value of <precision> is implementation-defined. 00074 <precision> shall not be greater than this value. 00075 b) The maximum value of <scale> is implementation-defined. <scale> 00076 shall not be greater than this maximum value. 00077 00078 21) NUMERIC specifies the data type exact numeric, with the decimal 00079 precision and scale specified by the <precision> and <scale>. 00080 00081 22) DECIMAL specifies the data type exact numeric, with the decimal 00082 scale specified by the <scale> and the implementation-defined 00083 decimal precision equal to or greater than the value of the 00084 specified <precision>. 00085 00086 6.26 <numeric value expression>, page 241: 00087 00088 1) If the declared type of both operands of a dyadic arithmetic 00089 operator is exact numeric, then the declared type of the result is 00090 an implementation-defined exact numeric type, with precision and 00091 scale determined as follows: 00092 00093 a) Let S1 and S2 be the scale of the first and second operands 00094 respectively. 00095 b) The precision of the result of addition and subtraction is 00096 implementation-defined, and the scale is the maximum of S1 and S2. 00097 c) The precision of the result of multiplication is 00098 implementation-defined, and the scale is S1 + S2. 00099 d) The precision and scale of the result of division are 00100 implementation-defined. 00101 */ 00102 00103 #include <my_global.h> 00104 #include <m_ctype.h> 00105 #include <myisampack.h> 00106 #include <my_sys.h> /* for my_alloca */ 00107 #include <m_string.h> 00108 #include <decimal.h> 00109 00110 /* 00111 Internally decimal numbers are stored base 10^9 (see DIG_BASE below) 00112 So one variable of type decimal_digit_t is limited: 00113 00114 0 < decimal_digit <= DIG_MAX < DIG_BASE 00115 00116 in the struct st_decimal_t: 00117 00118 intg is the number of *decimal* digits (NOT number of decimal_digit_t's !) 00119 before the point 00120 frac - number of decimal digits after the point 00121 buf is an array of decimal_digit_t's 00122 len is the length of buf (length of allocated space) in decimal_digit_t's, 00123 not in bytes 00124 */ 00125 typedef decimal_digit_t dec1; 00126 typedef longlong dec2; 00127 00128 #define DIG_PER_DEC1 9 00129 #define DIG_MASK 100000000 00130 #define DIG_BASE 1000000000 00131 #define DIG_MAX (DIG_BASE-1) 00132 #define DIG_BASE2 ((dec2)DIG_BASE * (dec2)DIG_BASE) 00133 #define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1) 00134 static const dec1 powers10[DIG_PER_DEC1+1]={ 00135 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; 00136 static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4}; 00137 static const dec1 frac_max[DIG_PER_DEC1-1]={ 00138 900000000, 990000000, 999000000, 00139 999900000, 999990000, 999999000, 00140 999999900, 999999990 }; 00141 00142 #ifdef HAVE_purify 00143 #define sanity(d) DBUG_ASSERT((d)->len > 0) 00144 #else 00145 #define sanity(d) DBUG_ASSERT((d)->len >0 && ((d)->buf[0] | \ 00146 (d)->buf[(d)->len-1] | 1)) 00147 #endif 00148 00149 #define FIX_INTG_FRAC_ERROR(len, intg1, frac1, error) \ 00150 do \ 00151 { \ 00152 if (unlikely(intg1+frac1 > (len))) \ 00153 { \ 00154 if (unlikely(intg1 > (len))) \ 00155 { \ 00156 intg1=(len); \ 00157 frac1=0; \ 00158 error=E_DEC_OVERFLOW; \ 00159 } \ 00160 else \ 00161 { \ 00162 frac1=(len)-intg1; \ 00163 error=E_DEC_TRUNCATED; \ 00164 } \ 00165 } \ 00166 else \ 00167 error=E_DEC_OK; \ 00168 } while(0) 00169 00170 #define ADD(to, from1, from2, carry) /* assume carry <= 1 */ \ 00171 do \ 00172 { \ 00173 dec1 a=(from1)+(from2)+(carry); \ 00174 DBUG_ASSERT((carry) <= 1); \ 00175 if (((carry)= a >= DIG_BASE)) /* no division here! */ \ 00176 a-=DIG_BASE; \ 00177 (to)=a; \ 00178 } while(0) 00179 00180 #define ADD2(to, from1, from2, carry) \ 00181 do \ 00182 { \ 00183 dec2 a=((dec2)(from1))+(from2)+(carry); \ 00184 if (((carry)= a >= DIG_BASE)) \ 00185 a-=DIG_BASE; \ 00186 if (unlikely(a >= DIG_BASE)) \ 00187 { \ 00188 a-=DIG_BASE; \ 00189 carry++; \ 00190 } \ 00191 (to)=(dec1) a; \ 00192 } while(0) 00193 00194 #define SUB(to, from1, from2, carry) /* to=from1-from2 */ \ 00195 do \ 00196 { \ 00197 dec1 a=(from1)-(from2)-(carry); \ 00198 if (((carry)= a < 0)) \ 00199 a+=DIG_BASE; \ 00200 (to)=a; \ 00201 } while(0) 00202 00203 #define SUB2(to, from1, from2, carry) /* to=from1-from2 */ \ 00204 do \ 00205 { \ 00206 dec1 a=(from1)-(from2)-(carry); \ 00207 if (((carry)= a < 0)) \ 00208 a+=DIG_BASE; \ 00209 if (unlikely(a < 0)) \ 00210 { \ 00211 a+=DIG_BASE; \ 00212 carry++; \ 00213 } \ 00214 (to)=a; \ 00215 } while(0) 00216 00217 /* 00218 Get maximum value for given precision and scale 00219 00220 SYNOPSIS 00221 max_decimal() 00222 precision/scale - see decimal_bin_size() below 00223 to - decimal where where the result will be stored 00224 to->buf and to->len must be set. 00225 */ 00226 00227 void max_decimal(int precision, int frac, decimal_t *to) 00228 { 00229 int intpart; 00230 dec1 *buf= to->buf; 00231 DBUG_ASSERT(precision && precision >= frac); 00232 00233 to->sign= 0; 00234 if ((intpart= to->intg= (precision - frac))) 00235 { 00236 int firstdigits= intpart % DIG_PER_DEC1; 00237 if (firstdigits) 00238 *buf++= powers10[firstdigits] - 1; /* get 9 99 999 ... */ 00239 for(intpart/= DIG_PER_DEC1; intpart; intpart--) 00240 *buf++= DIG_MAX; 00241 } 00242 00243 if ((to->frac= frac)) 00244 { 00245 int lastdigits= frac % DIG_PER_DEC1; 00246 for(frac/= DIG_PER_DEC1; frac; frac--) 00247 *buf++= DIG_MAX; 00248 if (lastdigits) 00249 *buf= frac_max[lastdigits - 1]; 00250 } 00251 } 00252 00253 00254 static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result) 00255 { 00256 int intg= from->intg, i; 00257 dec1 *buf0= from->buf; 00258 i= ((intg - 1) % DIG_PER_DEC1) + 1; 00259 while (intg > 0 && *buf0 == 0) 00260 { 00261 intg-= i; 00262 i= DIG_PER_DEC1; 00263 buf0++; 00264 } 00265 if (intg > 0) 00266 { 00267 for (i= (intg - 1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ; 00268 DBUG_ASSERT(intg > 0); 00269 } 00270 else 00271 intg=0; 00272 *intg_result= intg; 00273 return buf0; 00274 } 00275 00276 00277 /* 00278 Count actual length of fraction part (without ending zeroes) 00279 00280 SYNOPSIS 00281 decimal_actual_fraction() 00282 from number for processing 00283 */ 00284 00285 int decimal_actual_fraction(decimal_t *from) 00286 { 00287 int frac= from->frac, i; 00288 dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1; 00289 00290 if (frac == 0) 00291 return 0; 00292 00293 i= ((frac - 1) % DIG_PER_DEC1 + 1); 00294 while (frac > 0 && *buf0 == 0) 00295 { 00296 frac-= i; 00297 i= DIG_PER_DEC1; 00298 buf0--; 00299 } 00300 if (frac > 0) 00301 { 00302 for (i= DIG_PER_DEC1 - ((frac - 1) % DIG_PER_DEC1); 00303 *buf0 % powers10[i++] == 0; 00304 frac--); 00305 } 00306 return frac; 00307 } 00308 00309 00310 /* 00311 Convert decimal to its printable string representation 00312 00313 SYNOPSIS 00314 decimal2string() 00315 from - value to convert 00316 to - points to buffer where string representation 00317 should be stored 00318 *to_len - in: size of to buffer 00319 out: length of the actually written string 00320 fixed_precision - 0 if representation can be variable length and 00321 fixed_decimals will not be checked in this case. 00322 Put number as with fixed point position with this 00323 number of digits (sign counted and decimal point is 00324 counted) 00325 fixed_decimals - number digits after point. 00326 filler - character to fill gaps in case of fixed_precision > 0 00327 00328 RETURN VALUE 00329 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW 00330 */ 00331 00332 int decimal2string(decimal_t *from, char *to, int *to_len, 00333 int fixed_precision, int fixed_decimals, 00334 char filler) 00335 { 00336 int len, intg, frac= from->frac, i, intg_len, frac_len, fill; 00337 /* number digits before decimal point */ 00338 int fixed_intg= (fixed_precision ? 00339 (fixed_precision - fixed_decimals) : 0); 00340 int error=E_DEC_OK; 00341 char *s=to; 00342 dec1 *buf, *buf0=from->buf, tmp; 00343 00344 DBUG_ASSERT(*to_len >= 2+from->sign); 00345 00346 /* removing leading zeroes */ 00347 buf0= remove_leading_zeroes(from, &intg); 00348 if (unlikely(intg+frac==0)) 00349 { 00350 intg=1; 00351 tmp=0; 00352 buf0=&tmp; 00353 } 00354 00355 if (!(intg_len= fixed_precision ? fixed_intg : intg)) 00356 intg_len= 1; 00357 frac_len= fixed_precision ? fixed_decimals : frac; 00358 len= from->sign + intg_len + test(frac) + frac_len; 00359 if (fixed_precision) 00360 { 00361 if (frac > fixed_decimals) 00362 { 00363 error= E_DEC_TRUNCATED; 00364 frac= fixed_decimals; 00365 } 00366 if (intg > fixed_intg) 00367 { 00368 error= E_DEC_OVERFLOW; 00369 intg= fixed_intg; 00370 } 00371 } 00372 else if (unlikely(len > --*to_len)) /* reserve one byte for \0 */ 00373 { 00374 int i=len-*to_len; 00375 error= (frac && i <= frac + 1) ? E_DEC_TRUNCATED : E_DEC_OVERFLOW; 00376 if (frac && i >= frac + 1) i--; 00377 if (i > frac) 00378 { 00379 intg-= i-frac; 00380 frac= 0; 00381 } 00382 else 00383 frac-=i; 00384 len= from->sign + intg_len + test(frac) + frac_len; 00385 } 00386 *to_len=len; 00387 s[len]=0; 00388 00389 if (from->sign) 00390 *s++='-'; 00391 00392 if (frac) 00393 { 00394 char *s1= s + intg_len; 00395 fill= frac_len - frac; 00396 buf=buf0+ROUND_UP(intg); 00397 *s1++='.'; 00398 for (; frac>0; frac-=DIG_PER_DEC1) 00399 { 00400 dec1 x=*buf++; 00401 for (i=min(frac, DIG_PER_DEC1); i; i--) 00402 { 00403 dec1 y=x/DIG_MASK; 00404 *s1++='0'+(uchar)y; 00405 x-=y*DIG_MASK; 00406 x*=10; 00407 } 00408 } 00409 for(; fill; fill--) 00410 *s1++=filler; 00411 } 00412 00413 fill= intg_len - intg; 00414 if (intg == 0) 00415 fill--; /* symbol 0 before digital point */ 00416 for(; fill; fill--) 00417 *s++=filler; 00418 if (intg) 00419 { 00420 s+=intg; 00421 for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1) 00422 { 00423 dec1 x=*--buf; 00424 for (i=min(intg, DIG_PER_DEC1); i; i--) 00425 { 00426 dec1 y=x/10; 00427 *--s='0'+(uchar)(x-y*10); 00428 x=y; 00429 } 00430 } 00431 } 00432 else 00433 *s= '0'; 00434 return error; 00435 } 00436 00437 00438 /* 00439 Return bounds of decimal digits in the number 00440 00441 SYNOPSIS 00442 digits_bounds() 00443 from - decimal number for processing 00444 start_result - index (from 0 ) of first decimal digits will 00445 be written by this address 00446 end_result - index of position just after last decimal digit 00447 be written by this address 00448 */ 00449 00450 static void digits_bounds(decimal_t *from, int *start_result, int *end_result) 00451 { 00452 int start, stop, i; 00453 dec1 *buf_beg= from->buf; 00454 dec1 *end= from->buf + ROUND_UP(from->intg) + ROUND_UP(from->frac); 00455 dec1 *buf_end= end - 1; 00456 00457 /* find non-zero digit from number begining */ 00458 while (buf_beg < end && *buf_beg == 0) 00459 buf_beg++; 00460 00461 if (buf_beg >= end) 00462 { 00463 /* it is zero */ 00464 *start_result= *end_result= 0; 00465 return; 00466 } 00467 00468 /* find non-zero decimal digit from number begining */ 00469 if (buf_beg == from->buf && from->intg) 00470 { 00471 start= DIG_PER_DEC1 - (i= ((from->intg-1) % DIG_PER_DEC1 + 1)); 00472 i--; 00473 } 00474 else 00475 { 00476 i= DIG_PER_DEC1 - 1; 00477 start= (int) ((buf_beg - from->buf) * DIG_PER_DEC1); 00478 } 00479 if (buf_beg < end) 00480 for (; *buf_beg < powers10[i--]; start++) ; 00481 *start_result= start; /* index of first decimal digit (from 0) */ 00482 00483 /* find non-zero digit at the end */ 00484 while (buf_end > buf_beg && *buf_end == 0) 00485 buf_end--; 00486 /* find non-zero decimal digit from the end */ 00487 if (buf_end == end - 1 && from->frac) 00488 { 00489 stop= (int) (((buf_end - from->buf) * DIG_PER_DEC1 + 00490 (i= ((from->frac - 1) % DIG_PER_DEC1 + 1)))); 00491 i= DIG_PER_DEC1 - i + 1; 00492 } 00493 else 00494 { 00495 stop= (int) ((buf_end - from->buf + 1) * DIG_PER_DEC1); 00496 i= 1; 00497 } 00498 for (; *buf_end % powers10[i++] == 0; stop--); 00499 *end_result= stop; /* index of position after last decimal digit (from 0) */ 00500 } 00501 00502 00503 /* 00504 Left shift for alignment of data in buffer 00505 00506 SYNOPSIS 00507 do_mini_left_shift() 00508 dec pointer to decimal number which have to be shifted 00509 shift number of decimal digits on which it should be shifted 00510 beg/end bounds of decimal digits (see digits_bounds()) 00511 00512 NOTE 00513 Result fitting in the buffer should be garanted. 00514 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) 00515 */ 00516 00517 void do_mini_left_shift(decimal_t *dec, int shift, int beg, int last) 00518 { 00519 dec1 *from= dec->buf + ROUND_UP(beg + 1) - 1; 00520 dec1 *end= dec->buf + ROUND_UP(last) - 1; 00521 int c_shift= DIG_PER_DEC1 - shift; 00522 DBUG_ASSERT(from >= dec->buf); 00523 DBUG_ASSERT(end < dec->buf + dec->len); 00524 if (beg % DIG_PER_DEC1 < shift) 00525 *(from - 1)= (*from) / powers10[c_shift]; 00526 for(; from < end; from++) 00527 *from= ((*from % powers10[c_shift]) * powers10[shift] + 00528 (*(from + 1)) / powers10[c_shift]); 00529 *from= (*from % powers10[c_shift]) * powers10[shift]; 00530 } 00531 00532 00533 /* 00534 Right shift for alignment of data in buffer 00535 00536 SYNOPSIS 00537 do_mini_left_shift() 00538 dec pointer to decimal number which have to be shifted 00539 shift number of decimal digits on which it should be shifted 00540 beg/end bounds of decimal digits (see digits_bounds()) 00541 00542 NOTE 00543 Result fitting in the buffer should be garanted. 00544 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) 00545 */ 00546 00547 void do_mini_right_shift(decimal_t *dec, int shift, int beg, int last) 00548 { 00549 dec1 *from= dec->buf + ROUND_UP(last) - 1; 00550 dec1 *end= dec->buf + ROUND_UP(beg + 1) - 1; 00551 int c_shift= DIG_PER_DEC1 - shift; 00552 DBUG_ASSERT(from < dec->buf + dec->len); 00553 DBUG_ASSERT(end >= dec->buf); 00554 if (DIG_PER_DEC1 - ((last - 1) % DIG_PER_DEC1 + 1) < shift) 00555 *(from + 1)= (*from % powers10[shift]) * powers10[c_shift]; 00556 for(; from > end; from--) 00557 *from= (*from / powers10[shift] + 00558 (*(from - 1) % powers10[shift]) * powers10[c_shift]); 00559 *from= *from / powers10[shift]; 00560 } 00561 00562 00563 /* 00564 Shift of decimal digits in given number (with rounding if it need) 00565 00566 SYNOPSIS 00567 decimal_shift() 00568 dec number to be shifted 00569 shift number of decimal positions 00570 shift > 0 means shift to left shift 00571 shift < 0 meand right shift 00572 NOTE 00573 In fact it is multipling on 10^shift. 00574 RETURN 00575 E_DEC_OK OK 00576 E_DEC_OVERFLOW operation lead to overflow, number is untoched 00577 E_DEC_TRUNCATED number was rounded to fit into buffer 00578 */ 00579 00580 int decimal_shift(decimal_t *dec, int shift) 00581 { 00582 /* index of first non zero digit (all indexes from 0) */ 00583 int beg; 00584 /* index of position after last decimal digit */ 00585 int end; 00586 /* index of digit position just after point */ 00587 int point= ROUND_UP(dec->intg) * DIG_PER_DEC1; 00588 /* new point position */ 00589 int new_point= point + shift; 00590 /* number of digits in result */ 00591 int digits_int, digits_frac; 00592 /* length of result and new fraction in big digits*/ 00593 int new_len, new_frac_len; 00594 /* return code */ 00595 int err= E_DEC_OK; 00596 int new_front; 00597 00598 if (shift == 0) 00599 return E_DEC_OK; 00600 00601 digits_bounds(dec, &beg, &end); 00602 00603 if (beg == end) 00604 { 00605 decimal_make_zero(dec); 00606 return E_DEC_OK; 00607 } 00608 00609 digits_int= new_point - beg; 00610 set_if_bigger(digits_int, 0); 00611 digits_frac= end - new_point; 00612 set_if_bigger(digits_frac, 0); 00613 00614 if ((new_len= ROUND_UP(digits_int) + (new_frac_len= ROUND_UP(digits_frac))) > 00615 dec->len) 00616 { 00617 int lack= new_len - dec->len; 00618 int diff; 00619 00620 if (new_frac_len < lack) 00621 return E_DEC_OVERFLOW; /* lack more then we have in fraction */ 00622 00623 /* cat off fraction part to allow new number to fit in our buffer */ 00624 err= E_DEC_TRUNCATED; 00625 new_frac_len-= lack; 00626 diff= digits_frac - (new_frac_len * DIG_PER_DEC1); 00627 /* Make rounding method as parameter? */ 00628 decimal_round(dec, dec, end - point - diff, HALF_UP); 00629 end-= diff; 00630 digits_frac= new_frac_len * DIG_PER_DEC1; 00631 00632 if (end <= beg) 00633 { 00634 /* 00635 we lost all digits (they will be shifted out of buffer), so we can 00636 just return 0 00637 */ 00638 decimal_make_zero(dec); 00639 return E_DEC_TRUNCATED; 00640 } 00641 } 00642 00643 if (shift % DIG_PER_DEC1) 00644 { 00645 int l_mini_shift, r_mini_shift, mini_shift; 00646 int do_left; 00647 /* 00648 Calculate left/right shift to align decimal digits inside our bug 00649 digits correctly 00650 */ 00651 if (shift > 0) 00652 { 00653 l_mini_shift= shift % DIG_PER_DEC1; 00654 r_mini_shift= DIG_PER_DEC1 - l_mini_shift; 00655 /* 00656 It is left shift so prefer left shift, but if we have not place from 00657 left, we have to have it from right, because we checked length of 00658 result 00659 */ 00660 do_left= l_mini_shift <= beg; 00661 DBUG_ASSERT(do_left || (dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); 00662 } 00663 else 00664 { 00665 r_mini_shift= (-shift) % DIG_PER_DEC1; 00666 l_mini_shift= DIG_PER_DEC1 - r_mini_shift; 00667 /* see comment above */ 00668 do_left= !((dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); 00669 DBUG_ASSERT(!do_left || l_mini_shift <= beg); 00670 } 00671 if (do_left) 00672 { 00673 do_mini_left_shift(dec, l_mini_shift, beg, end); 00674 mini_shift=- l_mini_shift; 00675 } 00676 else 00677 { 00678 do_mini_right_shift(dec, r_mini_shift, beg, end); 00679 mini_shift= r_mini_shift; 00680 } 00681 new_point+= mini_shift; 00682 /* 00683 If number is shifted and correctly aligned in buffer we can 00684 finish 00685 */ 00686 if (!(shift+= mini_shift) && (new_point - digits_int) < DIG_PER_DEC1) 00687 { 00688 dec->intg= digits_int; 00689 dec->frac= digits_frac; 00690 return err; /* already shifted as it should be */ 00691 } 00692 beg+= mini_shift; 00693 end+= mini_shift; 00694 } 00695 00696 /* if new 'decimal front' is in first digit, we do not need move digits */ 00697 if ((new_front= (new_point - digits_int)) >= DIG_PER_DEC1 || 00698 new_front < 0) 00699 { 00700 /* need to move digits */ 00701 int d_shift; 00702 dec1 *to, *barier; 00703 if (new_front > 0) 00704 { 00705 /* move left */ 00706 d_shift= new_front / DIG_PER_DEC1; 00707 to= dec->buf + (ROUND_UP(beg + 1) - 1 - d_shift); 00708 barier= dec->buf + (ROUND_UP(end) - 1 - d_shift); 00709 DBUG_ASSERT(to >= dec->buf); 00710 DBUG_ASSERT(barier + d_shift < dec->buf + dec->len); 00711 for(; to <= barier; to++) 00712 *to= *(to + d_shift); 00713 for(barier+= d_shift; to <= barier; to++) 00714 *to= 0; 00715 d_shift= -d_shift; 00716 } 00717 else 00718 { 00719 /* move right */ 00720 d_shift= (1 - new_front) / DIG_PER_DEC1; 00721 to= dec->buf + ROUND_UP(end) - 1 + d_shift; 00722 barier= dec->buf + ROUND_UP(beg + 1) - 1 + d_shift; 00723 DBUG_ASSERT(to < dec->buf + dec->len); 00724 DBUG_ASSERT(barier - d_shift >= dec->buf); 00725 for(; to >= barier; to--) 00726 *to= *(to - d_shift); 00727 for(barier-= d_shift; to >= barier; to--) 00728 *to= 0; 00729 } 00730 d_shift*= DIG_PER_DEC1; 00731 beg+= d_shift; 00732 end+= d_shift; 00733 new_point+= d_shift; 00734 } 00735 00736 /* 00737 If there are gaps then fill ren with 0. 00738 00739 Only one of following 'for' loops will work becouse beg <= end 00740 */ 00741 beg= ROUND_UP(beg + 1) - 1; 00742 end= ROUND_UP(end) - 1; 00743 DBUG_ASSERT(new_point >= 0); 00744 00745 /* We don't want negative new_point below */ 00746 if (new_point != 0) 00747 new_point= ROUND_UP(new_point) - 1; 00748 00749 if (new_point > end) 00750 { 00751 do 00752 { 00753 dec->buf[new_point]=0; 00754 } while (--new_point > end); 00755 } 00756 else 00757 { 00758 for (; new_point < beg; new_point++) 00759 dec->buf[new_point]= 0; 00760 } 00761 dec->intg= digits_int; 00762 dec->frac= digits_frac; 00763 return err; 00764 } 00765 00766 00767 /* 00768 Convert string to decimal 00769 00770 SYNOPSIS 00771 internal_str2decl() 00772 from - value to convert. Doesn't have to be \0 terminated! 00773 to - decimal where where the result will be stored 00774 to->buf and to->len must be set. 00775 end - Pointer to pointer to end of string. Will on return be 00776 set to the char after the last used character 00777 fixed - use to->intg, to->frac as limits for input number 00778 00779 NOTE 00780 to->intg and to->frac can be modified even when fixed=1 00781 (but only decreased, in this case) 00782 00783 RETURN VALUE 00784 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM 00785 In case of E_DEC_FATAL_ERROR *to is set to decimal zero 00786 (to make error handling easier) 00787 */ 00788 00789 int 00790 internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed) 00791 { 00792 const char *s= from, *s1, *endp, *end_of_string= *end; 00793 int i, intg, frac, error, intg1, frac1; 00794 dec1 x,*buf; 00795 sanity(to); 00796 00797 error= E_DEC_BAD_NUM; /* In case of bad number */ 00798 while (s < end_of_string && my_isspace(&my_charset_latin1, *s)) 00799 s++; 00800 if (s == end_of_string) 00801 goto fatal_error; 00802 00803 if ((to->sign= (*s == '-'))) 00804 s++; 00805 else if (*s == '+') 00806 s++; 00807 00808 s1=s; 00809 while (s < end_of_string && my_isdigit(&my_charset_latin1, *s)) 00810 s++; 00811 intg= (int) (s-s1); 00812 if (s < end_of_string && *s=='.') 00813 { 00814 endp= s+1; 00815 while (endp < end_of_string && my_isdigit(&my_charset_latin1, *endp)) 00816 endp++; 00817 frac= (int) (endp - s - 1); 00818 } 00819 else 00820 { 00821 frac= 0; 00822 endp= s; 00823 } 00824 00825 *end= (char*) endp; 00826 00827 if (frac+intg == 0) 00828 goto fatal_error; 00829 00830 error= 0; 00831 if (fixed) 00832 { 00833 if (frac > to->frac) 00834 { 00835 error=E_DEC_TRUNCATED; 00836 frac=to->frac; 00837 } 00838 if (intg > to->intg) 00839 { 00840 error=E_DEC_OVERFLOW; 00841 intg=to->intg; 00842 } 00843 intg1=ROUND_UP(intg); 00844 frac1=ROUND_UP(frac); 00845 if (intg1+frac1 > to->len) 00846 { 00847 error= E_DEC_OOM; 00848 goto fatal_error; 00849 } 00850 } 00851 else 00852 { 00853 intg1=ROUND_UP(intg); 00854 frac1=ROUND_UP(frac); 00855 FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error); 00856 if (unlikely(error)) 00857 { 00858 frac=frac1*DIG_PER_DEC1; 00859 if (error == E_DEC_OVERFLOW) 00860 intg=intg1*DIG_PER_DEC1; 00861 } 00862 } 00863 /* Error is guranteed to be set here */ 00864 to->intg=intg; 00865 to->frac=frac; 00866 00867 buf=to->buf+intg1; 00868 s1=s; 00869 00870 for (x=0, i=0; intg; intg--) 00871 { 00872 x+= (*--s - '0')*powers10[i]; 00873 00874 if (unlikely(++i == DIG_PER_DEC1)) 00875 { 00876 *--buf=x; 00877 x=0; 00878 i=0; 00879 } 00880 } 00881 if (i) 00882 *--buf=x; 00883 00884 buf=to->buf+intg1; 00885 for (x=0, i=0; frac; frac--) 00886 { 00887 x= (*++s1 - '0') + x*10; 00888 00889 if (unlikely(++i == DIG_PER_DEC1)) 00890 { 00891 *buf++=x; 00892 x=0; 00893 i=0; 00894 } 00895 } 00896 if (i) 00897 *buf=x*powers10[DIG_PER_DEC1-i]; 00898 00899 /* Handle exponent */ 00900 if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E')) 00901 { 00902 int str_error; 00903 longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error); 00904 00905 if (end_of_string != endp +1) /* If at least one digit */ 00906 { 00907 *end= (char*) end_of_string; 00908 if (str_error > 0) 00909 { 00910 error= E_DEC_BAD_NUM; 00911 goto fatal_error; 00912 } 00913 if (exp > INT_MAX/2 || (str_error == 0 && exp < 0)) 00914 { 00915 error= E_DEC_OVERFLOW; 00916 goto fatal_error; 00917 } 00918 if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) 00919 { 00920 error= E_DEC_TRUNCATED; 00921 goto fatal_error; 00922 } 00923 if (error != E_DEC_OVERFLOW) 00924 error= decimal_shift(to, (int) exp); 00925 } 00926 } 00927 return error; 00928 00929 fatal_error: 00930 decimal_make_zero(to); 00931 return error; 00932 } 00933 00934 00935 /* 00936 Convert decimal to double 00937 00938 SYNOPSIS 00939 decimal2double() 00940 from - value to convert 00941 to - result will be stored there 00942 00943 RETURN VALUE 00944 E_DEC_OK 00945 */ 00946 00947 int decimal2double(decimal_t *from, double *to) 00948 { 00949 double x=0, t=DIG_BASE; 00950 int intg, frac; 00951 dec1 *buf=from->buf; 00952 00953 for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1) 00954 x=x*DIG_BASE + *buf++; 00955 for (frac=from->frac; frac > 0; frac-=DIG_PER_DEC1, t*=DIG_BASE) 00956 x+=*buf++/t; 00957 *to=from->sign ? -x : x; 00958 return E_DEC_OK; 00959 } 00960 00961 /* 00962 Convert double to decimal 00963 00964 SYNOPSIS 00965 double2decimal() 00966 from - value to convert 00967 to - result will be stored there 00968 00969 RETURN VALUE 00970 E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED 00971 */ 00972 00973 int double2decimal(double from, decimal_t *to) 00974 { 00975 /* TODO: fix it, when we'll have dtoa */ 00976 char buff[400], *end; 00977 int length, res; 00978 DBUG_ENTER("double2decimal"); 00979 length= my_sprintf(buff, (buff, "%.16G", from)); 00980 DBUG_PRINT("info",("from: %g from_as_str: %s", from, buff)); 00981 end= buff+length; 00982 res= string2decimal(buff, to, &end); 00983 DBUG_PRINT("exit", ("res: %d", res)); 00984 DBUG_RETURN(res); 00985 } 00986 00987 00988 static int ull2dec(ulonglong from, decimal_t *to) 00989 { 00990 int intg1, error=E_DEC_OK; 00991 ulonglong x=from; 00992 dec1 *buf; 00993 00994 sanity(to); 00995 00996 for (intg1=1; from >= DIG_BASE; intg1++, from/=DIG_BASE); 00997 if (unlikely(intg1 > to->len)) 00998 { 00999 intg1=to->len; 01000 error=E_DEC_OVERFLOW; 01001 } 01002 to->frac=0; 01003 to->intg=intg1*DIG_PER_DEC1; 01004 01005 for (buf=to->buf+intg1; intg1; intg1--) 01006 { 01007 ulonglong y=x/DIG_BASE; 01008 *--buf=(dec1)(x-y*DIG_BASE); 01009 x=y; 01010 } 01011 return error; 01012 } 01013 01014 int ulonglong2decimal(ulonglong from, decimal_t *to) 01015 { 01016 to->sign=0; 01017 return ull2dec(from, to); 01018 } 01019 01020 int longlong2decimal(longlong from, decimal_t *to) 01021 { 01022 if ((to->sign= from < 0)) 01023 return ull2dec(-from, to); 01024 return ull2dec(from, to); 01025 } 01026 01027 int decimal2ulonglong(decimal_t *from, ulonglong *to) 01028 { 01029 dec1 *buf=from->buf; 01030 ulonglong x=0; 01031 int intg, frac; 01032 01033 if (from->sign) 01034 { 01035 *to=ULL(0); 01036 return E_DEC_OVERFLOW; 01037 } 01038 01039 for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1) 01040 { 01041 ulonglong y=x; 01042 x=x*DIG_BASE + *buf++; 01043 if (unlikely(y > ((ulonglong) ULONGLONG_MAX/DIG_BASE) || x < y)) 01044 { 01045 *to=y; 01046 return E_DEC_OVERFLOW; 01047 } 01048 } 01049 *to=x; 01050 for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1) 01051 if (*buf++) 01052 return E_DEC_TRUNCATED; 01053 return E_DEC_OK; 01054 } 01055 01056 int decimal2longlong(decimal_t *from, longlong *to) 01057 { 01058 dec1 *buf=from->buf; 01059 longlong x=0; 01060 int intg, frac; 01061 01062 for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1) 01063 { 01064 longlong y=x; 01065 /* 01066 Attention: trick! 01067 we're calculating -|from| instead of |from| here 01068 because |LONGLONG_MIN| > LONGLONG_MAX 01069 so we can convert -9223372036854775808 correctly 01070 */ 01071 x=x*DIG_BASE - *buf++; 01072 if (unlikely(y < (LONGLONG_MIN/DIG_BASE) || x > y)) 01073 { 01074 *to= from->sign ? y : -y; 01075 return E_DEC_OVERFLOW; 01076 } 01077 } 01078 /* boundary case: 9223372036854775808 */ 01079 if (unlikely(from->sign==0 && x == LONGLONG_MIN)) 01080 { 01081 *to= LONGLONG_MAX; 01082 return E_DEC_OVERFLOW; 01083 } 01084 01085 *to=from->sign ? x : -x; 01086 for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1) 01087 if (*buf++) 01088 return E_DEC_TRUNCATED; 01089 return E_DEC_OK; 01090 } 01091 01092 /* 01093 Convert decimal to its binary fixed-length representation 01094 two representations of the same length can be compared with memcmp 01095 with the correct -1/0/+1 result 01096 01097 SYNOPSIS 01098 decimal2bin() 01099 from - value to convert 01100 to - points to buffer where string representation should be stored 01101 precision/scale - see decimal_bin_size() below 01102 01103 NOTE 01104 the buffer is assumed to be of the size decimal_bin_size(precision, scale) 01105 01106 RETURN VALUE 01107 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW 01108 01109 DESCRIPTION 01110 for storage decimal numbers are converted to the "binary" format. 01111 01112 This format has the following properties: 01113 1. length of the binary representation depends on the {precision, scale} 01114 as provided by the caller and NOT on the intg/frac of the decimal to 01115 convert. 01116 2. binary representations of the same {precision, scale} can be compared 01117 with memcmp - with the same result as decimal_cmp() of the original 01118 decimals (not taking into account possible precision loss during 01119 conversion). 01120 01121 This binary format is as follows: 01122 1. First the number is converted to have a requested precision and scale. 01123 2. Every full DIG_PER_DEC1 digits of intg part are stored in 4 bytes 01124 as is 01125 3. The first intg % DIG_PER_DEC1 digits are stored in the reduced 01126 number of bytes (enough bytes to store this number of digits - 01127 see dig2bytes) 01128 4. same for frac - full decimal_digit_t's are stored as is, 01129 the last frac % DIG_PER_DEC1 digits - in the reduced number of bytes. 01130 5. If the number is negative - every byte is inversed. 01131 5. The very first bit of the resulting byte array is inverted (because 01132 memcmp compares unsigned bytes, see property 2 above) 01133 01134 Example: 01135 01136 1234567890.1234 01137 01138 internally is represented as 3 decimal_digit_t's 01139 01140 1 234567890 123400000 01141 01142 (assuming we want a binary representation with precision=14, scale=4) 01143 in hex it's 01144 01145 00-00-00-01 0D-FB-38-D2 07-5A-EF-40 01146 01147 now, middle decimal_digit_t is full - it stores 9 decimal digits. It goes 01148 into binary representation as is: 01149 01150 01151 ........... 0D-FB-38-D2 ............ 01152 01153 First decimal_digit_t has only one decimal digit. We can store one digit in 01154 one byte, no need to waste four: 01155 01156 01 0D-FB-38-D2 ............ 01157 01158 now, last digit. It's 123400000. We can store 1234 in two bytes: 01159 01160 01 0D-FB-38-D2 04-D2 01161 01162 So, we've packed 12 bytes number in 7 bytes. 01163 And now we invert the highest bit to get the final result: 01164 01165 81 0D FB 38 D2 04 D2 01166 01167 And for -1234567890.1234 it would be 01168 01169 7E F2 04 37 2D FB 2D 01170 */ 01171 int decimal2bin(decimal_t *from, char *to, int precision, int frac) 01172 { 01173 dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1; 01174 int error=E_DEC_OK, intg=precision-frac, 01175 isize1, intg1, intg1x, from_intg, 01176 intg0=intg/DIG_PER_DEC1, 01177 frac0=frac/DIG_PER_DEC1, 01178 intg0x=intg-intg0*DIG_PER_DEC1, 01179 frac0x=frac-frac0*DIG_PER_DEC1, 01180 frac1=from->frac/DIG_PER_DEC1, 01181 frac1x=from->frac-frac1*DIG_PER_DEC1, 01182 isize0=intg0*sizeof(dec1)+dig2bytes[intg0x], 01183 fsize0=frac0*sizeof(dec1)+dig2bytes[frac0x], 01184 fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x]; 01185 const int orig_isize0= isize0; 01186 const int orig_fsize0= fsize0; 01187 char *orig_to= to; 01188 01189 buf1= remove_leading_zeroes(from, &from_intg); 01190 01191 if (unlikely(from_intg+fsize1==0)) 01192 { 01193 mask=0; /* just in case */ 01194 intg=1; 01195 buf1=&mask; 01196 } 01197 01198 intg1=from_intg/DIG_PER_DEC1; 01199 intg1x=from_intg-intg1*DIG_PER_DEC1; 01200 isize1=intg1*sizeof(dec1)+dig2bytes[intg1x]; 01201 01202 if (intg < from_intg) 01203 { 01204 buf1+=intg1-intg0+(intg1x>0)-(intg0x>0); 01205 intg1=intg0; intg1x=intg0x; 01206 error=E_DEC_OVERFLOW; 01207 } 01208 else if (isize0 > isize1) 01209 { 01210 while (isize0-- > isize1) 01211 *to++= (char)mask; 01212 } 01213 if (fsize0 < fsize1) 01214 { 01215 frac1=frac0; frac1x=frac0x; 01216 error=E_DEC_TRUNCATED; 01217 } 01218 else if (fsize0 > fsize1 && frac1x) 01219 { 01220 if (frac0 == frac1) 01221 { 01222 frac1x=frac0x; 01223 fsize0= fsize1; 01224 } 01225 else 01226 { 01227 frac1++; 01228 frac1x=0; 01229 } 01230 } 01231 01232 /* intg1x part */ 01233 if (intg1x) 01234 { 01235 int i=dig2bytes[intg1x]; 01236 dec1 x=(*buf1++ % powers10[intg1x]) ^ mask; 01237 switch (i) 01238 { 01239 case 1: mi_int1store(to, x); break; 01240 case 2: mi_int2store(to, x); break; 01241 case 3: mi_int3store(to, x); break; 01242 case 4: mi_int4store(to, x); break; 01243 default: DBUG_ASSERT(0); 01244 } 01245 to+=i; 01246 } 01247 01248 /* intg1+frac1 part */ 01249 for (stop1=buf1+intg1+frac1; buf1 < stop1; to+=sizeof(dec1)) 01250 { 01251 dec1 x=*buf1++ ^ mask; 01252 DBUG_ASSERT(sizeof(dec1) == 4); 01253 mi_int4store(to, x); 01254 } 01255 01256 /* frac1x part */ 01257 if (frac1x) 01258 { 01259 dec1 x; 01260 int i=dig2bytes[frac1x], 01261 lim=(frac1 < frac0 ? DIG_PER_DEC1 : frac0x); 01262 while (frac1x < lim && dig2bytes[frac1x] == i) 01263 frac1x++; 01264 x=(*buf1 / powers10[DIG_PER_DEC1 - frac1x]) ^ mask; 01265 switch (i) 01266 { 01267 case 1: mi_int1store(to, x); break; 01268 case 2: mi_int2store(to, x); break; 01269 case 3: mi_int3store(to, x); break; 01270 case 4: mi_int4store(to, x); break; 01271 default: DBUG_ASSERT(0); 01272 } 01273 to+=i; 01274 } 01275 if (fsize0 > fsize1) 01276 { 01277 char *to_end= orig_to + orig_fsize0 + orig_isize0; 01278 01279 while (fsize0-- > fsize1 && to < to_end) 01280 *to++=(uchar)mask; 01281 } 01282 orig_to[0]^= 0x80; 01283 01284 /* Check that we have written the whole decimal and nothing more */ 01285 DBUG_ASSERT(to == orig_to + orig_fsize0 + orig_isize0); 01286 return error; 01287 } 01288 01289 /* 01290 Restores decimal from its binary fixed-length representation 01291 01292 SYNOPSIS 01293 bin2decimal() 01294 from - value to convert 01295 to - result 01296 precision/scale - see decimal_bin_size() below 01297 01298 NOTE 01299 see decimal2bin() 01300 the buffer is assumed to be of the size decimal_bin_size(precision, scale) 01301 01302 RETURN VALUE 01303 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW 01304 */ 01305 01306 int bin2decimal(char *from, decimal_t *to, int precision, int scale) 01307 { 01308 int error=E_DEC_OK, intg=precision-scale, 01309 intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1, 01310 intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1, 01311 intg1=intg0+(intg0x>0), frac1=frac0+(frac0x>0); 01312 dec1 *buf=to->buf, mask=(*from & 0x80) ? 0 : -1; 01313 char *stop; 01314 char *d_copy; 01315 int bin_size= decimal_bin_size(precision, scale); 01316 01317 sanity(to); 01318 d_copy= (char *)my_alloca(bin_size); 01319 memcpy(d_copy, from, bin_size); 01320 d_copy[0]^= 0x80; 01321 from= d_copy; 01322 01323 FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error); 01324 if (unlikely(error)) 01325 { 01326 if (intg1 < intg0+(intg0x>0)) 01327 { 01328 from+=dig2bytes[intg0x]+sizeof(dec1)*(intg0-intg1); 01329 frac0=frac0x=intg0x=0; 01330 intg0=intg1; 01331 } 01332 else 01333 { 01334 frac0x=0; 01335 frac0=frac1; 01336 } 01337 } 01338 01339 to->sign=(mask != 0); 01340 to->intg=intg0*DIG_PER_DEC1+intg0x; 01341 to->frac=frac0*DIG_PER_DEC1+frac0x; 01342 01343 if (intg0x) 01344 { 01345 int i=dig2bytes[intg0x]; 01346 dec1 x; 01347 switch (i) 01348 { 01349 case 1: x=mi_sint1korr(from); break; 01350 case 2: x=mi_sint2korr(from); break; 01351 case 3: x=mi_sint3korr(from); break; 01352 case 4: x=mi_sint4korr(from); break; 01353 default: DBUG_ASSERT(0); 01354 } 01355 from+=i; 01356 *buf=x ^ mask; 01357 if (((ulonglong)*buf) >= (ulonglong) powers10[intg0x+1]) 01358 goto err; 01359 if (buf > to->buf || *buf != 0) 01360 buf++; 01361 else 01362 to->intg-=intg0x; 01363 } 01364 for (stop=from+intg0*sizeof(dec1); from < stop; from+=sizeof(dec1)) 01365 { 01366 DBUG_ASSERT(sizeof(dec1) == 4); 01367 *buf=mi_sint4korr(from) ^ mask; 01368 if (((uint32)*buf) > DIG_MAX) 01369 goto err; 01370 if (buf > to->buf || *buf != 0) 01371 buf++; 01372 else 01373 to->intg-=DIG_PER_DEC1; 01374 } 01375 DBUG_ASSERT(to->intg >=0); 01376 for (stop=from+frac0*sizeof(dec1); from < stop; from+=sizeof(dec1)) 01377 { 01378 DBUG_ASSERT(sizeof(dec1) == 4); 01379 *buf=mi_sint4korr(from) ^ mask; 01380 if (((uint32)*buf) > DIG_MAX) 01381 goto err; 01382 buf++; 01383 } 01384 if (frac0x) 01385 { 01386 int i=dig2bytes[frac0x]; 01387 dec1 x; 01388 switch (i) 01389 { 01390 case 1: x=mi_sint1korr(from); break; 01391 case 2: x=mi_sint2korr(from); break; 01392 case 3: x=mi_sint3korr(from); break; 01393 case 4: x=mi_sint4korr(from); break; 01394 default: DBUG_ASSERT(0); 01395 } 01396 *buf=(x ^ mask) * powers10[DIG_PER_DEC1 - frac0x]; 01397 if (((uint32)*buf) > DIG_MAX) 01398 goto err; 01399 buf++; 01400 } 01401 my_afree(d_copy); 01402 return error; 01403 01404 err: 01405 my_afree(d_copy); 01406 decimal_make_zero(((decimal_t*) to)); 01407 return(E_DEC_BAD_NUM); 01408 } 01409 01410 /* 01411 Returns the size of array to hold a decimal with given precision and scale 01412 01413 RETURN VALUE 01414 size in dec1 01415 (multiply by sizeof(dec1) to get the size if bytes) 01416 */ 01417 01418 int decimal_size(int precision, int scale) 01419 { 01420 DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision); 01421 return ROUND_UP(precision-scale)+ROUND_UP(scale); 01422 } 01423 01424 /* 01425 Returns the size of array to hold a binary representation of a decimal 01426 01427 RETURN VALUE 01428 size in bytes 01429 */ 01430 01431 int decimal_bin_size(int precision, int scale) 01432 { 01433 int intg=precision-scale, 01434 intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1, 01435 intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1; 01436 01437 DBUG_ASSERT(scale >= 0 && precision > 0 && scale <= precision); 01438 return intg0*sizeof(dec1)+dig2bytes[intg0x]+ 01439 frac0*sizeof(dec1)+dig2bytes[frac0x]; 01440 } 01441 01442 /* 01443 Rounds the decimal to "scale" digits 01444 01445 SYNOPSIS 01446 decimal_round() 01447 from - decimal to round, 01448 to - result buffer. from==to is allowed 01449 scale - to what position to round. can be negative! 01450 mode - round to nearest even or truncate 01451 01452 NOTES 01453 scale can be negative ! 01454 one TRUNCATED error (line XXX below) isn't treated very logical :( 01455 01456 RETURN VALUE 01457 E_DEC_OK/E_DEC_TRUNCATED 01458 */ 01459 01460 int 01461 decimal_round(decimal_t *from, decimal_t *to, int scale, 01462 decimal_round_mode mode) 01463 { 01464 int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, 01465 frac1=ROUND_UP(from->frac), round_digit, 01466 intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len, 01467 intg1=ROUND_UP(from->intg + 01468 (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX))); 01469 dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; 01470 int first_dig; 01471 01472 sanity(to); 01473 01474 switch (mode) { 01475 case HALF_UP: 01476 case HALF_EVEN: round_digit=5; break; 01477 case CEILING: round_digit= from->sign ? 10 : 0; break; 01478 case FLOOR: round_digit= from->sign ? 0 : 10; break; 01479 case TRUNCATE: round_digit=10; break; 01480 default: DBUG_ASSERT(0); 01481 } 01482 01483 if (unlikely(frac0+intg0 > len)) 01484 { 01485 frac0=len-intg0; 01486 scale=frac0*DIG_PER_DEC1; 01487 error=E_DEC_TRUNCATED; 01488 } 01489 01490 if (scale+from->intg < 0) 01491 { 01492 decimal_make_zero(to); 01493 return E_DEC_OK; 01494 } 01495 01496 if (to != from || intg1>intg0) 01497 { 01498 dec1 *p0= buf0+intg0+max(frac1, frac0); 01499 dec1 *p1= buf1+intg1+max(frac1, frac0); 01500 01501 to->buf[0]= 0; 01502 while (buf0 < p0) 01503 *(--p1) = *(--p0); 01504 01505 intg0= intg1; 01506 buf0=to->buf; 01507 buf1=to->buf; 01508 to->sign=from->sign; 01509 to->intg=min(intg0, len)*DIG_PER_DEC1; 01510 } 01511 01512 if (frac0 > frac1) 01513 { 01514 buf1+=intg0+frac1; 01515 while (frac0-- > frac1) 01516 *buf1++=0; 01517 goto done; 01518 } 01519 01520 if (scale >= from->frac) 01521 goto done; /* nothing to do */ 01522 01523 buf0+=intg0+frac0-1; 01524 buf1+=intg0+frac0-1; 01525 if (scale == frac0*DIG_PER_DEC1) 01526 { 01527 int do_inc= FALSE; 01528 DBUG_ASSERT(frac0+intg0 >= 0); 01529 switch (round_digit) { 01530 case 0: 01531 { 01532 dec1 *p0= buf0 + (frac1-frac0); 01533 for (; p0 > buf0; p0--) 01534 { 01535 if (*p0) 01536 { 01537 do_inc= TRUE; 01538 break; 01539 } 01540 } 01541 break; 01542 } 01543 case 5: 01544 { 01545 x= buf0[1]/DIG_MASK; 01546 do_inc= (x>5) || ((x == 5) && 01547 (mode == HALF_UP || (frac0+intg0 > 0 && *buf0 & 1))); 01548 break; 01549 } 01550 default: 01551 break; 01552 } 01553 if (do_inc) 01554 { 01555 if (frac0+intg0>0) 01556 (*buf1)++; 01557 else 01558 *(++buf1)=DIG_BASE; 01559 } 01560 else if (frac0+intg0==0) 01561 { 01562 decimal_make_zero(to); 01563 return E_DEC_OK; 01564 } 01565 } 01566 else 01567 { 01568 /* TODO - fix this code as it won't work for CEILING mode */ 01569 int pos=frac0*DIG_PER_DEC1-scale-1; 01570 DBUG_ASSERT(frac0+intg0 > 0); 01571 x=*buf1 / powers10[pos]; 01572 y=x % 10; 01573 if (y > round_digit || 01574 (round_digit == 5 && y == 5 && (mode == HALF_UP || (x/10) & 1))) 01575 x+=10; 01576 *buf1=powers10[pos]*(x-y); 01577 } 01578 if (frac0 < 0) 01579 { 01580 dec1 *end=to->buf+intg0, *buf=buf1+1; 01581 while (buf < end) 01582 *buf++=0; 01583 } 01584 if (*buf1 >= DIG_BASE) 01585 { 01586 carry=1; 01587 *buf1-=DIG_BASE; 01588 while (carry && --buf1 >= to->buf) 01589 ADD(*buf1, *buf1, 0, carry); 01590 if (unlikely(carry)) 01591 { 01592 /* shifting the number to create space for new digit */ 01593 if (frac0+intg0 >= len) 01594 { 01595 frac0--; 01596 scale=frac0*DIG_PER_DEC1; 01597 error=E_DEC_TRUNCATED; /* XXX */ 01598 } 01599 for (buf1=to->buf+intg0+max(frac0,0); buf1 > to->buf; buf1--) 01600 { 01601 buf1[0]=buf1[-1]; 01602 } 01603 *buf1=1; 01604 to->intg++; 01605 } 01606 } 01607 else 01608 { 01609 for (;;) 01610 { 01611 if (likely(*buf1)) 01612 break; 01613 if (buf1-- == to->buf) 01614 { 01615 /* making 'zero' with the proper scale */ 01616 dec1 *p0= to->buf + frac0 + 1; 01617 to->intg=1; 01618 to->frac= max(scale, 0); 01619 to->sign= 0; 01620 for (buf1= to->buf; buf1<p0; buf1++) 01621 *buf1= 0; 01622 return E_DEC_OK; 01623 } 01624 } 01625 } 01626 01627 /* Here we check 999.9 -> 1000 case when we need to increase intg */ 01628 first_dig= to->intg % DIG_PER_DEC1; 01629 if (first_dig && (*buf1 >= powers10[first_dig])) 01630 to->intg++; 01631 01632 if (scale<0) 01633 scale=0; 01634 01635 done: 01636 to->frac=scale; 01637 return error; 01638 } 01639 01640 /* 01641 Returns the size of the result of the operation 01642 01643 SYNOPSIS 01644 decimal_result_size() 01645 from1 - operand of the unary operation or first operand of the 01646 binary operation 01647 from2 - second operand of the binary operation 01648 op - operation. one char '+', '-', '*', '/' are allowed 01649 others may be added later 01650 param - extra param to the operation. unused for '+', '-', '*' 01651 scale increment for '/' 01652 01653 NOTE 01654 returned valued may be larger than the actual buffer requred 01655 in the operation, as decimal_result_size, by design, operates on 01656 precision/scale values only and not on the actual decimal number 01657 01658 RETURN VALUE 01659 size of to->buf array in dec1 elements. to get size in bytes 01660 multiply by sizeof(dec1) 01661 */ 01662 01663 int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param) 01664 { 01665 switch (op) { 01666 case '-': 01667 return ROUND_UP(max(from1->intg, from2->intg)) + 01668 ROUND_UP(max(from1->frac, from2->frac)); 01669 case '+': 01670 return ROUND_UP(max(from1->intg, from2->intg)+1) + 01671 ROUND_UP(max(from1->frac, from2->frac)); 01672 case '*': 01673 return ROUND_UP(from1->intg+from2->intg)+ 01674 ROUND_UP(from1->frac)+ROUND_UP(from2->frac); 01675 case '/': 01676 return ROUND_UP(from1->intg+from2->intg+1+from1->frac+from2->frac+param); 01677 default: DBUG_ASSERT(0); 01678 } 01679 return -1; /* shut up the warning */ 01680 } 01681 01682 static int do_add(decimal_t *from1, decimal_t *from2, decimal_t *to) 01683 { 01684 int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), 01685 frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), 01686 frac0=max(frac1, frac2), intg0=max(intg1, intg2), error; 01687 dec1 *buf1, *buf2, *buf0, *stop, *stop2, x, carry; 01688 01689 sanity(to); 01690 01691 /* is there a need for extra word because of carry ? */ 01692 x=intg1 > intg2 ? from1->buf[0] : 01693 intg2 > intg1 ? from2->buf[0] : 01694 from1->buf[0] + from2->buf[0] ; 01695 if (unlikely(x > DIG_MAX-1)) /* yes, there is */ 01696 { 01697 intg0++; 01698 to->buf[0]=0; /* safety */ 01699 } 01700 01701 FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); 01702 if (unlikely(error == E_DEC_OVERFLOW)) 01703 { 01704 max_decimal(to->len * DIG_PER_DEC1, 0, to); 01705 return error; 01706 } 01707 01708 buf0=to->buf+intg0+frac0; 01709 01710 to->sign=from1->sign; 01711 to->frac=max(from1->frac, from2->frac); 01712 to->intg=intg0*DIG_PER_DEC1; 01713 if (unlikely(error)) 01714 { 01715 set_if_smaller(to->frac, frac0*DIG_PER_DEC1); 01716 set_if_smaller(frac1, frac0); 01717 set_if_smaller(frac2, frac0); 01718 set_if_smaller(intg1, intg0); 01719 set_if_smaller(intg2, intg0); 01720 } 01721 01722 /* part 1 - max(frac) ... min (frac) */ 01723 if (frac1 > frac2) 01724 { 01725 buf1=from1->buf+intg1+frac1; 01726 stop=from1->buf+intg1+frac2; 01727 buf2=from2->buf+intg2+frac2; 01728 stop2=from1->buf+(intg1 > intg2 ? intg1-intg2 : 0); 01729 } 01730 else 01731 { 01732 buf1=from2->buf+intg2+frac2; 01733 stop=from2->buf+intg2+frac1; 01734 buf2=from1->buf+intg1+frac1; 01735 stop2=from2->buf+(intg2 > intg1 ? intg2-intg1 : 0); 01736 } 01737 while (buf1 > stop) 01738 *--buf0=*--buf1; 01739 01740 /* part 2 - min(frac) ... min(intg) */ 01741 carry=0; 01742 while (buf1 > stop2) 01743 { 01744 ADD(*--buf0, *--buf1, *--buf2, carry); 01745 } 01746 01747 /* part 3 - min(intg) ... max(intg) */ 01748 buf1= intg1 > intg2 ? ((stop=from1->buf)+intg1-intg2) : 01749 ((stop=from2->buf)+intg2-intg1) ; 01750 while (buf1 > stop) 01751 { 01752 ADD(*--buf0, *--buf1, 0, carry); 01753 } 01754 01755 if (unlikely(carry)) 01756 *--buf0=1; 01757 DBUG_ASSERT(buf0 == to->buf || buf0 == to->buf+1); 01758 01759 return error; 01760 } 01761 01762 /* to=from1-from2. 01763 if to==0, return -1/0/+1 - the result of the comparison */ 01764 static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) 01765 { 01766 int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), 01767 frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac); 01768 int frac0=max(frac1, frac2), error; 01769 dec1 *buf1, *buf2, *buf0, *stop1, *stop2, *start1, *start2, carry=0; 01770 01771 /* let carry:=1 if from2 > from1 */ 01772 start1=buf1=from1->buf; stop1=buf1+intg1; 01773 start2=buf2=from2->buf; stop2=buf2+intg2; 01774 if (unlikely(*buf1 == 0)) 01775 { 01776 while (buf1 < stop1 && *buf1 == 0) 01777 buf1++; 01778 start1=buf1; 01779 intg1= (int) (stop1-buf1); 01780 } 01781 if (unlikely(*buf2 == 0)) 01782 { 01783 while (buf2 < stop2 && *buf2 == 0) 01784 buf2++; 01785 start2=buf2; 01786 intg2= (int) (stop2-buf2); 01787 } 01788 if (intg2 > intg1) 01789 carry=1; 01790 else if (intg2 == intg1) 01791 { 01792 dec1 *end1= stop1 + (frac1 - 1); 01793 dec1 *end2= stop2 + (frac2 - 1); 01794 while (unlikely((buf1 <= end1) && (*end1 == 0))) 01795 end1--; 01796 while (unlikely((buf2 <= end2) && (*end2 == 0))) 01797 end2--; 01798 frac1= (int) (end1 - stop1) + 1; 01799 frac2= (int) (end2 - stop2) + 1; 01800 while (buf1 <=end1 && buf2 <= end2 && *buf1 == *buf2) 01801 buf1++, buf2++; 01802 if (buf1 <= end1) 01803 { 01804 if (buf2 <= end2) 01805 carry= *buf2 > *buf1; 01806 else 01807 carry= 0; 01808 } 01809 else 01810 { 01811 if (buf2 <= end2) 01812 carry=1; 01813 else /* short-circuit everything: from1 == from2 */ 01814 { 01815 if (to == 0) /* decimal_cmp() */ 01816 return 0; 01817 decimal_make_zero(to); 01818 return E_DEC_OK; 01819 } 01820 } 01821 } 01822 01823 if (to == 0) /* decimal_cmp() */ 01824 return carry == from1->sign ? 1 : -1; 01825 01826 sanity(to); 01827 01828 to->sign=from1->sign; 01829 01830 /* ensure that always from1 > from2 (and intg1 >= intg2) */ 01831 if (carry) 01832 { 01833 swap_variables(decimal_t *,from1,from1); 01834 swap_variables(dec1 *,start1, start2); 01835 swap_variables(int,intg1,intg2); 01836 swap_variables(int,frac1,frac2); 01837 to->sign= 1 - to->sign; 01838 } 01839 01840 FIX_INTG_FRAC_ERROR(to->len, intg1, frac0, error); 01841 buf0=to->buf+intg1+frac0; 01842 01843 to->frac=max(from1->frac, from2->frac); 01844 to->intg=intg1*DIG_PER_DEC1; 01845 if (unlikely(error)) 01846 { 01847 set_if_smaller(to->frac, frac0*DIG_PER_DEC1); 01848 set_if_smaller(frac1, frac0); 01849 set_if_smaller(frac2, frac0); 01850 set_if_smaller(intg2, intg1); 01851 } 01852 carry=0; 01853 01854 /* part 1 - max(frac) ... min (frac) */ 01855 if (frac1 > frac2) 01856 { 01857 buf1=start1+intg1+frac1; 01858 stop1=start1+intg1+frac2; 01859 buf2=start2+intg2+frac2; 01860 while (frac0-- > frac1) 01861 *--buf0=0; 01862 while (buf1 > stop1) 01863 *--buf0=*--buf1; 01864 } 01865 else 01866 { 01867 buf1=start1+intg1+frac1; 01868 buf2=start2+intg2+frac2; 01869 stop2=start2+intg2+frac1; 01870 while (frac0-- > frac2) 01871 *--buf0=0; 01872 while (buf2 > stop2) 01873 { 01874 SUB(*--buf0, 0, *--buf2, carry); 01875 } 01876 } 01877 01878 /* part 2 - min(frac) ... intg2 */ 01879 while (buf2 > start2) 01880 { 01881 SUB(*--buf0, *--buf1, *--buf2, carry); 01882 } 01883 01884 /* part 3 - intg2 ... intg1 */ 01885 while (carry && buf1 > start1) 01886 { 01887 SUB(*--buf0, *--buf1, 0, carry); 01888 } 01889 01890 while (buf1 > start1) 01891 *--buf0=*--buf1; 01892 01893 while (buf0 > to->buf) 01894 *--buf0=0; 01895 01896 return error; 01897 } 01898 01899 int decimal_intg(decimal_t *from) 01900 { 01901 int res; 01902 dec1 *tmp_res; 01903 tmp_res= remove_leading_zeroes(from, &res); 01904 return res; 01905 } 01906 01907 int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to) 01908 { 01909 if (likely(from1->sign == from2->sign)) 01910 return do_add(from1, from2, to); 01911 return do_sub(from1, from2, to); 01912 } 01913 01914 int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) 01915 { 01916 if (likely(from1->sign == from2->sign)) 01917 return do_sub(from1, from2, to); 01918 return do_add(from1, from2, to); 01919 } 01920 01921 int decimal_cmp(decimal_t *from1, decimal_t *from2) 01922 { 01923 if (likely(from1->sign == from2->sign)) 01924 return do_sub(from1, from2, 0); 01925 return from1->sign > from2->sign ? -1 : 1; 01926 } 01927 01928 int decimal_is_zero(decimal_t *from) 01929 { 01930 dec1 *buf1=from->buf, 01931 *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac); 01932 while (buf1 < end) 01933 if (*buf1++) 01934 return 0; 01935 return 1; 01936 } 01937 01938 /* 01939 multiply two decimals 01940 01941 SYNOPSIS 01942 decimal_mul() 01943 from1, from2 - factors 01944 to - product 01945 01946 RETURN VALUE 01947 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW; 01948 01949 NOTES 01950 in this implementation, with sizeof(dec1)=4 we have DIG_PER_DEC1=9, 01951 and 63-digit number will take only 7 dec1 words (basically a 7-digit 01952 "base 999999999" number). Thus there's no need in fast multiplication 01953 algorithms, 7-digit numbers can be multiplied with a naive O(n*n) 01954 method. 01955 01956 XXX if this library is to be used with huge numbers of thousands of 01957 digits, fast multiplication must be implemented. 01958 */ 01959 int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) 01960 { 01961 int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), 01962 frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), 01963 intg0=ROUND_UP(from1->intg+from2->intg), 01964 frac0=frac1+frac2, error, i, j, d_to_move; 01965 dec1 *buf1=from1->buf+intg1, *buf2=from2->buf+intg2, *buf0, 01966 *start2, *stop2, *stop1, *start0, carry; 01967 01968 sanity(to); 01969 01970 i=intg0; 01971 j=frac0; 01972 FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); 01973 to->sign=from1->sign != from2->sign; 01974 to->frac=from1->frac+from2->frac; 01975 to->intg=intg0*DIG_PER_DEC1; 01976 01977 if (unlikely(error)) 01978 { 01979 set_if_smaller(to->frac, frac0*DIG_PER_DEC1); 01980 set_if_smaller(to->intg, intg0*DIG_PER_DEC1); 01981 if (unlikely(i > intg0)) 01982 { 01983 i-=intg0; 01984 j=i >> 1; 01985 intg1-= j; 01986 intg2-=i-j; 01987 frac1=frac2=0; /* frac0 is already 0 here */ 01988 } 01989 else 01990 { 01991 j-=frac0; 01992 i=j >> 1; 01993 frac1-= i; 01994 frac2-=j-i; 01995 } 01996 } 01997 start0=to->buf+intg0+frac0-1; 01998 start2=buf2+frac2-1; 01999 stop1=buf1-intg1; 02000 stop2=buf2-intg2; 02001 02002 bzero(to->buf, (intg0+frac0)*sizeof(dec1)); 02003 02004 for (buf1+=frac1-1; buf1 >= stop1; buf1--, start0--) 02005 { 02006 carry=0; 02007 for (buf0=start0, buf2=start2; buf2 >= stop2; buf2--, buf0--) 02008 { 02009 dec1 hi, lo; 02010 dec2 p= ((dec2)*buf1) * ((dec2)*buf2); 02011 hi=(dec1)(p/DIG_BASE); 02012 lo=(dec1)(p-((dec2)hi)*DIG_BASE); 02013 ADD2(*buf0, *buf0, lo, carry); 02014 carry+=hi; 02015 } 02016 if (carry) 02017 { 02018 if (buf0 < to->buf) 02019 return E_DEC_OVERFLOW; 02020 ADD2(*buf0, *buf0, 0, carry); 02021 } 02022 for (buf0--; carry; buf0--) 02023 { 02024 if (buf0 < to->buf) 02025 return E_DEC_OVERFLOW; 02026 ADD(*buf0, *buf0, 0, carry); 02027 } 02028 } 02029 02030 /* Now we have to check for -0.000 case */ 02031 if (to->sign) 02032 { 02033 dec1 *buf= to->buf; 02034 dec1 *end= to->buf + intg0 + frac0; 02035 DBUG_ASSERT(buf != end); 02036 for (;;) 02037 { 02038 if (*buf) 02039 break; 02040 if (++buf == end) 02041 { 02042 /* We got decimal zero */ 02043 decimal_make_zero(to); 02044 break; 02045 } 02046 } 02047 } 02048 buf1= to->buf; 02049 d_to_move= intg0 + ROUND_UP(to->frac); 02050 while (!*buf1 && (to->intg > DIG_PER_DEC1)) 02051 { 02052 buf1++; 02053 to->intg-= DIG_PER_DEC1; 02054 d_to_move--; 02055 } 02056 if (to->buf < buf1) 02057 { 02058 dec1 *cur_d= to->buf; 02059 for (; d_to_move--; cur_d++, buf1++) 02060 *cur_d= *buf1; 02061 } 02062 return error; 02063 } 02064 02065 /* 02066 naive division algorithm (Knuth's Algorithm D in 4.3.1) - 02067 it's ok for short numbers 02068 also we're using alloca() to allocate a temporary buffer 02069 02070 XXX if this library is to be used with huge numbers of thousands of 02071 digits, fast division must be implemented and alloca should be 02072 changed to malloc (or at least fallback to malloc if alloca() fails) 02073 but then, decimal_mul() should be rewritten too :( 02074 */ 02075 static int do_div_mod(decimal_t *from1, decimal_t *from2, 02076 decimal_t *to, decimal_t *mod, int scale_incr) 02077 { 02078 int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1, 02079 frac2=ROUND_UP(from2->frac)*DIG_PER_DEC1, prec2=from2->intg+frac2, 02080 error, i, intg0, frac0, len1, len2, dintg, div=(!mod); 02081 dec1 *buf0, *buf1=from1->buf, *buf2=from2->buf, *tmp1, 02082 *start2, *stop2, *stop1, *stop0, norm2, carry, *start1, dcarry; 02083 dec2 norm_factor, x, guess, y; 02084 02085 LINT_INIT(error); 02086 02087 if (mod) 02088 to=mod; 02089 02090 sanity(to); 02091 02092 /* removing all the leading zeroes */ 02093 i= ((prec2 - 1) % DIG_PER_DEC1) + 1; 02094 while (prec2 > 0 && *buf2 == 0) 02095 { 02096 prec2-= i; 02097 i= DIG_PER_DEC1; 02098 buf2++; 02099 } 02100 if (prec2 <= 0) /* short-circuit everything: from2 == 0 */ 02101 return E_DEC_DIV_ZERO; 02102 for (i= (prec2 - 1) % DIG_PER_DEC1; *buf2 < powers10[i--]; prec2--) ; 02103 DBUG_ASSERT(prec2 > 0); 02104 02105 i=((prec1-1) % DIG_PER_DEC1)+1; 02106 while (prec1 > 0 && *buf1 == 0) 02107 { 02108 prec1-=i; 02109 i=DIG_PER_DEC1; 02110 buf1++; 02111 } 02112 if (prec1 <= 0) 02113 { /* short-circuit everything: from1 == 0 */ 02114 decimal_make_zero(to); 02115 return E_DEC_OK; 02116 } 02117 for (i=(prec1-1) % DIG_PER_DEC1; *buf1 < powers10[i--]; prec1--) ; 02118 DBUG_ASSERT(prec1 > 0); 02119 02120 /* let's fix scale_incr, taking into account frac1,frac2 increase */ 02121 if ((scale_incr-= frac1 - from1->frac + frac2 - from2->frac) < 0) 02122 scale_incr=0; 02123 02124 dintg=(prec1-frac1)-(prec2-frac2)+(*buf1 >= *buf2); 02125 if (dintg < 0) 02126 { 02127 dintg/=DIG_PER_DEC1; 02128 intg0=0; 02129 } 02130 else 02131 intg0=ROUND_UP(dintg); 02132 if (mod) 02133 { 02134 /* we're calculating N1 % N2. 02135 The result will have 02136 frac=max(frac1, frac2), as for subtraction 02137 intg=intg2 02138 */ 02139 to->sign=from1->sign; 02140 to->frac=max(from1->frac, from2->frac); 02141 frac0=0; 02142 } 02143 else 02144 { 02145 /* 02146 we're calculating N1/N2. N1 is in the buf1, has prec1 digits 02147 N2 is in the buf2, has prec2 digits. Scales are frac1 and 02148 frac2 accordingly. 02149 Thus, the result will have 02150 frac = ROUND_UP(frac1+frac2+scale_incr) 02151 and 02152 intg = (prec1-frac1) - (prec2-frac2) + 1 02153 prec = intg+frac 02154 */ 02155 frac0=ROUND_UP(frac1+frac2+scale_incr); 02156 FIX_INTG_FRAC_ERROR(to->len, intg0, frac0, error); 02157 to->sign=from1->sign != from2->sign; 02158 to->intg=intg0*DIG_PER_DEC1; 02159 to->frac=frac0*DIG_PER_DEC1; 02160 } 02161 buf0=to->buf; 02162 stop0=buf0+intg0+frac0; 02163 if (likely(div)) 02164 while (dintg++ < 0) 02165 *buf0++=0; 02166 02167 len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1; 02168 set_if_bigger(len1, 3); 02169 if (!(tmp1=(dec1 *)my_alloca(len1*sizeof(dec1)))) 02170 return E_DEC_OOM; 02171 memcpy(tmp1, buf1, i*sizeof(dec1)); 02172 bzero(tmp1+i, (len1-i)*sizeof(dec1)); 02173 02174 start1=tmp1; 02175 stop1=start1+len1; 02176 start2=buf2; 02177 stop2=buf2+ROUND_UP(prec2)-1; 02178 02179 /* removing end zeroes */ 02180 while (*stop2 == 0 && stop2 >= start2) 02181 stop2--; 02182 len2= (int) (stop2++ - start2); 02183 02184 /* 02185 calculating norm2 (normalized *start2) - we need *start2 to be large 02186 (at least > DIG_BASE/2), but unlike Knuth's Alg. D we don't want to 02187 normalize input numbers (as we don't make a copy of the divisor). 02188 Thus we normalize first dec1 of buf2 only, and we'll normalize *start1 02189 on the fly for the purpose of guesstimation only. 02190 It's also faster, as we're saving on normalization of buf2 02191 */ 02192 norm_factor=DIG_BASE/(*start2+1); 02193 norm2=(dec1)(norm_factor*start2[0]); 02194 if (likely(len2>0)) 02195 norm2+=(dec1)(norm_factor*start2[1]/DIG_BASE); 02196 02197 if (*start1 < *start2) 02198 dcarry=*start1++; 02199 else 02200 dcarry=0; 02201 02202 /* main loop */ 02203 for (; buf0 < stop0; buf0++) 02204 { 02205 /* short-circuit, if possible */ 02206 if (unlikely(dcarry == 0 && *start1 < *start2)) 02207 guess=0; 02208 else 02209 { 02210 /* D3: make a guess */ 02211 x=start1[0]+((dec2)dcarry)*DIG_BASE; 02212 y=start1[1]; 02213 guess=(norm_factor*x+norm_factor*y/DIG_BASE)/norm2; 02214 if (unlikely(guess >= DIG_BASE)) 02215 guess=DIG_BASE-1; 02216 if (likely(len2>0)) 02217 { 02218 /* hmm, this is a suspicious trick - I removed normalization here */ 02219 if (start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y) 02220 guess--; 02221 if (unlikely(start2[1]*guess > (x-guess*start2[0])*DIG_BASE+y)) 02222 guess--; 02223 DBUG_ASSERT(start2[1]*guess <= (x-guess*start2[0])*DIG_BASE+y); 02224 } 02225 02226 /* D4: multiply and subtract */ 02227 buf2=stop2; 02228 buf1=start1+len2; 02229 DBUG_ASSERT(buf1 < stop1); 02230 for (carry=0; buf2 > start2; buf1--) 02231 { 02232 dec1 hi, lo; 02233 x=guess * (*--buf2); 02234 hi=(dec1)(x/DIG_BASE); 02235 lo=(dec1)(x-((dec2)hi)*DIG_BASE); 02236 SUB2(*buf1, *buf1, lo, carry); 02237 carry+=hi; 02238 } 02239 carry= dcarry < carry; 02240 02241 /* D5: check the remainder */ 02242 if (unlikely(carry)) 02243 { 02244 /* D6: correct the guess */ 02245 guess--; 02246 buf2=stop2; 02247 buf1=start1+len2; 02248 for (carry=0; buf2 > start2; buf1--) 02249 { 02250 ADD(*buf1, *buf1, *--buf2, carry); 02251 } 02252 } 02253 } 02254 if (likely(div)) 02255 *buf0=(dec1)guess; 02256 dcarry= *start1; 02257 start1++; 02258 } 02259 if (mod) 02260 { 02261 /* 02262 now the result is in tmp1, it has 02263 intg=prec1-frac1 02264 frac=max(frac1, frac2)=to->frac 02265 */ 02266 if (dcarry) 02267 *--start1=dcarry; 02268 buf0=to->buf; 02269 intg0=(int) (ROUND_UP(prec1-frac1)-(start1-tmp1)); 02270 frac0=ROUND_UP(to->frac); 02271 error=E_DEC_OK; 02272 if (unlikely(frac0==0 && intg0==0)) 02273 { 02274 decimal_make_zero(to); 02275 goto done; 02276 } 02277 if (intg0<=0) 02278 { 02279 if (unlikely(-intg0 >= to->len)) 02280 { 02281 decimal_make_zero(to); 02282 error=E_DEC_TRUNCATED; 02283 goto done; 02284 } 02285 stop1=start1+frac0; 02286 frac0+=intg0; 02287 to->intg=0; 02288 while (intg0++ < 0) 02289 *buf0++=0; 02290 } 02291 else 02292 { 02293 if (unlikely(intg0 > to->len)) 02294 { 02295 frac0=0; 02296 intg0=to->len; 02297 error=E_DEC_OVERFLOW; 02298 goto done; 02299 } 02300 DBUG_ASSERT(intg0 <= ROUND_UP(from2->intg)); 02301 stop1=start1+frac0+intg0; 02302 to->intg=min(intg0*DIG_PER_DEC1, from2->intg); 02303 } 02304 if (unlikely(intg0+frac0 > to->len)) 02305 { 02306 stop1-=to->len-frac0-intg0; 02307 frac0=to->len-intg0; 02308 to->frac=frac0*DIG_PER_DEC1; 02309 error=E_DEC_TRUNCATED; 02310 } 02311 while (start1 < stop1) 02312 *buf0++=*start1++; 02313 } 02314 done: 02315 my_afree(tmp1); 02316 return error; 02317 } 02318 02319 /* 02320 division of two decimals 02321 02322 SYNOPSIS 02323 decimal_div() 02324 from1 - dividend 02325 from2 - divisor 02326 to - quotient 02327 02328 RETURN VALUE 02329 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO; 02330 02331 NOTES 02332 see do_div_mod() 02333 */ 02334 02335 int 02336 decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, int scale_incr) 02337 { 02338 return do_div_mod(from1, from2, to, 0, scale_incr); 02339 } 02340 02341 /* 02342 modulus 02343 02344 SYNOPSIS 02345 decimal_mod() 02346 from1 - dividend 02347 from2 - divisor 02348 to - modulus 02349 02350 RETURN VALUE 02351 E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO; 02352 02353 NOTES 02354 see do_div_mod() 02355 02356 DESCRIPTION 02357 the modulus R in R = M mod N 02358 02359 is defined as 02360 02361 0 <= |R| < |M| 02362 sign R == sign M 02363 R = M - k*N, where k is integer 02364 02365 thus, there's no requirement for M or N to be integers 02366 */ 02367 02368 int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to) 02369 { 02370 return do_div_mod(from1, from2, 0, to, 0); 02371 } 02372 02373 #ifdef MAIN 02374 02375 int full= 0; 02376 decimal_t a, b, c; 02377 char buf1[100], buf2[100], buf3[100]; 02378 02379 void dump_decimal(decimal_t *d) 02380 { 02381 int i; 02382 printf("/* intg=%d, frac=%d, sign=%d, buf[]={", d->intg, d->frac, d->sign); 02383 for (i=0; i < ROUND_UP(d->frac)+ROUND_UP(d->intg)-1; i++) 02384 printf("%09d, ", d->buf[i]); 02385 printf("%09d} */ ", d->buf[i]); 02386 } 02387 02388 02389 void check_result_code(int actual, int want) 02390 { 02391 if (actual != want) 02392 { 02393 printf("\n^^^^^^^^^^^^^ must return %d\n", want); 02394 exit(1); 02395 } 02396 } 02397 02398 02399 void print_decimal(decimal_t *d, const char *orig, int actual, int want) 02400 { 02401 char s[100]; 02402 int slen=sizeof(s); 02403 02404 if (full) dump_decimal(d); 02405 decimal2string(d, s, &slen, 0, 0, 0); 02406 printf("'%s'", s); 02407 check_result_code(actual, want); 02408 if (orig && strcmp(orig, s)) 02409 { 02410 printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); 02411 exit(1); 02412 } 02413 } 02414 02415 void test_d2s() 02416 { 02417 char s[100]; 02418 int slen, res; 02419 02420 /***********************************/ 02421 printf("==== decimal2string ====\n"); 02422 a.buf[0]=12345; a.intg=5; a.frac=0; a.sign=0; 02423 slen=sizeof(s); 02424 res=decimal2string(&a, s, &slen, 0, 0, 0); 02425 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02426 02427 a.buf[1]=987000000; a.frac=3; 02428 slen=sizeof(s); 02429 res=decimal2string(&a, s, &slen, 0, 0, 0); 02430 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02431 02432 a.sign=1; 02433 slen=sizeof(s); 02434 res=decimal2string(&a, s, &slen, 0, 0, 0); 02435 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02436 02437 slen=8; 02438 res=decimal2string(&a, s, &slen, 0, 0, 0); 02439 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02440 02441 slen=5; 02442 res=decimal2string(&a, s, &slen, 0, 0, 0); 02443 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02444 02445 a.buf[0]=987000000; a.frac=3; a.intg=0; 02446 slen=sizeof(s); 02447 res=decimal2string(&a, s, &slen, 0, 0, 0); 02448 dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); 02449 } 02450 02451 void test_s2d(const char *s, const char *orig, int ex) 02452 { 02453 char s1[100], *end; 02454 int res; 02455 sprintf(s1, "'%s'", s); 02456 end= strend(s); 02457 printf("len=%2d %-30s => res=%d ", a.len, s1, 02458 (res= string2decimal(s, &a, &end))); 02459 print_decimal(&a, orig, res, ex); 02460 printf("\n"); 02461 } 02462 02463 void test_d2f(const char *s, int ex) 02464 { 02465 char s1[100], *end; 02466 double x; 02467 int res; 02468 02469 sprintf(s1, "'%s'", s); 02470 end= strend(s); 02471 string2decimal(s, &a, &end); 02472 res=decimal2double(&a, &x); 02473 if (full) dump_decimal(&a); 02474 printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x); 02475 check_result_code(res, ex); 02476 } 02477 02478 void test_d2b2d(const char *str, int p, int s, const char *orig, int ex) 02479 { 02480 char s1[100], buf[100], *end; 02481 int res, i, size=decimal_bin_size(p, s); 02482 02483 sprintf(s1, "'%s'", str); 02484 end= strend(str); 02485 string2decimal(str, &a, &end); 02486 res=decimal2bin(&a, buf, p, s); 02487 printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size); 02488 if (full) 02489 { 02490 printf("0x"); 02491 for (i=0; i < size; i++) 02492 printf("%02x", ((uchar *)buf)[i]); 02493 } 02494 res=bin2decimal(buf, &a, p, s); 02495 printf(" => res=%d ", res); 02496 print_decimal(&a, orig, res, ex); 02497 printf("\n"); 02498 } 02499 02500 void test_f2d(double from, int ex) 02501 { 02502 int res; 02503 02504 res=double2decimal(from, &a); 02505 printf("%-40.*f => res=%d ", DBL_DIG-2, from, res); 02506 print_decimal(&a, 0, res, ex); 02507 printf("\n"); 02508 } 02509 02510 void test_ull2d(ulonglong from, const char *orig, int ex) 02511 { 02512 char s[100]; 02513 int res; 02514 02515 res=ulonglong2decimal(from, &a); 02516 longlong10_to_str(from,s,10); 02517 printf("%-40s => res=%d ", s, res); 02518 print_decimal(&a, orig, res, ex); 02519 printf("\n"); 02520 } 02521 02522 void test_ll2d(longlong from, const char *orig, int ex) 02523 { 02524 char s[100]; 02525 int res; 02526 02527 res=longlong2decimal(from, &a); 02528 longlong10_to_str(from,s,-10); 02529 printf("%-40s => res=%d ", s, res); 02530 print_decimal(&a, orig, res, ex); 02531 printf("\n"); 02532 } 02533 02534 void test_d2ull(const char *s, const char *orig, int ex) 02535 { 02536 char s1[100], *end; 02537 ulonglong x; 02538 int res; 02539 02540 end= strend(s); 02541 string2decimal(s, &a, &end); 02542 res=decimal2ulonglong(&a, &x); 02543 if (full) dump_decimal(&a); 02544 longlong10_to_str(x,s1,10); 02545 printf("%-40s => res=%d %s\n", s, res, s1); 02546 check_result_code(res, ex); 02547 if (orig && strcmp(orig, s1)) 02548 { 02549 printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); 02550 exit(1); 02551 } 02552 } 02553 02554 void test_d2ll(const char *s, const char *orig, int ex) 02555 { 02556 char s1[100], *end; 02557 longlong x; 02558 int res; 02559 02560 end= strend(s); 02561 string2decimal(s, &a, &end); 02562 res=decimal2longlong(&a, &x); 02563 if (full) dump_decimal(&a); 02564 longlong10_to_str(x,s1,-10); 02565 printf("%-40s => res=%d %s\n", s, res, s1); 02566 check_result_code(res, ex); 02567 if (orig && strcmp(orig, s1)) 02568 { 02569 printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); 02570 exit(1); 02571 } 02572 } 02573 02574 void test_da(const char *s1, const char *s2, const char *orig, int ex) 02575 { 02576 char s[100], *end; 02577 int res; 02578 sprintf(s, "'%s' + '%s'", s1, s2); 02579 end= strend(s1); 02580 string2decimal(s1, &a, &end); 02581 end= strend(s2); 02582 string2decimal(s2, &b, &end); 02583 res=decimal_add(&a, &b, &c); 02584 printf("%-40s => res=%d ", s, res); 02585 print_decimal(&c, orig, res, ex); 02586 printf("\n"); 02587 } 02588 02589 void test_ds(const char *s1, const char *s2, const char *orig, int ex) 02590 { 02591 char s[100], *end; 02592 int res; 02593 sprintf(s, "'%s' - '%s'", s1, s2); 02594 end= strend(s1); 02595 string2decimal(s1, &a, &end); 02596 end= strend(s2); 02597 string2decimal(s2, &b, &end); 02598 res=decimal_sub(&a, &b, &c); 02599 printf("%-40s => res=%d ", s, res); 02600 print_decimal(&c, orig, res, ex); 02601 printf("\n"); 02602 } 02603 02604 void test_dc(const char *s1, const char *s2, int orig) 02605 { 02606 char s[100], *end; 02607 int res; 02608 sprintf(s, "'%s' <=> '%s'", s1, s2); 02609 end= strend(s1); 02610 string2decimal(s1, &a, &end); 02611 end= strend(s2); 02612 string2decimal(s2, &b, &end); 02613 res=decimal_cmp(&a, &b); 02614 printf("%-40s => res=%d\n", s, res); 02615 if (orig != res) 02616 { 02617 printf("\n^^^^^^^^^^^^^ must've been %d\n", orig); 02618 exit(1); 02619 } 02620 } 02621 02622 void test_dm(const char *s1, const char *s2, const char *orig, int ex) 02623 { 02624 char s[100], *end; 02625 int res; 02626 sprintf(s, "'%s' * '%s'", s1, s2); 02627 end= strend(s1); 02628 string2decimal(s1, &a, &end); 02629 end= strend(s2); 02630 string2decimal(s2, &b, &end); 02631 res=decimal_mul(&a, &b, &c); 02632 printf("%-40s => res=%d ", s, res); 02633 print_decimal(&c, orig, res, ex); 02634 printf("\n"); 02635 } 02636 02637 void test_dv(const char *s1, const char *s2, const char *orig, int ex) 02638 { 02639 char s[100], *end; 02640 int res; 02641 sprintf(s, "'%s' / '%s'", s1, s2); 02642 end= strend(s1); 02643 string2decimal(s1, &a, &end); 02644 end= strend(s2); 02645 string2decimal(s2, &b, &end); 02646 res=decimal_div(&a, &b, &c, 5); 02647 printf("%-40s => res=%d ", s, res); 02648 check_result_code(res, ex); 02649 if (res == E_DEC_DIV_ZERO) 02650 printf("E_DEC_DIV_ZERO"); 02651 else 02652 print_decimal(&c, orig, res, ex); 02653 printf("\n"); 02654 } 02655 02656 void test_md(const char *s1, const char *s2, const char *orig, int ex) 02657 { 02658 char s[100], *end; 02659 int res; 02660 sprintf(s, "'%s' %% '%s'", s1, s2); 02661 end= strend(s1); 02662 string2decimal(s1, &a, &end); 02663 end= strend(s2); 02664 string2decimal(s2, &b, &end); 02665 res=decimal_mod(&a, &b, &c); 02666 printf("%-40s => res=%d ", s, res); 02667 check_result_code(res, ex); 02668 if (res == E_DEC_DIV_ZERO) 02669 printf("E_DEC_DIV_ZERO"); 02670 else 02671 print_decimal(&c, orig, res, ex); 02672 printf("\n"); 02673 } 02674 02675 const char *round_mode[]= 02676 {"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; 02677 02678 void test_ro(const char *s1, int n, decimal_round_mode mode, const char *orig, 02679 int ex) 02680 { 02681 char s[100], *end; 02682 int res; 02683 sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]); 02684 end= strend(s1); 02685 string2decimal(s1, &a, &end); 02686 res=decimal_round(&a, &b, n, mode); 02687 printf("%-40s => res=%d ", s, res); 02688 print_decimal(&b, orig, res, ex); 02689 printf("\n"); 02690 } 02691 02692 02693 void test_mx(int precision, int frac, const char *orig) 02694 { 02695 char s[100]; 02696 sprintf(s, "%d, %d", precision, frac); 02697 max_decimal(precision, frac, &a); 02698 printf("%-40s => ", s); 02699 print_decimal(&a, orig, 0, 0); 02700 printf("\n"); 02701 } 02702 02703 02704 void test_pr(const char *s1, int prec, int dec, char filler, const char *orig, 02705 int ex) 02706 { 02707 char s[100], *end; 02708 char s2[100]; 02709 int slen= sizeof(s2); 02710 int res; 02711 02712 sprintf(s, filler ? "'%s', %d, %d, '%c'" : "'%s', %d, %d, '\\0'", 02713 s1, prec, dec, filler); 02714 end= strend(s1); 02715 string2decimal(s1, &a, &end); 02716 res= decimal2string(&a, s2, &slen, prec, dec, filler); 02717 printf("%-40s => res=%d '%s'", s, res, s2); 02718 check_result_code(res, ex); 02719 if (orig && strcmp(orig, s2)) 02720 { 02721 printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); 02722 exit(1); 02723 } 02724 printf("\n"); 02725 } 02726 02727 02728 void test_sh(const char *s1, int shift, const char *orig, int ex) 02729 { 02730 char s[100], *end; 02731 int res; 02732 sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); 02733 end= strend(s1); 02734 string2decimal(s1, &a, &end); 02735 res= decimal_shift(&a, shift); 02736 printf("%-40s => res=%d ", s, res); 02737 print_decimal(&a, orig, res, ex); 02738 printf("\n"); 02739 } 02740 02741 02742 void test_fr(const char *s1, const char *orig) 02743 { 02744 char s[100], *end; 02745 sprintf(s, "'%s'", s1); 02746 printf("%-40s => ", s); 02747 end= strend(s1); 02748 string2decimal(s1, &a, &end); 02749 a.frac= decimal_actual_fraction(&a); 02750 print_decimal(&a, orig, 0, 0); 02751 printf("\n"); 02752 } 02753 02754 02755 int main() 02756 { 02757 a.buf=(void*)buf1; 02758 a.len=sizeof(buf1)/sizeof(dec1); 02759 b.buf=(void*)buf2; 02760 b.len=sizeof(buf2)/sizeof(dec1); 02761 c.buf=(void*)buf3; 02762 c.len=sizeof(buf3)/sizeof(dec1); 02763 02764 if (full) 02765 test_d2s(); 02766 02767 printf("==== string2decimal ====\n"); 02768 test_s2d("12345", "12345", 0); 02769 test_s2d("12345.", "12345", 0); 02770 test_s2d("123.45", "123.45", 0); 02771 test_s2d("-123.45", "-123.45", 0); 02772 test_s2d(".00012345000098765", "0.00012345000098765", 0); 02773 test_s2d(".12345000098765", "0.12345000098765", 0); 02774 test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0); 02775 test_s2d("1234500009876.5", "1234500009876.5", 0); 02776 a.len=1; 02777 test_s2d("123450000098765", "98765", 2); 02778 test_s2d("123450.000098765", "123450", 1); 02779 a.len=sizeof(buf1)/sizeof(dec1); 02780 test_s2d("123E5", "12300000", 0); 02781 test_s2d("123E-2", "1.23", 0); 02782 02783 printf("==== decimal2double ====\n"); 02784 test_d2f("12345", 0); 02785 test_d2f("123.45", 0); 02786 test_d2f("-123.45", 0); 02787 test_d2f("0.00012345000098765", 0); 02788 test_d2f("1234500009876.5", 0); 02789 02790 printf("==== double2decimal ====\n"); 02791 test_f2d(12345, 0); 02792 test_f2d(1.0/3, 0); 02793 test_f2d(-123.45, 0); 02794 test_f2d(0.00012345000098765, 0); 02795 test_f2d(1234500009876.5, 0); 02796 02797 printf("==== ulonglong2decimal ====\n"); 02798 test_ull2d(ULL(12345), "12345", 0); 02799 test_ull2d(ULL(0), "0", 0); 02800 test_ull2d(ULL(18446744073709551615), "18446744073709551615", 0); 02801 02802 printf("==== decimal2ulonglong ====\n"); 02803 test_d2ull("12345", "12345", 0); 02804 test_d2ull("0", "0", 0); 02805 test_d2ull("18446744073709551615", "18446744073709551615", 0); 02806 test_d2ull("18446744073709551616", "18446744073", 2); 02807 test_d2ull("-1", "0", 2); 02808 test_d2ull("1.23", "1", 1); 02809 test_d2ull("9999999999999999999999999.000", "9999999999999999", 2); 02810 02811 printf("==== longlong2decimal ====\n"); 02812 test_ll2d(LL(-12345), "-12345", 0); 02813 test_ll2d(LL(-1), "-1", 0); 02814 test_ll2d(LL(-9223372036854775807), "-9223372036854775807", 0); 02815 test_ll2d(ULL(9223372036854775808), "-9223372036854775808", 0); 02816 02817 printf("==== decimal2longlong ====\n"); 02818 test_d2ll("18446744073709551615", "18446744073", 2); 02819 test_d2ll("-1", "-1", 0); 02820 test_d2ll("-1.23", "-1", 1); 02821 test_d2ll("-9223372036854775807", "-9223372036854775807", 0); 02822 test_d2ll("-9223372036854775808", "-9223372036854775808", 0); 02823 test_d2ll("9223372036854775808", "9223372036854775807", 2); 02824 02825 printf("==== do_add ====\n"); 02826 test_da(".00012345000098765" ,"123.45", "123.45012345000098765", 0); 02827 test_da(".1" ,".45", "0.55", 0); 02828 test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765", 0); 02829 test_da("9999909999999.5" ,".555", "9999910000000.055", 0); 02830 test_da("99999999" ,"1", "100000000", 0); 02831 test_da("989999999" ,"1", "990000000", 0); 02832 test_da("999999999" ,"1", "1000000000", 0); 02833 test_da("12345" ,"123.45", "12468.45", 0); 02834 test_da("-12345" ,"-123.45", "-12468.45", 0); 02835 test_ds("-12345" ,"123.45", "-12468.45", 0); 02836 test_ds("12345" ,"-123.45", "12468.45", 0); 02837 02838 printf("==== do_sub ====\n"); 02839 test_ds(".00012345000098765", "123.45","-123.44987654999901235", 0); 02840 test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235", 0); 02841 test_ds("9999900000000.5", ".555","9999899999999.945", 0); 02842 test_ds("1111.5551", "1111.555","0.0001", 0); 02843 test_ds(".555", ".555","0", 0); 02844 test_ds("10000000", "1","9999999", 0); 02845 test_ds("1000001000", ".1","1000000999.9", 0); 02846 test_ds("1000000000", ".1","999999999.9", 0); 02847 test_ds("12345", "123.45","12221.55", 0); 02848 test_ds("-12345", "-123.45","-12221.55", 0); 02849 test_da("-12345", "123.45","-12221.55", 0); 02850 test_da("12345", "-123.45","12221.55", 0); 02851 test_ds("123.45", "12345","-12221.55", 0); 02852 test_ds("-123.45", "-12345","12221.55", 0); 02853 test_da("123.45", "-12345","-12221.55", 0); 02854 test_da("-123.45", "12345","12221.55", 0); 02855 test_da("5", "-6.0","-1.0", 0); 02856 02857 printf("==== decimal_mul ====\n"); 02858 test_dm("12", "10","120", 0); 02859 test_dm("-123.456", "98765.4321","-12193185.1853376", 0); 02860 test_dm("-123456000000", "98765432100000","-12193185185337600000000000", 0); 02861 test_dm("123456", "987654321","121931851853376", 0); 02862 test_dm("123456", "9876543210","1219318518533760", 0); 02863 test_dm("123", "0.01","1.23", 0); 02864 test_dm("123", "0","0", 0); 02865 02866 printf("==== decimal_div ====\n"); 02867 test_dv("120", "10","12.000000000", 0); 02868 test_dv("123", "0.01","12300.000000000", 0); 02869 test_dv("120", "100000000000.00000","0.000000001200000000", 0); 02870 test_dv("123", "0","", 4); 02871 test_dv("0", "0", "", 4); 02872 test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000", 0); 02873 test_dv("121931851853376", "987654321","123456.000000000", 0); 02874 test_dv("0", "987","0", 0); 02875 test_dv("1", "3","0.333333333", 0); 02876 test_dv("1.000000000000", "3","0.333333333333333333", 0); 02877 test_dv("1", "1","1.000000000", 0); 02878 test_dv("0.0123456789012345678912345", "9999999999","0.000000000001234567890246913578148141", 0); 02879 test_dv("10.333000000", "12.34500","0.837019036046982584042122316", 0); 02880 test_dv("10.000000000060", "2","5.000000000030000000", 0); 02881 02882 printf("==== decimal_mod ====\n"); 02883 test_md("234","10","4", 0); 02884 test_md("234.567","10.555","2.357", 0); 02885 test_md("-234.567","10.555","-2.357", 0); 02886 test_md("234.567","-10.555","2.357", 0); 02887 c.buf[1]=0x3ABECA; 02888 test_md("99999999999999999999999999999999999999","3","0", 0); 02889 if (c.buf[1] != 0x3ABECA) 02890 { 02891 printf("%X - overflow\n", c.buf[1]); 02892 exit(1); 02893 } 02894 02895 printf("==== decimal2bin/bin2decimal ====\n"); 02896 test_d2b2d("-10.55", 4, 2,"-10.55", 0); 02897 test_d2b2d("0.0123456789012345678912345", 30, 25,"0.0123456789012345678912345", 0); 02898 test_d2b2d("12345", 5, 0,"12345", 0); 02899 test_d2b2d("12345", 10, 3,"12345.000", 0); 02900 test_d2b2d("123.45", 10, 3,"123.450", 0); 02901 test_d2b2d("-123.45", 20, 10,"-123.4500000000", 0); 02902 test_d2b2d(".00012345000098765", 15, 14,"0.00012345000098", 0); 02903 test_d2b2d(".00012345000098765", 22, 20,"0.00012345000098765000", 0); 02904 test_d2b2d(".12345000098765", 30, 20,"0.12345000098765000000", 0); 02905 test_d2b2d("-.000000012345000098765", 30, 20,"-0.00000001234500009876", 0); 02906 test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000", 0); 02907 test_d2b2d("111111111.11", 10, 2,"11111111.11", 0); 02908 test_d2b2d("000000000.01", 7, 3,"0.010", 0); 02909 test_d2b2d("123.4", 10, 2, "123.40", 0); 02910 02911 02912 printf("==== decimal_cmp ====\n"); 02913 test_dc("12","13",-1); 02914 test_dc("13","12",1); 02915 test_dc("-10","10",-1); 02916 test_dc("10","-10",1); 02917 test_dc("-12","-13",1); 02918 test_dc("0","12",-1); 02919 test_dc("-10","0",-1); 02920 test_dc("4","4",0); 02921 02922 printf("==== decimal_round ====\n"); 02923 test_ro("5678.123451",-4,TRUNCATE,"0", 0); 02924 test_ro("5678.123451",-3,TRUNCATE,"5000", 0); 02925 test_ro("5678.123451",-2,TRUNCATE,"5600", 0); 02926 test_ro("5678.123451",-1,TRUNCATE,"5670", 0); 02927 test_ro("5678.123451",0,TRUNCATE,"5678", 0); 02928 test_ro("5678.123451",1,TRUNCATE,"5678.1", 0); 02929 test_ro("5678.123451",2,TRUNCATE,"5678.12", 0); 02930 test_ro("5678.123451",3,TRUNCATE,"5678.123", 0); 02931 test_ro("5678.123451",4,TRUNCATE,"5678.1234", 0); 02932 test_ro("5678.123451",5,TRUNCATE,"5678.12345", 0); 02933 test_ro("5678.123451",6,TRUNCATE,"5678.123451", 0); 02934 test_ro("-5678.123451",-4,TRUNCATE,"0", 0); 02935 memset(buf2, 33, sizeof(buf2)); 02936 test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000", 0); 02937 test_ro("15.1",0,HALF_UP,"15", 0); 02938 test_ro("15.5",0,HALF_UP,"16", 0); 02939 test_ro("15.9",0,HALF_UP,"16", 0); 02940 test_ro("-15.1",0,HALF_UP,"-15", 0); 02941 test_ro("-15.5",0,HALF_UP,"-16", 0); 02942 test_ro("-15.9",0,HALF_UP,"-16", 0); 02943 test_ro("15.1",1,HALF_UP,"15.1", 0); 02944 test_ro("-15.1",1,HALF_UP,"-15.1", 0); 02945 test_ro("15.17",1,HALF_UP,"15.2", 0); 02946 test_ro("15.4",-1,HALF_UP,"20", 0); 02947 test_ro("-15.4",-1,HALF_UP,"-20", 0); 02948 test_ro("5.4",-1,HALF_UP,"10", 0); 02949 test_ro(".999", 0, HALF_UP, "1", 0); 02950 memset(buf2, 33, sizeof(buf2)); 02951 test_ro("999999999", -9, HALF_UP, "1000000000", 0); 02952 test_ro("15.1",0,HALF_EVEN,"15", 0); 02953 test_ro("15.5",0,HALF_EVEN,"16", 0); 02954 test_ro("14.5",0,HALF_EVEN,"14", 0); 02955 test_ro("15.9",0,HALF_EVEN,"16", 0); 02956 test_ro("15.1",0,CEILING,"16", 0); 02957 test_ro("-15.1",0,CEILING,"-15", 0); 02958 test_ro("15.1",0,FLOOR,"15", 0); 02959 test_ro("-15.1",0,FLOOR,"-16", 0); 02960 test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000", 0); 02961 test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000", 0); 02962 02963 b.buf[0]=DIG_BASE+1; 02964 b.buf++; 02965 test_ro(".3", 0, HALF_UP, "0", 0); 02966 b.buf--; 02967 if (b.buf[0] != DIG_BASE+1) 02968 { 02969 printf("%d - underflow\n", b.buf[0]); 02970 exit(1); 02971 } 02972 02973 printf("==== max_decimal ====\n"); 02974 test_mx(1,1,"0.9"); 02975 test_mx(1,0,"9"); 02976 test_mx(2,1,"9.9"); 02977 test_mx(4,2,"99.99"); 02978 test_mx(6,3,"999.999"); 02979 test_mx(8,4,"9999.9999"); 02980 test_mx(10,5,"99999.99999"); 02981 test_mx(12,6,"999999.999999"); 02982 test_mx(14,7,"9999999.9999999"); 02983 test_mx(16,8,"99999999.99999999"); 02984 test_mx(18,9,"999999999.999999999"); 02985 test_mx(20,10,"9999999999.9999999999"); 02986 test_mx(20,20,"0.99999999999999999999"); 02987 test_mx(20,0,"99999999999999999999"); 02988 test_mx(40,20,"99999999999999999999.99999999999999999999"); 02989 02990 printf("==== decimal2string ====\n"); 02991 test_pr("123.123", 0, 0, 0, "123.123", 0); 02992 test_pr("123.123", 7, 3, '0', "123.123", 0); 02993 test_pr("123.123", 9, 3, '0', "00123.123", 0); 02994 test_pr("123.123", 9, 4, '0', "0123.1230", 0); 02995 test_pr("123.123", 9, 5, '0', "123.12300", 0); 02996 test_pr("123.123", 9, 2, '0', "000123.12", 1); 02997 test_pr("123.123", 9, 6, '0', "23.123000", 2); 02998 02999 printf("==== decimal_shift ====\n"); 03000 test_sh("123.123", 1, "1231.23", 0); 03001 test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0); 03002 test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0); 03003 test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0); 03004 test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0); 03005 test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0); 03006 test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0); 03007 test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0); 03008 test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0); 03009 test_sh("123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); 03010 test_sh("123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); 03011 test_sh("123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); 03012 test_sh("000000000000000000000000123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); 03013 test_sh("00000000123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); 03014 test_sh("00000000000000000123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); 03015 test_sh("123", 1, "1230", 0); 03016 test_sh("123", 10, "1230000000000", 0); 03017 test_sh(".123", 1, "1.23", 0); 03018 test_sh(".123", 10, "1230000000", 0); 03019 test_sh(".123", 14, "12300000000000", 0); 03020 test_sh("000.000", 1000, "0", 0); 03021 test_sh("000.", 1000, "0", 0); 03022 test_sh(".000", 1000, "0", 0); 03023 test_sh("1", 1000, "1", 2); 03024 test_sh("123.123", -1, "12.3123", 0); 03025 test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0); 03026 test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0); 03027 test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0); 03028 test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0); 03029 test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0); 03030 test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0); 03031 test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0); 03032 test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0); 03033 test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0); 03034 test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0); 03035 test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0); 03036 a.len= 2; 03037 test_sh("123.123", -2, "1.23123", 0); 03038 test_sh("123.123", -3, "0.123123", 0); 03039 test_sh("123.123", -6, "0.000123123", 0); 03040 test_sh("123.123", -7, "0.0000123123", 0); 03041 test_sh("123.123", -15, "0.000000000000123123", 0); 03042 test_sh("123.123", -16, "0.000000000000012312", 1); 03043 test_sh("123.123", -17, "0.000000000000001231", 1); 03044 test_sh("123.123", -18, "0.000000000000000123", 1); 03045 test_sh("123.123", -19, "0.000000000000000012", 1); 03046 test_sh("123.123", -20, "0.000000000000000001", 1); 03047 test_sh("123.123", -21, "0", 1); 03048 test_sh(".000000000123", -1, "0.0000000000123", 0); 03049 test_sh(".000000000123", -6, "0.000000000000000123", 0); 03050 test_sh(".000000000123", -7, "0.000000000000000012", 1); 03051 test_sh(".000000000123", -8, "0.000000000000000001", 1); 03052 test_sh(".000000000123", -9, "0", 1); 03053 test_sh(".000000000123", 1, "0.00000000123", 0); 03054 test_sh(".000000000123", 8, "0.0123", 0); 03055 test_sh(".000000000123", 9, "0.123", 0); 03056 test_sh(".000000000123", 10, "1.23", 0); 03057 test_sh(".000000000123", 17, "12300000", 0); 03058 test_sh(".000000000123", 18, "123000000", 0); 03059 test_sh(".000000000123", 19, "1230000000", 0); 03060 test_sh(".000000000123", 20, "12300000000", 0); 03061 test_sh(".000000000123", 21, "123000000000", 0); 03062 test_sh(".000000000123", 22, "1230000000000", 0); 03063 test_sh(".000000000123", 23, "12300000000000", 0); 03064 test_sh(".000000000123", 24, "123000000000000", 0); 03065 test_sh(".000000000123", 25, "1230000000000000", 0); 03066 test_sh(".000000000123", 26, "12300000000000000", 0); 03067 test_sh(".000000000123", 27, "123000000000000000", 0); 03068 test_sh(".000000000123", 28, "0.000000000123", 2); 03069 test_sh("123456789.987654321", -1, "12345678.998765432", 1); 03070 test_sh("123456789.987654321", -2, "1234567.899876543", 1); 03071 test_sh("123456789.987654321", -8, "1.234567900", 1); 03072 test_sh("123456789.987654321", -9, "0.123456789987654321", 0); 03073 test_sh("123456789.987654321", -10, "0.012345678998765432", 1); 03074 test_sh("123456789.987654321", -17, "0.000000001234567900", 1); 03075 test_sh("123456789.987654321", -18, "0.000000000123456790", 1); 03076 test_sh("123456789.987654321", -19, "0.000000000012345679", 1); 03077 test_sh("123456789.987654321", -26, "0.000000000000000001", 1); 03078 test_sh("123456789.987654321", -27, "0", 1); 03079 test_sh("123456789.987654321", 1, "1234567900", 1); 03080 test_sh("123456789.987654321", 2, "12345678999", 1); 03081 test_sh("123456789.987654321", 4, "1234567899877", 1); 03082 test_sh("123456789.987654321", 8, "12345678998765432", 1); 03083 test_sh("123456789.987654321", 9, "123456789987654321", 0); 03084 test_sh("123456789.987654321", 10, "123456789.987654321", 2); 03085 test_sh("123456789.987654321", 0, "123456789.987654321", 0); 03086 a.len= sizeof(buf1)/sizeof(dec1); 03087 03088 printf("==== decimal_actual_fraction ====\n"); 03089 test_fr("1.123456789000000000", "1.123456789"); 03090 test_fr("1.12345678000000000", "1.12345678"); 03091 test_fr("1.1234567000000000", "1.1234567"); 03092 test_fr("1.123456000000000", "1.123456"); 03093 test_fr("1.12345000000000", "1.12345"); 03094 test_fr("1.1234000000000", "1.1234"); 03095 test_fr("1.123000000000", "1.123"); 03096 test_fr("1.12000000000", "1.12"); 03097 test_fr("1.1000000000", "1.1"); 03098 test_fr("1.000000000", "1"); 03099 test_fr("1.0", "1"); 03100 test_fr("10000000000000000000.0", "10000000000000000000"); 03101 03102 return 0; 03103 } 03104 #endif
1.4.7

