~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mystrings/decimal.c

  • Committer: Brian Aker
  • Date: 2008-09-04 19:31:00 UTC
  • Revision ID: brian@tangent.org-20080904193100-l849hgghfy4urj43
Changing default character set from this point on.

Show diffs side-by-side

added added

removed removed

Lines of Context:
97
97
      implementation-defined.
98
98
*/
99
99
 
100
 
#include <config.h>
101
100
#include <alloca.h>
102
101
#include <m_string.h>
103
102
#include <m_ctype.h>
104
103
#include <storage/myisam/myisampack.h>
105
104
#include <mystrings/decimal.h>
106
105
 
107
 
#include <drizzled/util/test.h>
108
106
/*
109
107
  Internally decimal numbers are stored base 10^9 (see DIG_BASE below)
110
108
  So one variable of type decimal_digit_t is limited:
127
125
#define DIG_MASK     100000000
128
126
#define DIG_BASE     1000000000
129
127
#define DIG_MAX      (DIG_BASE-1)
 
128
#define DIG_BASE2    ((dec2)DIG_BASE * (dec2)DIG_BASE)
130
129
#define ROUND_UP(X)  (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1)
131
130
static const dec1 powers10[DIG_PER_DEC1+1]={
132
131
  1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
405
404
    for (; frac>0; frac-=DIG_PER_DEC1)
406
405
    {
407
406
      dec1 x=*buf++;
408
 
      for (i=cmin(frac, DIG_PER_DEC1); i; i--)
 
407
      for (i=min(frac, DIG_PER_DEC1); i; i--)
409
408
      {
410
409
        dec1 y=x/DIG_MASK;
411
 
        *s1++='0'+(unsigned char)y;
 
410
        *s1++='0'+(uchar)y;
412
411
        x-=y*DIG_MASK;
413
412
        x*=10;
414
413
      }
428
427
    for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1)
429
428
    {
430
429
      dec1 x=*--buf;
431
 
      for (i=cmin(intg, DIG_PER_DEC1); i; i--)
 
430
      for (i=min(intg, DIG_PER_DEC1); i; i--)
432
431
      {
433
432
        dec1 y=x/10;
434
 
        *--s='0'+(unsigned char)(x-y*10);
 
433
        *--s='0'+(uchar)(x-y*10);
435
434
        x=y;
436
435
      }
437
436
    }
804
803
  sanity(to);
805
804
 
806
805
  error= E_DEC_BAD_NUM;                         /* In case of bad number */
807
 
  while (s < end_of_string && my_isspace(&my_charset_utf8_general_ci, *s))
 
806
  while (s < end_of_string && my_isspace(&my_charset_latin1, *s))
808
807
    s++;
809
808
  if (s == end_of_string)
810
809
    goto fatal_error;
815
814
    s++;
816
815
 
817
816
  s1=s;
818
 
  while (s < end_of_string && my_isdigit(&my_charset_utf8_general_ci, *s))
 
817
  while (s < end_of_string && my_isdigit(&my_charset_latin1, *s))
819
818
    s++;
820
819
  intg= (int) (s-s1);
821
820
  if (s < end_of_string && *s=='.')
822
821
  {
823
822
    endp= s+1;
824
 
    while (endp < end_of_string && my_isdigit(&my_charset_utf8_general_ci, *endp))
 
823
    while (endp < end_of_string && my_isdigit(&my_charset_latin1, *endp))
825
824
      endp++;
826
825
    frac= (int) (endp - s - 1);
827
826
  }
1177
1176
 
1178
1177
                7E F2 04 37 2D FB 2D
1179
1178
*/
1180
 
int decimal2bin(decimal_t *from, unsigned char *to, int precision, int frac)
 
1179
int decimal2bin(decimal_t *from, uchar *to, int precision, int frac)
1181
1180
{
1182
1181
  dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1;
1183
1182
  int error=E_DEC_OK, intg=precision-frac,
1193
1192
      fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x];
1194
1193
  const int orig_isize0= isize0;
1195
1194
  const int orig_fsize0= fsize0;
1196
 
  unsigned char *orig_to= to;
 
1195
  uchar *orig_to= to;
1197
1196
 
1198
1197
  buf1= remove_leading_zeroes(from, &from_intg);
1199
1198
 
1283
1282
  }
1284
1283
  if (fsize0 > fsize1)
1285
1284
  {
1286
 
    unsigned char *to_end= orig_to + orig_fsize0 + orig_isize0;
 
1285
    uchar *to_end= orig_to + orig_fsize0 + orig_isize0;
1287
1286
 
1288
1287
    while (fsize0-- > fsize1 && to < to_end)
1289
 
      *to++= (unsigned char)mask;
 
1288
      *to++= (uchar)mask;
1290
1289
  }
