Commit b838e5bb authored by unknown's avatar unknown

Merge mskold@bk-internal.mysql.com:/home/bk/mysql-5.0

into mysql.com:/usr/local/home/marty/MySQL/test/mysql-5.0-ndb
parents 61711490 14995012
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <my_global.h> #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 int32 decimal_digit;
typedef struct st_decimal { typedef struct st_decimal {
...@@ -70,10 +70,10 @@ int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode ...@@ -70,10 +70,10 @@ int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode
/* /*
returns the length of the buffer to hold string representation returns the length of the buffer to hold string representation
of the decimal of the decimal (including decimal dot, possible sign and \0)
*/ */
#define decimal_string_size(dec) ((dec)->intg + (dec)->frac + ((dec)->frac > 0) + 1) #define decimal_string_size(dec) ((dec)->intg + (dec)->frac + ((dec)->frac > 0) + 2)
/* negate a decimal */ /* negate a decimal */
#define decimal_neg(dec) do { (dec)->sign^=1; } while(0) #define decimal_neg(dec) do { (dec)->sign^=1; } while(0)
...@@ -91,9 +91,12 @@ int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode ...@@ -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_OK 0
#define E_DEC_TRUNCATED 1 #define E_DEC_TRUNCATED 1
#define E_DEC_OVERFLOW 2 #define E_DEC_OVERFLOW 2
#define E_DEC_DIV_ZERO 3 #define E_DEC_DIV_ZERO 4
#define E_DEC_BAD_NUM 4 #define E_DEC_BAD_NUM 8
#define E_DEC_OOM 5 #define E_DEC_OOM 16
#define E_DEC_ERROR 31
#define E_DEC_FATAL_ERROR 30
#endif #endif
...@@ -819,12 +819,21 @@ int decimal_bin_size(int precision, int scale) ...@@ -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 decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode)
{ {
int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, 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; intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len;
dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0;
sanity(to); 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)) if (unlikely(frac0+intg0 > len))
{ {
frac0=len-intg0; frac0=len-intg0;
...@@ -865,26 +874,20 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode ...@@ -865,26 +874,20 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode
buf1+=intg0+frac0-1; buf1+=intg0+frac0-1;
if (scale == frac0*DIG_PER_DEC1) if (scale == frac0*DIG_PER_DEC1)
{ {
if (mode != TRUNCATE) x=buf0[1]/DIG_MASK;
{ if (x > round_digit ||
x=buf0[1]/DIG_MASK; (round_digit == 5 && x == 5 && (mode == HALF_UP || *buf0 & 1)))
if (x > 5 || (x == 5 && (mode == HALF_UP || *buf0 & 1))) (*buf1)++;
(*buf1)++;
}
} }
else else
{ {
int pos=frac0*DIG_PER_DEC1-scale-1; int pos=frac0*DIG_PER_DEC1-scale-1;
if (mode != TRUNCATE) x=*buf1 / powers10[pos];
{ y=x % 10;
x=*buf1 / powers10[pos]; if (y > round_digit ||
y=x % 10; (round_digit == 5 && y == 5 && (mode == HALF_UP || (x/10) & 1)))
if (y > 5 || (y == 5 && (mode == HALF_UP || (x/10) & 1))) x+=10;
x+=10; *buf1=powers10[pos]*(x-y);
*buf1=powers10[pos]*(x-y);
}
else
*buf1=(*buf1/powers10[pos+1])*powers10[pos+1];
} }
if (*buf1 >= DIG_BASE) if (*buf1 >= DIG_BASE)
{ {
...@@ -1820,12 +1823,13 @@ void test_md(char *s1, char *s2) ...@@ -1820,12 +1823,13 @@ void test_md(char *s1, char *s2)
printf("\n"); printf("\n");
} }
char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"};
void test_ro(char *s1, int n, decimal_round_mode mode) void test_ro(char *s1, int n, decimal_round_mode mode)
{ {
char s[100]; char s[100];
int res; int res;
sprintf(s, "%s('%s', %d)", (mode == TRUNCATE ? "truncate" : "round"), sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]);
s1, n);
string2decimal(s1, &a, 0); string2decimal(s1, &a, 0);
res=decimal_round(&a, &b, n, mode); res=decimal_round(&a, &b, n, mode);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
...@@ -1953,33 +1957,6 @@ main() ...@@ -1953,33 +1957,6 @@ main()
test_dv("1", "1"); test_dv("1", "1");
test_dv("0.0123456789012345678912345", "9999999999"); 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"); printf("==== decimal_mod ====\n");
test_md("234","10"); test_md("234","10");
test_md("234.567","10.555"); test_md("234.567","10.555");
...@@ -2008,6 +1985,41 @@ main() ...@@ -2008,6 +1985,41 @@ main()
test_dc("0","12"); test_dc("0","12");
test_dc("-10","0"); test_dc("-10","0");
test_dc("4","4"); 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; return 0;
} }
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment