diff options
author | unknown <serg@serg.mylan> | 2004-11-03 18:43:48 +0100 |
---|---|---|
committer | unknown <serg@serg.mylan> | 2004-11-03 18:43:48 +0100 |
commit | c41f992deaf38b8cdcd0379598c00642673e37a1 (patch) | |
tree | 2da4d18ba56881974367609881b46b6bc223f7af | |
parent | 09e0503538cbf882cdb1c215a45becfd3826d67a (diff) | |
download | mariadb-git-c41f992deaf38b8cdcd0379598c00642673e37a1.tar.gz |
error codes chaged to bitmap (for easier testing with masks)
two more round() modes - CEILING and FLOOR
-rw-r--r-- | include/decimal.h | 11 | ||||
-rw-r--r-- | strings/decimal.c | 104 |
2 files changed, 65 insertions, 50 deletions
diff --git a/include/decimal.h b/include/decimal.h index 2de62af140d..dd10cee991c 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -19,7 +19,7 @@ #include <my_global.h> -typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP} decimal_round_mode; +typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode; typedef int32 decimal_digit; typedef struct st_decimal { @@ -91,9 +91,12 @@ int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode #define E_DEC_OK 0 #define E_DEC_TRUNCATED 1 #define E_DEC_OVERFLOW 2 -#define E_DEC_DIV_ZERO 3 -#define E_DEC_BAD_NUM 4 -#define E_DEC_OOM 5 +#define E_DEC_DIV_ZERO 4 +#define E_DEC_BAD_NUM 8 +#define E_DEC_OOM 16 + +#define E_DEC_ERROR 31 +#define E_DEC_FATAL_ERROR 30 #endif diff --git a/strings/decimal.c b/strings/decimal.c index fc175417839..821fc1414ad 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -819,12 +819,21 @@ int decimal_bin_size(int precision, int scale) int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode) { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, - frac1=ROUND_UP(from->frac), + frac1=ROUND_UP(from->frac), round_digit, intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len; dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; sanity(to); + switch (mode) { + case HALF_UP: + case HALF_EVEN: round_digit=5; break; + case CEILING: round_digit= from->sign ? 10 : 0; break; + case FLOOR: round_digit= from->sign ? 0 : 10; break; + case TRUNCATE: round_digit=10; break; + default: DBUG_ASSERT(0); + } + if (unlikely(frac0+intg0 > len)) { frac0=len-intg0; @@ -865,26 +874,20 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode buf1+=intg0+frac0-1; if (scale == frac0*DIG_PER_DEC1) { - if (mode != TRUNCATE) - { - x=buf0[1]/DIG_MASK; - if (x > 5 || (x == 5 && (mode == HALF_UP || *buf0 & 1))) - (*buf1)++; - } + x=buf0[1]/DIG_MASK; + if (x > round_digit || + (round_digit == 5 && x == 5 && (mode == HALF_UP || *buf0 & 1))) + (*buf1)++; } else { int pos=frac0*DIG_PER_DEC1-scale-1; - if (mode != TRUNCATE) - { - x=*buf1 / powers10[pos]; - y=x % 10; - if (y > 5 || (y == 5 && (mode == HALF_UP || (x/10) & 1))) - x+=10; - *buf1=powers10[pos]*(x-y); - } - else - *buf1=(*buf1/powers10[pos+1])*powers10[pos+1]; + x=*buf1 / powers10[pos]; + y=x % 10; + if (y > round_digit || + (round_digit == 5 && y == 5 && (mode == HALF_UP || (x/10) & 1))) + x+=10; + *buf1=powers10[pos]*(x-y); } if (*buf1 >= DIG_BASE) { @@ -1820,12 +1823,13 @@ void test_md(char *s1, char *s2) printf("\n"); } +char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; + void test_ro(char *s1, int n, decimal_round_mode mode) { char s[100]; int res; - sprintf(s, "%s('%s', %d)", (mode == TRUNCATE ? "truncate" : "round"), - s1, n); + sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]); string2decimal(s1, &a, 0); res=decimal_round(&a, &b, n, mode); printf("%-40s => res=%d ", s, res); @@ -1953,33 +1957,6 @@ main() test_dv("1", "1"); test_dv("0.0123456789012345678912345", "9999999999"); - printf("==== decimal_round ====\n"); - test_ro("15.1",0,HALF_UP); - test_ro("15.5",0,HALF_UP); - test_ro("15.5",0,HALF_UP); - test_ro("15.9",0,HALF_UP); - test_ro("-15.1",0,HALF_UP); - test_ro("-15.5",0,HALF_UP); - test_ro("-15.9",0,HALF_UP); - test_ro("15.1",1,HALF_UP); - test_ro("-15.1",1,HALF_UP); - test_ro("15.17",1,HALF_UP); - test_ro("15.4",-1,HALF_UP); - test_ro("-15.4",-1,HALF_UP); - test_ro("5678.123451",-4,TRUNCATE); - test_ro("5678.123451",-3,TRUNCATE); - test_ro("5678.123451",-2,TRUNCATE); - test_ro("5678.123451",-1,TRUNCATE); - test_ro("5678.123451",0,TRUNCATE); - test_ro("5678.123451",1,TRUNCATE); - test_ro("5678.123451",2,TRUNCATE); - test_ro("5678.123451",3,TRUNCATE); - test_ro("5678.123451",4,TRUNCATE); - test_ro("5678.123451",5,TRUNCATE); - test_ro("5678.123451",6,TRUNCATE); - test_ro("-5678.123451",-4,TRUNCATE); - test_ro("99999999999999999999999999999999999999",-31,TRUNCATE); - printf("==== decimal_mod ====\n"); test_md("234","10"); test_md("234.567","10.555"); @@ -2008,6 +1985,41 @@ main() test_dc("0","12"); test_dc("-10","0"); test_dc("4","4"); + + printf("==== decimal_round ====\n"); + test_ro("5678.123451",-4,TRUNCATE); + test_ro("5678.123451",-3,TRUNCATE); + test_ro("5678.123451",-2,TRUNCATE); + test_ro("5678.123451",-1,TRUNCATE); + test_ro("5678.123451",0,TRUNCATE); + test_ro("5678.123451",1,TRUNCATE); + test_ro("5678.123451",2,TRUNCATE); + test_ro("5678.123451",3,TRUNCATE); + test_ro("5678.123451",4,TRUNCATE); + test_ro("5678.123451",5,TRUNCATE); + test_ro("5678.123451",6,TRUNCATE); + test_ro("-5678.123451",-4,TRUNCATE); + test_ro("99999999999999999999999999999999999999",-31,TRUNCATE); + test_ro("15.1",0,HALF_UP); + test_ro("15.5",0,HALF_UP); + test_ro("15.9",0,HALF_UP); + test_ro("-15.1",0,HALF_UP); + test_ro("-15.5",0,HALF_UP); + test_ro("-15.9",0,HALF_UP); + test_ro("15.1",1,HALF_UP); + test_ro("-15.1",1,HALF_UP); + test_ro("15.17",1,HALF_UP); + test_ro("15.4",-1,HALF_UP); + test_ro("-15.4",-1,HALF_UP); + test_ro("15.1",0,HALF_EVEN); + test_ro("15.5",0,HALF_EVEN); + test_ro("14.5",0,HALF_EVEN); + test_ro("15.9",0,HALF_EVEN); + test_ro("15.1",0,CEILING); + test_ro("-15.1",0,CEILING); + test_ro("15.1",0,FLOOR); + test_ro("-15.1",0,FLOOR); + return 0; } #endif |