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