1169695Skan/* Utility functions for decimal floating point support via decNumber. 2169695Skan Copyright (C) 2005 Free Software Foundation, Inc. 3169695Skan Contributed by IBM Corporation. Author Mike Cowlishaw. 4169695Skan 5169695Skan This file is part of GCC. 6169695Skan 7169695Skan GCC is free software; you can redistribute it and/or modify it under 8169695Skan the terms of the GNU General Public License as published by the Free 9169695Skan Software Foundation; either version 2, or (at your option) any later 10169695Skan version. 11169695Skan 12169695Skan In addition to the permissions in the GNU General Public License, 13169695Skan the Free Software Foundation gives you unlimited permission to link 14169695Skan the compiled version of this file into combinations with other 15169695Skan programs, and to distribute those combinations without any 16169695Skan restriction coming from the use of this file. (The General Public 17169695Skan License restrictions do apply in other respects; for example, they 18169695Skan cover modification of the file, and distribution when not linked 19169695Skan into a combine executable.) 20169695Skan 21169695Skan GCC is distributed in the hope that it will be useful, but WITHOUT ANY 22169695Skan WARRANTY; without even the implied warranty of MERCHANTABILITY or 23169695Skan FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24169695Skan for more details. 25169695Skan 26169695Skan You should have received a copy of the GNU General Public License 27169695Skan along with GCC; see the file COPYING. If not, write to the Free 28169695Skan Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 29169695Skan 02110-1301, USA. */ 30169695Skan 31169695Skan#include "config.h" 32169695Skan#include "decNumber.h" /* base number library */ 33169695Skan#include "decNumberLocal.h" /* decNumber local types, etc. */ 34169695Skan#include "decUtility.h" /* utility routines */ 35169695Skan 36169695Skan/* ================================================================== */ 37169695Skan/* Shared utility routines */ 38169695Skan/* ================================================================== */ 39169695Skan 40169695Skan/* define and include the conversion tables to use */ 41169695Skan#define DEC_BIN2DPD 1 /* used for all sizes */ 42169695Skan#if DECDPUN==3 43169695Skan#define DEC_DPD2BIN 1 44169695Skan#else 45169695Skan#define DEC_DPD2BCD 1 46169695Skan#endif 47169695Skan#include "decDPD.h" /* lookup tables */ 48169695Skan 49169695Skan/* The maximum number of decNumberUnits we need for a working copy of */ 50169695Skan/* the units array is the ceiling of digits/DECDPUN, where digits is */ 51169695Skan/* the maximum number of digits in any of the formats for which this */ 52169695Skan/* is used. We do not want to include decimal128.h, so, as a very */ 53169695Skan/* special case, that number is defined here. */ 54169695Skan#define DECMAX754 34 55169695Skan#define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN) 56169695Skan 57169695Skan/* ------------------------------------------------------------------ */ 58169695Skan/* decDensePackCoeff -- densely pack coefficient into DPD form */ 59169695Skan/* */ 60169695Skan/* dn is the source number (assumed valid, max DECMAX754 digits) */ 61169695Skan/* bytes is the target's byte array */ 62169695Skan/* len is length of target format's byte array */ 63169695Skan/* shift is the number of 0 digits to add on the right (normally 0) */ 64169695Skan/* */ 65169695Skan/* The coefficient must be known small enough to fit, and is filled */ 66169695Skan/* in from the right (least significant first). Note that the full */ 67169695Skan/* coefficient is copied, including the leading 'odd' digit. This */ 68169695Skan/* digit is retrieved and packed into the combination field by the */ 69169695Skan/* caller. */ 70169695Skan/* */ 71169695Skan/* shift is used for 'fold-down' padding. */ 72169695Skan/* */ 73169695Skan/* No error is possible. */ 74169695Skan/* ------------------------------------------------------------------ */ 75169695Skanvoid 76169695SkandecDensePackCoeff (const decNumber * dn, uByte * bytes, Int len, Int shift) 77169695Skan{ 78169695Skan Int cut; /* work */ 79169695Skan Int n; /* output bunch counter */ 80169695Skan Int digits = dn->digits; /* digit countdown */ 81169695Skan uInt dpd; /* densely packed decimal value */ 82169695Skan uInt bin; /* binary value 0-999 */ 83169695Skan uByte *bout; /* -> current output byte */ 84169695Skan const Unit *inu = dn->lsu; /* -> current input unit */ 85169695Skan Unit uar[DECMAXUNITS]; /* working copy of units, iff shifted */ 86169695Skan#if DECDPUN!=3 /* not fast path */ 87169695Skan Unit in; /* current input unit */ 88169695Skan#endif 89169695Skan 90169695Skan if (shift != 0) 91169695Skan { /* shift towards most significant required */ 92169695Skan /* shift the units array to the left by pad digits and copy */ 93169695Skan /* [this code is a special case of decShiftToMost, which could */ 94169695Skan /* be used instead if exposed and the array were copied first] */ 95169695Skan Unit *target, *first; /* work */ 96169695Skan const Unit *source; /* work */ 97169695Skan uInt next = 0; /* work */ 98169695Skan 99169695Skan source = dn->lsu + D2U (digits) - 1; /* where msu comes from */ 100169695Skan first = uar + D2U (digits + shift) - 1; /* where msu will end up */ 101169695Skan target = uar + D2U (digits) - 1 + D2U (shift); /* where upper part of first cut goes */ 102169695Skan 103169695Skan cut = (DECDPUN - shift % DECDPUN) % DECDPUN; 104169695Skan for (; source >= dn->lsu; source--, target--) 105169695Skan { 106169695Skan /* split the source Unit and accumulate remainder for next */ 107169695Skan uInt rem = *source % powers[cut]; 108169695Skan next += *source / powers[cut]; 109169695Skan if (target <= first) 110169695Skan *target = (Unit) next; /* write to target iff valid */ 111169695Skan next = rem * powers[DECDPUN - cut]; /* save remainder for next Unit */ 112169695Skan } 113169695Skan /* propagate remainder to one below and clear the rest */ 114169695Skan for (; target >= uar; target--) 115169695Skan { 116169695Skan *target = (Unit) next; 117169695Skan next = 0; 118169695Skan } 119169695Skan digits += shift; /* add count (shift) of zeros added */ 120169695Skan inu = uar; /* use units in working array */ 121169695Skan } 122169695Skan 123169695Skan /* densely pack the coefficient into the byte array, starting from 124169695Skan the right (optionally padded) */ 125169695Skan bout = &bytes[len - 1]; /* rightmost result byte for phase */ 126169695Skan 127169695Skan#if DECDPUN!=3 /* not fast path */ 128169695Skan in = *inu; /* prime */ 129169695Skan cut = 0; /* at lowest digit */ 130169695Skan bin = 0; /* [keep compiler quiet] */ 131169695Skan#endif 132169695Skan 133169695Skan for (n = 0; digits > 0; n++) 134169695Skan { /* each output bunch */ 135169695Skan#if DECDPUN==3 /* fast path, 3-at-a-time */ 136169695Skan bin = *inu; /* 3 ready for convert */ 137169695Skan digits -= 3; /* [may go negative] */ 138169695Skan inu++; /* may need another */ 139169695Skan 140169695Skan#else /* must collect digit-by-digit */ 141169695Skan Unit dig; /* current digit */ 142169695Skan Int j; /* digit-in-bunch count */ 143169695Skan for (j = 0; j < 3; j++) 144169695Skan { 145169695Skan#if DECDPUN<=4 146169695Skan Unit temp = (Unit) ((uInt) (in * 6554) >> 16); 147169695Skan dig = (Unit) (in - X10 (temp)); 148169695Skan in = temp; 149169695Skan#else 150169695Skan dig = in % 10; 151169695Skan in = in / 10; 152169695Skan#endif 153169695Skan 154169695Skan if (j == 0) 155169695Skan bin = dig; 156169695Skan else if (j == 1) 157169695Skan bin += X10 (dig); 158169695Skan else /* j==2 */ 159169695Skan bin += X100 (dig); 160169695Skan 161169695Skan digits--; 162169695Skan if (digits == 0) 163169695Skan break; /* [also protects *inu below] */ 164169695Skan cut++; 165169695Skan if (cut == DECDPUN) 166169695Skan { 167169695Skan inu++; 168169695Skan in = *inu; 169169695Skan cut = 0; 170169695Skan } 171169695Skan } 172169695Skan#endif 173169695Skan /* here we have 3 digits in bin, or have used all input digits */ 174169695Skan 175169695Skan dpd = BIN2DPD[bin]; 176169695Skan 177169695Skan /* write bunch (bcd) to byte array */ 178169695Skan switch (n & 0x03) 179169695Skan { /* phase 0-3 */ 180169695Skan case 0: 181169695Skan *bout = (uByte) dpd; /* [top 2 bits truncated] */ 182169695Skan bout--; 183169695Skan *bout = (uByte) (dpd >> 8); 184169695Skan break; 185169695Skan case 1: 186169695Skan *bout |= (uByte) (dpd << 2); 187169695Skan bout--; 188169695Skan *bout = (uByte) (dpd >> 6); 189169695Skan break; 190169695Skan case 2: 191169695Skan *bout |= (uByte) (dpd << 4); 192169695Skan bout--; 193169695Skan *bout = (uByte) (dpd >> 4); 194169695Skan break; 195169695Skan case 3: 196169695Skan *bout |= (uByte) (dpd << 6); 197169695Skan bout--; 198169695Skan *bout = (uByte) (dpd >> 2); 199169695Skan bout--; 200169695Skan break; 201169695Skan } /* switch */ 202169695Skan } /* n bunches */ 203169695Skan return; 204169695Skan} 205169695Skan 206169695Skan/* ------------------------------------------------------------------ */ 207169695Skan/* decDenseUnpackCoeff -- unpack a format's coefficient */ 208169695Skan/* */ 209169695Skan/* byte is the source's byte array */ 210169695Skan/* len is length of the source's byte array */ 211169695Skan/* dn is the target number, with 7, 16, or 34-digit space. */ 212169695Skan/* bunches is the count of DPD groups in the decNumber (2, 5, or 11)*/ 213169695Skan/* odd is 1 if there is a non-zero leading 10-bit group containing */ 214169695Skan/* a single digit, 0 otherwise */ 215169695Skan/* */ 216169695Skan/* (This routine works on a copy of the number, if necessary, where */ 217169695Skan/* an extra 10-bit group is prefixed to the coefficient continuation */ 218169695Skan/* to hold the most significant digit if the latter is non-0.) */ 219169695Skan/* */ 220169695Skan/* dn->digits is set, but not the sign or exponent. */ 221169695Skan/* No error is possible [the redundant 888 codes are allowed]. */ 222169695Skan/* ------------------------------------------------------------------ */ 223169695Skanvoid 224169695SkandecDenseUnpackCoeff (const uByte * bytes, Int len, decNumber * dn, 225169695Skan Int bunches, Int odd) 226169695Skan{ 227169695Skan uInt dpd = 0; /* collector for 10 bits */ 228169695Skan Int n; /* counter */ 229169695Skan const uByte *bin; /* -> current input byte */ 230169695Skan Unit *uout = dn->lsu; /* -> current output unit */ 231169695Skan Unit out = 0; /* accumulator */ 232169695Skan Int cut = 0; /* power of ten in current unit */ 233169695Skan Unit *last = uout; /* will be unit containing msd */ 234169695Skan#if DECDPUN!=3 235169695Skan uInt bcd; /* BCD result */ 236169695Skan uInt nibble; /* work */ 237169695Skan#endif 238169695Skan 239169695Skan /* Expand the densely-packed integer, right to left */ 240169695Skan bin = &bytes[len - 1]; /* next input byte to use */ 241169695Skan for (n = 0; n < bunches + odd; n++) 242169695Skan { /* N bunches of 10 bits */ 243169695Skan /* assemble the 10 bits */ 244169695Skan switch (n & 0x03) 245169695Skan { /* phase 0-3 */ 246169695Skan case 0: 247169695Skan dpd = *bin; 248169695Skan bin--; 249169695Skan dpd |= (*bin & 0x03) << 8; 250169695Skan break; 251169695Skan case 1: 252169695Skan dpd = (unsigned) *bin >> 2; 253169695Skan bin--; 254169695Skan dpd |= (*bin & 0x0F) << 6; 255169695Skan break; 256169695Skan case 2: 257169695Skan dpd = (unsigned) *bin >> 4; 258169695Skan bin--; 259169695Skan dpd |= (*bin & 0x3F) << 4; 260169695Skan break; 261169695Skan case 3: 262169695Skan dpd = (unsigned) *bin >> 6; 263169695Skan bin--; 264169695Skan dpd |= (*bin) << 2; 265169695Skan bin--; 266169695Skan break; 267169695Skan } /*switch */ 268169695Skan 269169695Skan#if DECDPUN==3 270169695Skan if (dpd == 0) 271169695Skan *uout = 0; 272169695Skan else 273169695Skan { 274169695Skan *uout = DPD2BIN[dpd]; /* convert 10 bits to binary 0-999 */ 275169695Skan last = uout; /* record most significant unit */ 276169695Skan } 277169695Skan uout++; 278169695Skan 279169695Skan#else /* DECDPUN!=3 */ 280169695Skan if (dpd == 0) 281169695Skan { /* fastpath [e.g., leading zeros] */ 282169695Skan cut += 3; 283169695Skan for (; cut >= DECDPUN;) 284169695Skan { 285169695Skan cut -= DECDPUN; 286169695Skan *uout = out; 287169695Skan uout++; 288169695Skan out = 0; 289169695Skan } 290169695Skan continue; 291169695Skan } 292169695Skan bcd = DPD2BCD[dpd]; /* convert 10 bits to 12 bits BCD */ 293169695Skan /* now split the 3 BCD nibbles into bytes, and accumulate into units */ 294169695Skan /* If this is the last bunch and it is an odd one, we only have one */ 295169695Skan /* nibble to handle [extras could overflow a Unit] */ 296169695Skan nibble = bcd & 0x000f; 297169695Skan if (nibble) 298169695Skan { 299169695Skan last = uout; 300169695Skan out = (Unit) (out + nibble * powers[cut]); 301169695Skan } 302169695Skan cut++; 303169695Skan if (cut == DECDPUN) 304169695Skan { 305169695Skan *uout = out; 306169695Skan uout++; 307169695Skan cut = 0; 308169695Skan out = 0; 309169695Skan } 310169695Skan if (n < bunches) 311169695Skan { 312169695Skan nibble = bcd & 0x00f0; 313169695Skan if (nibble) 314169695Skan { 315169695Skan nibble >>= 4; 316169695Skan last = uout; 317169695Skan out = (Unit) (out + nibble * powers[cut]); 318169695Skan } 319169695Skan cut++; 320169695Skan if (cut == DECDPUN) 321169695Skan { 322169695Skan *uout = out; 323169695Skan uout++; 324169695Skan cut = 0; 325169695Skan out = 0; 326169695Skan } 327169695Skan nibble = bcd & 0x0f00; 328169695Skan if (nibble) 329169695Skan { 330169695Skan nibble >>= 8; 331169695Skan last = uout; 332169695Skan out = (Unit) (out + nibble * powers[cut]); 333169695Skan } 334169695Skan cut++; 335169695Skan if (cut == DECDPUN) 336169695Skan { 337169695Skan *uout = out; 338169695Skan uout++; 339169695Skan cut = 0; 340169695Skan out = 0; 341169695Skan } 342169695Skan } 343169695Skan#endif 344169695Skan } /* n */ 345169695Skan if (cut != 0) 346169695Skan *uout = out; /* write out final unit */ 347169695Skan 348169695Skan /* here, last points to the most significant unit with digits */ 349169695Skan /* we need to inspect it to get final digits count */ 350169695Skan dn->digits = (last - dn->lsu) * DECDPUN; /* floor of digits */ 351169695Skan for (cut = 0; cut < DECDPUN; cut++) 352169695Skan { 353169695Skan if (*last < powers[cut]) 354169695Skan break; 355169695Skan dn->digits++; 356169695Skan } 357169695Skan if (dn->digits == 0) 358169695Skan dn->digits++; /* zero has one digit */ 359169695Skan return; 360169695Skan} 361