github.com/matrixorigin/matrixone@v0.7.0/cgo/external/decNumber/decPacked.c (about)

     1  /* ------------------------------------------------------------------ */
     2  /* Packed Decimal conversion module                                   */
     3  /* ------------------------------------------------------------------ */
     4  /* Copyright (c) IBM Corporation, 2000, 2002.  All rights reserved.   */
     5  /*                                                                    */
     6  /* This software is made available under the terms of the             */
     7  /* ICU License -- ICU 1.8.1 and later.                                */
     8  /*                                                                    */
     9  /* The description and User's Guide ("The decNumber C Library") for   */
    10  /* this software is called decNumber.pdf.  This document is           */
    11  /* available, together with arithmetic and format specifications,     */
    12  /* testcases, and Web links, on the General Decimal Arithmetic page.  */
    13  /*                                                                    */
    14  /* Please send comments, suggestions, and corrections to the author:  */
    15  /*   mfc@uk.ibm.com                                                   */
    16  /*   Mike Cowlishaw, IBM Fellow                                       */
    17  /*   IBM UK, PO Box 31, Birmingham Road, Warwick CV34 5JL, UK         */
    18  /* ------------------------------------------------------------------ */
    19  /* This module comprises the routines for Packed Decimal format       */
    20  /* numbers.  Conversions are supplied to and from decNumber, which in */
    21  /* turn supports:                                                     */
    22  /*   conversions to and from string                                   */
    23  /*   arithmetic routines                                              */
    24  /*   utilities.                                                       */
    25  /* Conversions from decNumber to and from densely packed decimal      */
    26  /* formats are provided by the decimal32 through decimal128 modules.  */
    27  /* ------------------------------------------------------------------ */
    28  
    29  #include <string.h>           // for NULL
    30  #include "decNumber.h"        // base number library
    31  #include "decPacked.h"        // packed decimal
    32  #include "decNumberLocal.h"   // decNumber local types, etc.
    33  
    34  /* ------------------------------------------------------------------ */
    35  /* decPackedFromNumber -- convert decNumber to BCD Packed Decimal     */
    36  /*                                                                    */
    37  /*   bcd    is the BCD bytes                                          */
    38  /*   length is the length of the BCD array                            */
    39  /*   scale  is the scale result                                       */
    40  /*   dn     is the decNumber                                          */
    41  /*   returns bcd, or NULL if error                                    */
    42  /*                                                                    */
    43  /* The number is converted to a BCD packed decimal byte array,        */
    44  /* right aligned in the bcd array, whose length is indicated by the   */
    45  /* second parameter.  The final 4-bit nibble in the array will be a   */
    46  /* sign nibble, C (1100) for + and D (1101) for -.  Unused bytes and  */
    47  /* nibbles to the left of the number are set to 0.                    */
    48  /*                                                                    */
    49  /* scale is set to the scale of the number (this is the exponent,     */
    50  /* negated).  To force the number to a specified scale, first use the */
    51  /* decNumberRescale routine, which will round and change the exponent */
    52  /* as necessary.                                                      */
    53  /*                                                                    */
    54  /* If there is an error (that is, the decNumber has too many digits   */
    55  /* to fit in length bytes, or it is a NaN or Infinity), NULL is       */
    56  /* returned and the bcd and scale results are unchanged.  Otherwise   */
    57  /* bcd is returned.                                                   */
    58  /* ------------------------------------------------------------------ */
    59  uByte * decPackedFromNumber(uByte *bcd, Int length, Int *scale,
    60                              const decNumber *dn) {
    61    const Unit *up=dn->lsu;     // Unit array pointer
    62    uByte obyte, *out;          // current output byte, and where it goes
    63    Int indigs=dn->digits;      // digits processed
    64    uInt cut=DECDPUN;           // downcounter per Unit
    65    uInt u=*up;                 // work
    66    uInt nib;                   // ..
    67    #if DECDPUN<=4
    68    uInt temp;                  // ..
    69    #endif
    70  
    71    if (dn->digits>length*2-1                  // too long ..
    72     ||(dn->bits & DECSPECIAL)) return NULL;   // .. or special -- hopeless
    73  
    74    if (dn->bits&DECNEG) obyte=DECPMINUS;      // set the sign ..
    75     else                obyte=DECPPLUS;
    76    *scale=-dn->exponent;                      // .. and scale
    77  
    78    // loop from lowest (rightmost) byte
    79    out=bcd+length-1;                          // -> final byte
    80    for (; out>=bcd; out--) {
    81      if (indigs>0) {
    82        if (cut==0) {
    83          up++;
    84          u=*up;
    85          cut=DECDPUN;
    86          }
    87        #if DECDPUN<=4
    88          temp=(u*6554)>>16;         // fast /10
    89          nib=u-X10(temp);
    90          u=temp;
    91        #else
    92          nib=u%10;                  // cannot use *6554 trick :-(
    93          u=u/10;
    94        #endif
    95        obyte|=(nib<<4);
    96        indigs--;
    97        cut--;
    98        }
    99      *out=obyte;
   100      obyte=0;                       // assume 0
   101      if (indigs>0) {
   102        if (cut==0) {
   103          up++;
   104          u=*up;
   105          cut=DECDPUN;
   106          }
   107        #if DECDPUN<=4
   108          temp=(u*6554)>>16;         // as above
   109          obyte=(uByte)(u-X10(temp));
   110          u=temp;
   111        #else
   112          obyte=(uByte)(u%10);
   113          u=u/10;
   114        #endif
   115        indigs--;
   116        cut--;
   117        }
   118      } // loop
   119  
   120    return bcd;
   121    } // decPackedFromNumber
   122  
   123  /* ------------------------------------------------------------------ */
   124  /* decPackedToNumber -- convert BCD Packed Decimal to a decNumber     */
   125  /*                                                                    */
   126  /*   bcd    is the BCD bytes                                          */
   127  /*   length is the length of the BCD array                            */
   128  /*   scale  is the scale associated with the BCD integer              */
   129  /*   dn     is the decNumber [with space for length*2 digits]         */
   130  /*   returns dn, or NULL if error                                     */
   131  /*                                                                    */
   132  /* The BCD packed decimal byte array, together with an associated     */
   133  /* scale, is converted to a decNumber.  The BCD array is assumed full */
   134  /* of digits, and must be ended by a 4-bit sign nibble in the least   */
   135  /* significant four bits of the final byte.                           */
   136  /*                                                                    */
   137  /* The scale is used (negated) as the exponent of the decNumber.      */
   138  /* Note that zeros may have a sign and/or a scale.                    */
   139  /*                                                                    */
   140  /* The decNumber structure is assumed to have sufficient space to     */
   141  /* hold the converted number (that is, up to length*2-1 digits), so   */
   142  /* no error is possible unless the adjusted exponent is out of range, */
   143  /* no sign nibble was found, or a sign nibble was found before the    */
   144  /* final nibble.  In these error cases, NULL is returned and the      */
   145  /* decNumber will be 0.                                               */
   146  /* ------------------------------------------------------------------ */
   147  decNumber * decPackedToNumber(const uByte *bcd, Int length,
   148                                const Int *scale, decNumber *dn) {
   149    const uByte *last=bcd+length-1;  // -> last byte
   150    const uByte *first;              // -> first non-zero byte
   151    uInt  nib;                       // work nibble
   152    Unit  *up=dn->lsu;               // output pointer
   153    Int   digits;                    // digits count
   154    Int   cut=0;                     // phase of output
   155  
   156    decNumberZero(dn);               // default result
   157    last=&bcd[length-1];
   158    nib=*last & 0x0f;                // get the sign
   159    if (nib==DECPMINUS || nib==DECPMINUSALT) dn->bits=DECNEG;
   160     else if (nib<=9) return NULL;   // not a sign nibble
   161  
   162    // skip leading zero bytes [final byte is always non-zero, due to sign]
   163    for (first=bcd; *first==0;) first++;
   164    digits=(last-first)*2+1;              // calculate digits ..
   165    if ((*first & 0xf0)==0) digits--;     // adjust for leading zero nibble
   166    if (digits!=0) dn->digits=digits;     // count of actual digits [if 0,
   167                                          // leave as 1]
   168  
   169    // check the adjusted exponent; note that scale could be unbounded
   170    dn->exponent=-*scale;                 // set the exponent
   171    if (*scale>=0) {                      // usual case
   172      if ((dn->digits-*scale-1)<-DECNUMMAXE) {      // underflow
   173        decNumberZero(dn);
   174        return NULL;}
   175      }
   176     else { // -ve scale; +ve exponent
   177      // need to be careful to avoid wrap, here, also BADINT case
   178      if ((*scale<-DECNUMMAXE)            // overflow even without digits
   179           || ((dn->digits-*scale-1)>DECNUMMAXE)) { // overflow
   180        decNumberZero(dn);
   181        return NULL;}
   182      }
   183    if (digits==0) return dn;             // result was zero
   184  
   185    // copy the digits to the number's units, starting at the lsu
   186    // [unrolled]
   187    for (;;) {                            // forever
   188      // left nibble first
   189      nib=(unsigned)(*last & 0xf0)>>4;
   190      // got a digit, in nib
   191      if (nib>9) {decNumberZero(dn); return NULL;}
   192  
   193      if (cut==0) *up=(Unit)nib;
   194       else *up=(Unit)(*up+nib*DECPOWERS[cut]);
   195      digits--;
   196      if (digits==0) break;               // got them all
   197      cut++;
   198      if (cut==DECDPUN) {
   199        up++;
   200        cut=0;
   201        }
   202      last--;                             // ready for next
   203      nib=*last & 0x0f;                   // get right nibble
   204      if (nib>9) {decNumberZero(dn); return NULL;}
   205  
   206      // got a digit, in nib
   207      if (cut==0) *up=(Unit)nib;
   208       else *up=(Unit)(*up+nib*DECPOWERS[cut]);
   209      digits--;
   210      if (digits==0) break;               // got them all
   211      cut++;
   212      if (cut==DECDPUN) {
   213        up++;
   214        cut=0;
   215        }
   216      } // forever
   217  
   218    return dn;
   219    } // decPackedToNumber
   220