1291
1290
  orig_to[0]^= 0x80;
1292
1291
 
1312
1311
    E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW
1313
1312
*/
1314
1313
 
1315
 
int bin2decimal(const unsigned char *from, decimal_t *to, int precision, int scale)
 
1314
int bin2decimal(const uchar *from, decimal_t *to, int precision, int scale)
1316
1315
{
1317
1316
  int error=E_DEC_OK, intg=precision-scale,
1318
1317
      intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1,
1319
1318
      intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1,
1320
1319
      intg1=intg0+(intg0x>0), frac1=frac0+(frac0x>0);
1321
1320
  dec1 *buf=to->buf, mask=(*from & 0x80) ? 0 : -1;
1322
 
  const unsigned char *stop;
1323
 
  unsigned char *d_copy;
 
1321
  const uchar *stop;
 
1322
  uchar *d_copy;
1324
1323
  int bin_size= decimal_bin_size(precision, scale);
1325
1324
 
1326
1325
  sanity(to);
1327
 
  d_copy= (unsigned char*) alloca(bin_size);
 
1326
  d_copy= (uchar*) alloca(bin_size);
1328
1327
  memcpy(d_copy, from, bin_size);
1329
1328
  d_copy[0]^= 0x80;
1330
1329
  from= d_copy;
1502
1501
 
1503
1502
  if (to != from || intg1>intg0)
1504
1503
  {
1505
 
    dec1 *p0= buf0+intg0+cmax(frac1, frac0);
1506
 
    dec1 *p1= buf1+intg1+cmax(frac1, frac0);
 
1504
    dec1 *p0= buf0+intg0+max(frac1, frac0);
 
1505
    dec1 *p1= buf1+intg1+max(frac1, frac0);
1507
1506
 
1508
1507
    while (buf0 < p0)
1509
1508
      *(--p1) = *(--p0);
1514
1513
    buf0=to->buf;
1515
1514
    buf1=to->buf;
1516
1515
    to->sign=from->sign;
1517
 
    to->intg=cmin(intg0, len)*DIG_PER_DEC1;
 
1516
    to->intg=min(intg0, len)*DIG_PER_DEC1;
1518
1517
  }
1519
1518
 
1520
1519
  if (frac0 > frac1)
1616
1615
        scale=frac0*DIG_PER_DEC1;
1617
1616
        error=E_DEC_TRUNCATED; /* XXX */
1618
1617
      }
1619
 
      for (buf1=to->buf+intg0+cmax(frac0,0); buf1 > to->buf; buf1--)
 
1618
      for (buf1=to->buf+intg0+max(frac0,0); buf1 > to->buf; buf1--)
1620
1619
      {
1621
1620
        buf1[0]=buf1[-1];
1622
1621
      }
1635
1634
        /* making 'zero' with the proper scale */
1636
1635
        dec1 *p0= to->buf + frac0 + 1;
1637
1636
        to->intg=1;
1638
 
        to->frac= cmax(scale, 0);
 
1637
        to->frac= max(scale, 0);
1639
1638
        to->sign= 0;
1640
1639
        for (buf1= to->buf; buf1<p0; buf1++)
1641
1640
          *buf1= 0;
