OSDN Git Service

config/
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid128_to_string.c
1 /* Copyright (C) 2007  Free Software Foundation, Inc.
2
3 This file is part of GCC.
4
5 GCC is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2, or (at your option) any later
8 version.
9
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file.  (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
17 executable.)
18
19 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING.  If not, write to the Free
26 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.  */
28
29 /*****************************************************************************
30  *    BID128_to_string
31  ****************************************************************************/
32
33 #include <stdio.h>
34 #include "bid_internal.h"
35 #include "bid128_2_str.h"
36 #include "bid128_2_str_macros.h"
37
38 extern int __bid128_coeff_2_string (UINT64 X_hi, UINT64 X_lo,
39                                   char *char_ptr);
40
41 #if DECIMAL_CALL_BY_REFERENCE
42
43 void
44 __bid128_to_string (char *str,
45                   UINT128 *
46                   px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
47                   _EXC_INFO_PARAM) {
48   UINT128 x;
49 #else
50
51 void
52 __bid128_to_string (char *str,
53                   UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM
54                   _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
55 #endif
56   UINT64 x_sign;
57   UINT64 x_exp;
58   int exp;      // unbiased exponent
59   // Note: C1.w[1], C1.w[0] represent x_signif_hi, x_signif_lo (all are UINT64)
60   int ind;
61   UINT128 C1;
62   unsigned int k = 0; // pointer in the string
63   unsigned int d0, d123;
64   UINT64 HI_18Dig, LO_18Dig, Tmp;
65   UINT32 MiDi[12], *ptr;
66   char *c_ptr_start, *c_ptr;
67   int midi_ind, k_lcv, len;
68
69 #if DECIMAL_CALL_BY_REFERENCE
70 #if !DECIMAL_GLOBAL_ROUNDING
71   _IDEC_round rnd_mode = *prnd_mode;
72 #endif
73   x = *px;
74 #endif
75
76   // check for NaN or Infinity
77   if ((x.w[1] & MASK_SPECIAL) == MASK_SPECIAL) {
78     // x is special
79     if ((x.w[1] & MASK_NAN) == MASK_NAN) { // x is NAN
80       if ((x.w[1] & MASK_SNAN) == MASK_SNAN) { // x is SNAN
81         // set invalid flag
82         *pfpsf |= INVALID_EXCEPTION;
83         str[0] = 'S';
84         str[1] = 'N';
85         str[2] = 'a';
86         str[3] = 'N';
87         str[4] = '\0';
88       } else { // x is QNaN
89         str[0] = 'Q';
90         str[1] = 'N';
91         str[2] = 'a';
92         str[3] = 'N';
93         str[4] = '\0';
94       }
95     } else { // x is not a NaN, so it must be infinity
96       if ((x.w[1] & MASK_SIGN) == 0x0ull) { // x is +inf
97         str[0] = '+';
98         str[1] = 'I';
99         str[2] = 'n';
100         str[3] = 'f';
101         str[4] = '\0';
102       } else { // x is -inf 
103         str[0] = '-';
104         str[1] = 'I';
105         str[2] = 'n';
106         str[3] = 'f';
107         str[4] = '\0';
108       }
109     }
110     return;
111   } else if (((x.w[1] & MASK_COEFF) == 0x0ull) && (x.w[0] == 0x0ull)) {
112     // x is 0
113     len = 0;
114
115     //determine if +/-
116     if (x.w[1] & MASK_SIGN)
117       str[len++] = '-';
118     else
119       str[len++] = '+';
120     str[len++] = '0';
121     str[len++] = 'E';
122
123     // extract the exponent and print
124     exp = (int) (((x.w[1] & MASK_EXP) >> 49) - 6176);
125     if (exp >= 0) {
126       str[len++] = '+';
127       len += sprintf (str + len, "%u", exp);// should not use sprintf (should 
128       // use sophisticated algorithm, since we know range of exp is limited)
129       str[len++] = '\0';
130     } else {
131       len += sprintf (str + len, "%d", exp);// should not use sprintf (should 
132       // use sophisticated algorithm, since we know range of exp is limited)
133       str[len++] = '\0';
134     }
135     return;
136   } else { // x is not special and is not zero
137     // unpack x
138     x_sign = x.w[1] & MASK_SIGN;// 0 for positive, MASK_SIGN for negative
139     x_exp = x.w[1] & MASK_EXP;// biased and shifted left 49 bit positions
140     C1.w[1] = x.w[1] & MASK_COEFF;
141     C1.w[0] = x.w[0];
142     exp = (x_exp >> 49) - 6176;
143
144     // determine sign's representation as a char
145     if (x_sign)
146       str[k++] = '-';// negative number
147     else
148       str[k++] = '+';// positive number
149
150     // determine coefficient's representation as a decimal string
151
152     // if zero or non-canonical, set coefficient to '0'
153     if ((C1.w[1] > 0x0001ed09bead87c0ull) || 
154         (C1.w[1] == 0x0001ed09bead87c0ull && 
155         (C1.w[0] > 0x378d8e63ffffffffull)) || 
156         ((x.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) || 
157         ((C1.w[1] == 0) && (C1.w[0] == 0))) {
158       str[k++] = '0';
159     } else {
160       /* ****************************************************
161          This takes a bid coefficient in C1.w[1],C1.w[0] 
162          and put the converted character sequence at location 
163          starting at &(str[k]). The function returns the number
164          of MiDi returned. Note that the character sequence 
165          does not have leading zeros EXCEPT when the input is of
166          zero value. It will then output 1 character '0'
167          The algorithm essentailly tries first to get a sequence of
168          Millenial Digits "MiDi" and then uses table lookup to get the
169          character strings of these MiDis.
170          **************************************************** */
171       /* Algorithm first decompose possibly 34 digits in hi and lo
172          18 digits. (The high can have at most 16 digits). It then
173          uses macro that handle 18 digit portions.
174          The first step is to get hi and lo such that
175          2^(64) C1.w[1] + C1.w[0] = hi * 10^18  + lo,   0 <= lo < 10^18.
176          We use a table lookup method to obtain the hi and lo 18 digits.
177          [C1.w[1],C1.w[0]] = c_8 2^(107) + c_7 2^(101) + ... + c_0 2^(59) + d
178          where 0 <= d < 2^59 and each c_j has 6 bits. Because d fits in
179          18 digits,  we set hi = 0, and lo = d to begin with.
180          We then retrieve from a table, for j = 0, 1, ..., 8
181          that gives us A and B where c_j 2^(59+6j) = A * 10^18 + B.
182          hi += A ; lo += B; After each accumulation into lo, we normalize 
183          immediately. So at the end, we have the decomposition as we need. */
184
185       Tmp = C1.w[0] >> 59;
186       LO_18Dig = (C1.w[0] << 5) >> 5;
187       Tmp += (C1.w[1] << 5);
188       HI_18Dig = 0;
189       k_lcv = 0;
190       // Tmp = {C1.w[1]{49:0}, C1.w[0]{63:59}}
191       // Lo_18Dig = {C1.w[0]{58:0}}
192
193       while (Tmp) {
194         midi_ind = (int) (Tmp & 0x000000000000003FLL);
195         midi_ind <<= 1;
196         Tmp >>= 6;
197         HI_18Dig += __bid_mod10_18_tbl[k_lcv][midi_ind++];
198         LO_18Dig += __bid_mod10_18_tbl[k_lcv++][midi_ind];
199         __L0_Normalize_10to18 (HI_18Dig, LO_18Dig);
200       }
201       ptr = MiDi;
202       if (HI_18Dig == 0LL) {
203         __L1_Split_MiDi_6_Lead (LO_18Dig, ptr);
204       } else {
205         __L1_Split_MiDi_6_Lead (HI_18Dig, ptr);
206         __L1_Split_MiDi_6 (LO_18Dig, ptr);
207       }
208       len = ptr - MiDi;
209       c_ptr_start = &(str[k]);
210       c_ptr = c_ptr_start;
211
212       /* now convert the MiDi into character strings */
213       __L0_MiDi2Str_Lead (MiDi[0], c_ptr);
214       for (k_lcv = 1; k_lcv < len; k_lcv++) {
215         __L0_MiDi2Str (MiDi[k_lcv], c_ptr);
216       }
217       k = k + (c_ptr - c_ptr_start);
218     }
219
220     // print E and sign of exponent
221     str[k++] = 'E';
222     if (exp < 0) {
223       exp = -exp;
224       str[k++] = '-';
225     } else {
226       str[k++] = '+';
227     }
228
229     // determine exponent's representation as a decimal string
230     // d0 = exp / 1000;
231     // Use Property 1
232     d0 = (exp * 0x418a) >> 24;// 0x418a * 2^-24 = (10^(-3))RP,15
233     d123 = exp - 1000 * d0;
234
235     if (d0) { // 1000 <= exp <= 6144 => 4 digits to return
236       str[k++] = d0 + 0x30;// ASCII for decimal digit d0
237       ind = 3 * d123;
238       str[k++] = __bid_char_table3[ind];
239       str[k++] = __bid_char_table3[ind + 1];
240       str[k++] = __bid_char_table3[ind + 2];
241     } else { // 0 <= exp <= 999 => d0 = 0
242       if (d123 < 10) { // 0 <= exp <= 9 => 1 digit to return
243         str[k++] = d123 + 0x30;// ASCII
244       } else if (d123 < 100) { // 10 <= exp <= 99 => 2 digits to return
245         ind = 2 * (d123 - 10);
246         str[k++] = __bid_char_table2[ind];
247         str[k++] = __bid_char_table2[ind + 1];
248       } else { // 100 <= exp <= 999 => 3 digits to return
249         ind = 3 * d123;
250         str[k++] = __bid_char_table3[ind];
251         str[k++] = __bid_char_table3[ind + 1];
252         str[k++] = __bid_char_table3[ind + 2];
253       }
254     }
255     str[k] = '\0';
256
257   }
258   return;
259
260 }