OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / libgcc / config / libbid / bid64_sqrt.c
1 /* Copyright (C) 2007, 2009  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 3, or (at your option) any later
8 version.
9
10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 for more details.
14
15 Under Section 7 of GPL version 3, you are granted additional
16 permissions described in the GCC Runtime Library Exception, version
17 3.1, as published by the Free Software Foundation.
18
19 You should have received a copy of the GNU General Public License and
20 a copy of the GCC Runtime Library Exception along with this program;
21 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22 <http://www.gnu.org/licenses/>.  */
23
24 /*****************************************************************************
25  *    BID64 square root
26  *****************************************************************************
27  *
28  *  Algorithm description:
29  *
30  *  if(exponent_x is odd)
31  *     scale coefficient_x by 10, adjust exponent
32  *  - get lower estimate for number of digits in coefficient_x
33  *  - scale coefficient x to between 31 and 33 decimal digits
34  *  - in parallel, check for exact case and return if true
35  *  - get high part of result coefficient using double precision sqrt
36  *  - compute remainder and refine coefficient in one iteration (which 
37  *                                 modifies it by at most 1)
38  *  - result exponent is easy to compute from the adjusted arg. exponent 
39  *
40  ****************************************************************************/
41
42 #include "bid_internal.h"
43 #include "bid_sqrt_macros.h"
44 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
45 #include <fenv.h>
46
47 #define FE_ALL_FLAGS FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW|FE_UNDERFLOW|FE_INEXACT
48 #endif
49
50 extern double sqrt (double);
51
52 #if DECIMAL_CALL_BY_REFERENCE
53
54 void
55 bid64_sqrt (UINT64 * pres,
56             UINT64 *
57             px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
58             _EXC_INFO_PARAM) {
59   UINT64 x;
60 #else
61
62 UINT64
63 bid64_sqrt (UINT64 x _RND_MODE_PARAM _EXC_FLAGS_PARAM
64             _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
65 #endif
66   UINT128 CA, CT;
67   UINT64 sign_x, coefficient_x;
68   UINT64 Q, Q2, A10, C4, R, R2, QE, res;
69   SINT64 D;
70   int_double t_scale;
71   int_float tempx;
72   double da, dq, da_h, da_l, dqe;
73   int exponent_x, exponent_q, bin_expon_cx;
74   int digits_x;
75   int scale;
76 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
77   fexcept_t binaryflags = 0;
78 #endif
79
80 #if DECIMAL_CALL_BY_REFERENCE
81 #if !DECIMAL_GLOBAL_ROUNDING
82   _IDEC_round rnd_mode = *prnd_mode;
83 #endif
84   x = *px;
85 #endif
86
87   // unpack arguments, check for NaN or Infinity
88   if (!unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x)) {
89     // x is Inf. or NaN or 0
90     if ((x & INFINITY_MASK64) == INFINITY_MASK64) {
91       res = coefficient_x;
92       if ((coefficient_x & SSNAN_MASK64) == SINFINITY_MASK64)   // -Infinity
93       {
94         res = NAN_MASK64;
95 #ifdef SET_STATUS_FLAGS
96         __set_status_flags (pfpsf, INVALID_EXCEPTION);
97 #endif
98       }
99 #ifdef SET_STATUS_FLAGS
100       if ((x & SNAN_MASK64) == SNAN_MASK64)     // sNaN
101         __set_status_flags (pfpsf, INVALID_EXCEPTION);
102 #endif
103       BID_RETURN (res & QUIET_MASK64);
104     }
105     // x is 0
106     exponent_x = (exponent_x + DECIMAL_EXPONENT_BIAS) >> 1;
107     res = sign_x | (((UINT64) exponent_x) << 53);
108     BID_RETURN (res);
109   }
110   // x<0?
111   if (sign_x && coefficient_x) {
112     res = NAN_MASK64;
113 #ifdef SET_STATUS_FLAGS
114     __set_status_flags (pfpsf, INVALID_EXCEPTION);
115 #endif
116     BID_RETURN (res);
117   }
118 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
119   (void) fegetexceptflag (&binaryflags, FE_ALL_FLAGS);
120 #endif
121   //--- get number of bits in the coefficient of x ---
122   tempx.d = (float) coefficient_x;
123   bin_expon_cx = ((tempx.i >> 23) & 0xff) - 0x7f;
124   digits_x = estimate_decimal_digits[bin_expon_cx];
125   // add test for range
126   if (coefficient_x >= power10_index_binexp[bin_expon_cx])
127     digits_x++;
128
129   A10 = coefficient_x;
130   if (exponent_x & 1) {
131     A10 = (A10 << 2) + A10;
132     A10 += A10;
133   }
134
135   dqe = sqrt ((double) A10);
136   QE = (UINT32) dqe;
137   if (QE * QE == A10) {
138     res =
139       very_fast_get_BID64 (0, (exponent_x + DECIMAL_EXPONENT_BIAS) >> 1,
140                            QE);
141 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
142     (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS);
143 #endif
144     BID_RETURN (res);
145   }
146   // if exponent is odd, scale coefficient by 10
147   scale = 31 - digits_x;
148   exponent_q = exponent_x - scale;
149   scale += (exponent_q & 1);    // exp. bias is even
150
151   CT = power10_table_128[scale];
152   __mul_64x128_short (CA, coefficient_x, CT);
153
154   // 2^64
155   t_scale.i = 0x43f0000000000000ull;
156   // convert CA to DP
157   da_h = CA.w[1];
158   da_l = CA.w[0];
159   da = da_h * t_scale.d + da_l;
160
161   dq = sqrt (da);
162
163   Q = (UINT64) dq;
164
165   // get sign(sqrt(CA)-Q)
166   R = CA.w[0] - Q * Q;
167   R = ((SINT64) R) >> 63;
168   D = R + R + 1;
169
170   exponent_q = (exponent_q + DECIMAL_EXPONENT_BIAS) >> 1;
171
172 #ifdef SET_STATUS_FLAGS
173   __set_status_flags (pfpsf, INEXACT_EXCEPTION);
174 #endif
175
176 #ifndef IEEE_ROUND_NEAREST
177 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
178   if (!((rnd_mode) & 3)) {
179 #endif
180 #endif
181
182     // midpoint to check
183     Q2 = Q + Q + D;
184     C4 = CA.w[0] << 2;
185
186     // get sign(-sqrt(CA)+Midpoint)
187     R2 = Q2 * Q2 - C4;
188     R2 = ((SINT64) R2) >> 63;
189
190     // adjust Q if R!=R2
191     Q += (D & (R ^ R2));
192 #ifndef IEEE_ROUND_NEAREST
193 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
194   } else {
195     C4 = CA.w[0];
196     Q += D;
197     if ((SINT64) (Q * Q - C4) > 0)
198       Q--;
199     if (rnd_mode == ROUNDING_UP)
200       Q++;
201   }
202 #endif
203 #endif
204
205   res = fast_get_BID64 (0, exponent_q, Q);
206 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
207   (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS);
208 #endif
209   BID_RETURN (res);
210 }
211
212
213 TYPE0_FUNCTION_ARG1 (UINT64, bid64q_sqrt, x)
214
215      UINT256 M256, C4, C8;
216      UINT128 CX, CX2, A10, S2, T128, CS, CSM, CS2, C256, CS1,
217        mul_factor2_long = { {0x0ull, 0x0ull} }, QH, Tmp, TP128, Qh, Ql;
218 UINT64 sign_x, Carry, B10, res, mul_factor, mul_factor2 = 0x0ull, CS0;
219 SINT64 D;
220 int_float fx, f64;
221 int exponent_x, bin_expon_cx, done = 0;
222 int digits, scale, exponent_q = 0, exact = 1, amount, extra_digits;
223 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
224 fexcept_t binaryflags = 0;
225 #endif
226
227         // unpack arguments, check for NaN or Infinity
228 if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) {
229   res = CX.w[1];
230   // NaN ?
231   if ((x.w[1] & 0x7c00000000000000ull) == 0x7c00000000000000ull) {
232 #ifdef SET_STATUS_FLAGS
233     if ((x.w[1] & 0x7e00000000000000ull) == 0x7e00000000000000ull)      // sNaN
234       __set_status_flags (pfpsf, INVALID_EXCEPTION);
235 #endif
236     Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull);
237     Tmp.w[0] = CX.w[0];
238     TP128 = reciprocals10_128[18];
239     __mul_128x128_full (Qh, Ql, Tmp, TP128);
240     amount = recip_scale[18];
241     __shr_128 (Tmp, Qh, amount);
242     res = (CX.w[1] & 0xfc00000000000000ull) | Tmp.w[0];
243     BID_RETURN (res);
244   }
245   // x is Infinity?
246   if ((x.w[1] & 0x7800000000000000ull) == 0x7800000000000000ull) {
247     if (sign_x) {
248       // -Inf, return NaN
249       res = 0x7c00000000000000ull;
250 #ifdef SET_STATUS_FLAGS
251       __set_status_flags (pfpsf, INVALID_EXCEPTION);
252 #endif
253     }
254     BID_RETURN (res);
255   }
256   // x is 0 otherwise
257
258   exponent_x =
259     ((exponent_x - DECIMAL_EXPONENT_BIAS_128) >> 1) +
260     DECIMAL_EXPONENT_BIAS;
261   if (exponent_x < 0)
262     exponent_x = 0;
263   if (exponent_x > DECIMAL_MAX_EXPON_64)
264     exponent_x = DECIMAL_MAX_EXPON_64;
265   //res= sign_x | (((UINT64)exponent_x)<<53);
266   res = get_BID64 (sign_x, exponent_x, 0, rnd_mode, pfpsf);
267   BID_RETURN (res);
268 }
269 if (sign_x) {
270   res = 0x7c00000000000000ull;
271 #ifdef SET_STATUS_FLAGS
272   __set_status_flags (pfpsf, INVALID_EXCEPTION);
273 #endif
274   BID_RETURN (res);
275 }
276 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
277 (void) fegetexceptflag (&binaryflags, FE_ALL_FLAGS);
278 #endif
279
280            // 2^64
281 f64.i = 0x5f800000;
282
283            // fx ~ CX
284 fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0];
285 bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f;
286 digits = estimate_decimal_digits[bin_expon_cx];
287
288 A10 = CX;
289 if (exponent_x & 1) {
290   A10.w[1] = (CX.w[1] << 3) | (CX.w[0] >> 61);
291   A10.w[0] = CX.w[0] << 3;
292   CX2.w[1] = (CX.w[1] << 1) | (CX.w[0] >> 63);
293   CX2.w[0] = CX.w[0] << 1;
294   __add_128_128 (A10, A10, CX2);
295 }
296
297 C256.w[1] = A10.w[1];
298 C256.w[0] = A10.w[0];
299 CS.w[0] = short_sqrt128 (A10);
300 CS.w[1] = 0;
301 mul_factor = 0;
302            // check for exact result  
303 if (CS.w[0] < 10000000000000000ull) {
304   if (CS.w[0] * CS.w[0] == A10.w[0]) {
305     __sqr64_fast (S2, CS.w[0]);
306     if (S2.w[1] == A10.w[1])    // && S2.w[0]==A10.w[0])
307     {
308       res =
309         get_BID64 (0,
310                    ((exponent_x - DECIMAL_EXPONENT_BIAS_128) >> 1) +
311                    DECIMAL_EXPONENT_BIAS, CS.w[0], rnd_mode, pfpsf);
312 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
313       (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS);
314 #endif
315       BID_RETURN (res);
316     }
317   }
318   if (CS.w[0] >= 1000000000000000ull) {
319     done = 1;
320     exponent_q = exponent_x;
321     C256.w[1] = A10.w[1];
322     C256.w[0] = A10.w[0];
323   }
324 #ifdef SET_STATUS_FLAGS
325   __set_status_flags (pfpsf, INEXACT_EXCEPTION);
326 #endif
327   exact = 0;
328 } else {
329   B10 = 0x3333333333333334ull;
330   __mul_64x64_to_128_full (CS2, CS.w[0], B10);
331   CS0 = CS2.w[1] >> 1;
332   if (CS.w[0] != ((CS0 << 3) + (CS0 << 1))) {
333 #ifdef SET_STATUS_FLAGS
334     __set_status_flags (pfpsf, INEXACT_EXCEPTION);
335 #endif
336     exact = 0;
337   }
338   done = 1;
339   CS.w[0] = CS0;
340   exponent_q = exponent_x + 2;
341   mul_factor = 10;
342   mul_factor2 = 100;
343   if (CS.w[0] >= 10000000000000000ull) {
344     __mul_64x64_to_128_full (CS2, CS.w[0], B10);
345     CS0 = CS2.w[1] >> 1;
346     if (CS.w[0] != ((CS0 << 3) + (CS0 << 1))) {
347 #ifdef SET_STATUS_FLAGS
348       __set_status_flags (pfpsf, INEXACT_EXCEPTION);
349 #endif
350       exact = 0;
351     }
352     exponent_q += 2;
353     CS.w[0] = CS0;
354     mul_factor = 100;
355     mul_factor2 = 10000;
356   }
357   if (exact) {
358     CS0 = CS.w[0] * mul_factor;
359     __sqr64_fast (CS1, CS0)
360       if ((CS1.w[0] != A10.w[0]) || (CS1.w[1] != A10.w[1])) {
361 #ifdef SET_STATUS_FLAGS
362       __set_status_flags (pfpsf, INEXACT_EXCEPTION);
363 #endif
364       exact = 0;
365     }
366   }
367 }
368
369 if (!done) {
370   // get number of digits in CX
371   D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1];
372   if (D > 0
373       || (!D && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0]))
374     digits++;
375
376   // if exponent is odd, scale coefficient by 10
377   scale = 31 - digits;
378   exponent_q = exponent_x - scale;
379   scale += (exponent_q & 1);    // exp. bias is even
380
381   T128 = power10_table_128[scale];
382   __mul_128x128_low (C256, CX, T128);
383
384
385   CS.w[0] = short_sqrt128 (C256);
386 }
387    //printf("CS=%016I64x\n",CS.w[0]);
388
389 exponent_q =
390   ((exponent_q - DECIMAL_EXPONENT_BIAS_128) >> 1) +
391   DECIMAL_EXPONENT_BIAS;
392 if ((exponent_q < 0) && (exponent_q + MAX_FORMAT_DIGITS >= 0)) {
393   extra_digits = -exponent_q;
394   exponent_q = 0;
395
396   // get coeff*(2^M[extra_digits])/10^extra_digits
397   __mul_64x64_to_128 (QH, CS.w[0], reciprocals10_64[extra_digits]);
398
399   // now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
400   amount = short_recip_scale[extra_digits];
401
402   CS0 = QH.w[1] >> amount;
403
404 #ifdef SET_STATUS_FLAGS
405   if (exact) {
406     if (CS.w[0] != CS0 * power10_table_128[extra_digits].w[0])
407       exact = 0;
408   }
409   if (!exact)
410     __set_status_flags (pfpsf, UNDERFLOW_EXCEPTION | INEXACT_EXCEPTION);
411 #endif
412
413   CS.w[0] = CS0;
414   if (!mul_factor)
415     mul_factor = 1;
416   mul_factor *= power10_table_128[extra_digits].w[0];
417   __mul_64x64_to_128 (mul_factor2_long, mul_factor, mul_factor);
418   if (mul_factor2_long.w[1])
419     mul_factor2 = 0;
420   else
421     mul_factor2 = mul_factor2_long.w[1];
422 }
423            // 4*C256
424 C4.w[1] = (C256.w[1] << 2) | (C256.w[0] >> 62);
425 C4.w[0] = C256.w[0] << 2;
426
427 #ifndef IEEE_ROUND_NEAREST
428 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
429 if (!((rnd_mode) & 3)) {
430 #endif
431 #endif
432   // compare to midpoints
433   CSM.w[0] = (CS.w[0] + CS.w[0]) | 1;
434   //printf("C256=%016I64x %016I64x, CSM=%016I64x %016I64x %016I64x\n",C4.w[1],C4.w[0],CSM.w[1],CSM.w[0], CS.w[0]);
435   if (mul_factor)
436     CSM.w[0] *= mul_factor;
437   // CSM^2
438   __mul_64x64_to_128 (M256, CSM.w[0], CSM.w[0]);
439   //__mul_128x128_to_256(M256, CSM, CSM);
440
441   if (C4.w[1] > M256.w[1] ||
442       (C4.w[1] == M256.w[1] && C4.w[0] > M256.w[0])) {
443     // round up
444     CS.w[0]++;
445   } else {
446     C8.w[0] = CS.w[0] << 3;
447     C8.w[1] = 0;
448     if (mul_factor) {
449       if (mul_factor2) {
450         __mul_64x64_to_128 (C8, C8.w[0], mul_factor2);
451       } else {
452         __mul_64x128_low (C8, C8.w[0], mul_factor2_long);
453       }
454     }
455     // M256 - 8*CSM
456     __sub_borrow_out (M256.w[0], Carry, M256.w[0], C8.w[0]);
457     M256.w[1] = M256.w[1] - C8.w[1] - Carry;
458
459     // if CSM' > C256, round up
460     if (M256.w[1] > C4.w[1] ||
461         (M256.w[1] == C4.w[1] && M256.w[0] > C4.w[0])) {
462       // round down
463       if (CS.w[0])
464         CS.w[0]--;
465     }
466   }
467 #ifndef IEEE_ROUND_NEAREST
468 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
469 } else {
470   CS.w[0]++;
471   CSM.w[0] = CS.w[0];
472   C8.w[0] = CSM.w[0] << 1;
473   if (mul_factor)
474     CSM.w[0] *= mul_factor;
475   __mul_64x64_to_128 (M256, CSM.w[0], CSM.w[0]);
476   C8.w[1] = 0;
477   if (mul_factor) {
478     if (mul_factor2) {
479       __mul_64x64_to_128 (C8, C8.w[0], mul_factor2);
480     } else {
481       __mul_64x128_low (C8, C8.w[0], mul_factor2_long);
482     }
483   }
484   //printf("C256=%016I64x %016I64x, CSM=%016I64x %016I64x %016I64x\n",C256.w[1],C256.w[0],M256.w[1],M256.w[0], CS.w[0]);
485
486   if (M256.w[1] > C256.w[1] ||
487       (M256.w[1] == C256.w[1] && M256.w[0] > C256.w[0])) {
488     __sub_borrow_out (M256.w[0], Carry, M256.w[0], C8.w[0]);
489     M256.w[1] = M256.w[1] - Carry - C8.w[1];
490     M256.w[0]++;
491     if (!M256.w[0]) {
492       M256.w[1]++;
493
494     }
495
496     if ((M256.w[1] > C256.w[1] ||
497          (M256.w[1] == C256.w[1] && M256.w[0] > C256.w[0]))
498         && (CS.w[0] > 1)) {
499
500       CS.w[0]--;
501
502       if (CS.w[0] > 1) {
503         __sub_borrow_out (M256.w[0], Carry, M256.w[0], C8.w[0]);
504         M256.w[1] = M256.w[1] - Carry - C8.w[1];
505         M256.w[0]++;
506         if (!M256.w[0]) {
507           M256.w[1]++;
508         }
509
510         if (M256.w[1] > C256.w[1] ||
511             (M256.w[1] == C256.w[1] && M256.w[0] > C256.w[0]))
512           CS.w[0]--;
513       }
514     }
515   }
516
517   else {
518                                 /*__add_carry_out(M256.w[0], Carry, M256.w[0], C8.w[0]);
519                                 M256.w[1] = M256.w[1] + Carry + C8.w[1];
520                                 M256.w[0]++;
521                                 if(!M256.w[0]) 
522                                 {
523                                         M256.w[1]++;
524                                 }
525                                 CS.w[0]++;
526                         if(M256.w[1]<C256.w[1] ||
527                                 (M256.w[1]==C256.w[1] && M256.w[0]<=C256.w[0]))
528                         {
529                                 CS.w[0]++;
530                         }*/
531     CS.w[0]++;
532   }
533   //printf("C256=%016I64x %016I64x, CSM=%016I64x %016I64x %016I64x %d\n",C4.w[1],C4.w[0],M256.w[1],M256.w[0], CS.w[0], exact);
534   // RU?
535   if (((rnd_mode) != ROUNDING_UP) || exact) {
536     if (CS.w[0])
537       CS.w[0]--;
538   }
539
540 }
541 #endif
542 #endif
543  //printf("C256=%016I64x %016I64x, CSM=%016I64x %016I64x %016I64x %d\n",C4.w[1],C4.w[0],M256.w[1],M256.w[0], CS.w[0], exact);
544
545 res = get_BID64 (0, exponent_q, CS.w[0], rnd_mode, pfpsf);
546 #ifdef UNCHANGED_BINARY_STATUS_FLAGS
547 (void) fesetexceptflag (&binaryflags, FE_ALL_FLAGS);
548 #endif
549 BID_RETURN (res);
550
551
552 }