1684
1683
{
1685
1684
  switch (op) {
1686
1685
  case '-':
1687
 
    return ROUND_UP(cmax(from1->intg, from2->intg)) +
1688
 
           ROUND_UP(cmax(from1->frac, from2->frac));
 
1686
    return ROUND_UP(max(from1->intg, from2->intg)) +
 
1687
           ROUND_UP(max(from1->frac, from2->frac));
1689
1688
  case '+':
1690
 
    return ROUND_UP(cmax(from1->intg, from2->intg)+1) +
1691
 
           ROUND_UP(cmax(from1->frac, from2->frac));
 
1689
    return ROUND_UP(max(from1->intg, from2->intg)+1) +
 
1690
           ROUND_UP(max(from1->frac, from2->frac));
1692
1691
  case '*':
1693
1692
    return ROUND_UP(from1->intg+from2->intg)+
1694
1693
           ROUND_UP(from1->frac)+ROUND_UP(from2->frac);
1703
1702
{
1704
1703
  int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
1705
1704
      frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac),
1706
 
      frac0=cmax(frac1, frac2), intg0=cmax(intg1, intg2), error;
 
1705
      frac0=max(frac1, frac2), intg0=max(intg1, intg2), error;
1707
1706
  dec1 *buf1, *buf2, *buf0, *stop, *stop2, x, carry;
1708
1707
 
1709
1708
  sanity(to);
1728
1727
  buf0=to->buf+intg0+frac0;
1729
1728
 
1730
1729
  to->sign=from1->sign;
1731
 
  to->frac=cmax(from1->frac, from2->frac);
 
1730
  to->frac=max(from1->frac, from2->frac);
1732
1731
  to->intg=intg0*DIG_PER_DEC1;
1733
1732
  if (unlikely(error))
1734
1733
  {
1739
1738
    set_if_smaller(intg2, intg0);
1740
1739
  }
1741
1740
 
1742
 
  /* part 1 - cmax(frac) ... cmin(frac) */
 
1741
  /* part 1 - max(frac) ... min (frac) */
1743
1742
  if (frac1 > frac2)
1744
1743
  {
1745
1744
    buf1=from1->buf+intg1+frac1;
1757
1756
  while (buf1 > stop)
1758
1757
    *--buf0=*--buf1;
1759
1758
 
1760
 
  /* part 2 - cmin(frac) ... cmin(intg) */
 
1759
  /* part 2 - min(frac) ... min(intg) */
1761
1760
  carry=0;
1762
1761
  while (buf1 > stop2)
1763
1762
  {
1764
1763
    ADD(*--buf0, *--buf1, *--buf2, carry);
1765
1764
  }
1766
1765
 
1767
 
  /* part 3 - cmin(intg) ... cmax(intg) */
 
1766
  /* part 3 - min(intg) ... max(intg) */
1768
1767
  buf1= intg1 > intg2 ? ((stop=from1->buf)+intg1-intg2) :
1769
1768
                        ((stop=from2->buf)+intg2-intg1) ;
1770
1769
  while (buf1 > stop)
1785
1784
{
1786
1785
  int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg),
1787
1786
      frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac);
1788
 
  int frac0=cmax(frac1, frac2), error;
 
1787
  int frac0=max(frac1, frac2), error;
1789
1788
  dec1 *buf1, *buf2, *buf0, *stop1, *stop2, *start1, *start2, carry=0;
1790
1789
 
1791
1790
  /* let carry:=1 if from2 > from1 */
1860
1859
  FIX_INTG_FRAC_ERROR(to->len, intg1, frac0, error);
1861
1860
  buf0=to->buf+intg1+frac0;
1862
1861
 
1863
 
  to->frac=cmax(from1->frac, from2->frac);
 
1862
  to->frac=max(from1->frac, from2->frac);
1864
1863
  to->intg=intg1*DIG_PER_DEC1;
1865
1864
  if (unlikely(error))
1866
1865
  {
1871
1870
  }
1872
1871
  carry=0;
1873
1872
 
1874
 
  /* part 1 - cmax(frac) ... cmin(frac) */
 
1873
  /* part 1 - max(frac) ... min (frac) */
1875
1874
  if (frac1 > frac2)
1876
1875
  {
1877
1876
    buf1=start1+intg1+frac1;
1895
1894
    }
1896
1895
  }
1897
1896
 
1898
 
  /* part 2 - cmin(frac) ... intg2 */
 
1897
  /* part 2 - min(frac) ... intg2 */
1899
1898
  while (buf2 > start2)
1900
1899
  {
1901
1900
    SUB(*--buf0, *--buf1, *--buf2, carry);
2151
2150
  {
2152
2151
    /* we're calculating N1 % N2.
2153
2152
       The result will have
2154
 
         frac=cmax(frac1, frac2), as for subtraction
 
2153
         frac=max(frac1, frac2), as for subtraction
2155
2154
         intg=intg2
2156
2155
    */
2157
2156
    to->sign=from1->sign;
2158
 
    to->frac=cmax(from1->frac, from2->frac);
 
2157
    to->frac=max(from1->frac, from2->frac);
2159
2158
    frac0=0;
2160
2159
  }
2161
2160
  else
2279
2278
    /*
2280
2279
      now the result is in tmp1, it has
2281
2280
        intg=prec1-frac1
2282
 
        frac=cmax(frac1, frac2)=to->frac
 
2281
        frac=max(frac1, frac2)=to->frac
2283
2282
    */
2284
2283
    if (dcarry)
2285
2284
      *--start1=dcarry;
2317
2316
      }
2318
2317
      assert(intg0 <= ROUND_UP(from2->intg));
2319
2318
      stop1=start1+frac0+intg0;
2320
 
      to->intg=cmin(intg0*DIG_PER_DEC1, from2->intg);
 
2319
      to->intg=min(intg0*DIG_PER_DEC1, from2->intg);
2321
2320
    }
2322
2321
    if (unlikely(intg0+frac0 > to->len))
2323
2322
    {
2507
2506
  {
2508
2507
    printf("0x");
2509
2508
    for (i=0; i < size; i++)
2510
 
      printf("%02x", ((unsigned char *)buf)[i]);
 
2509
      printf("%02x", ((uchar *)buf)[i]);
2511
2510
  }
2512
2511
  res=bin2decimal(buf, &a, p, s);
2513
2512
  printf(" => res=%d ", res);