1 /* mpfr_hypot -- Euclidean distance 2 3 Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramel projects, INRIA. 5 6 This file is part of the GNU MPFR Library. 7 8 The GNU MPFR Library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or (at your 11 option) any later version. 12 13 The GNU MPFR Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ 22 23 #define MPFR_NEED_LONGLONG_H 24 #include "mpfr-impl.h" 25 26 /* The computation of hypot of x and y is done by * 27 * hypot(x,y)= sqrt(x^2+y^2) = z */ 28 29 int 30 mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd_mode) 31 { 32 int inexact, exact; 33 mpfr_t t, te, ti; /* auxiliary variables */ 34 mpfr_prec_t N, Nz; /* size variables */ 35 mpfr_prec_t Nt; /* precision of the intermediary variable */ 36 mpfr_prec_t threshold; 37 mpfr_exp_t Ex, sh; 38 mpfr_uexp_t diff_exp; 39 40 MPFR_SAVE_EXPO_DECL (expo); 41 MPFR_ZIV_DECL (loop); 42 MPFR_BLOCK_DECL (flags); 43 44 MPFR_LOG_FUNC 45 (("x[%Pu]=%.*Rg y[%Pu]=%.*Rg rnd=%d", 46 mpfr_get_prec (x), mpfr_log_prec, x, 47 mpfr_get_prec (y), mpfr_log_prec, y, rnd_mode), 48 ("z[%Pu]=%.*Rg inexact=%d", 49 mpfr_get_prec (z), mpfr_log_prec, z, inexact)); 50 51 /* particular cases */ 52 if (MPFR_ARE_SINGULAR (x, y)) 53 { 54 if (MPFR_IS_INF (x) || MPFR_IS_INF (y)) 55 { 56 /* Return +inf, even when the other number is NaN. */ 57 MPFR_SET_INF (z); 58 MPFR_SET_POS (z); 59 MPFR_RET (0); 60 } 61 else if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y)) 62 { 63 MPFR_SET_NAN (z); 64 MPFR_RET_NAN; 65 } 66 else if (MPFR_IS_ZERO (x)) 67 return mpfr_abs (z, y, rnd_mode); 68 else /* y is necessarily 0 */ 69 return mpfr_abs (z, x, rnd_mode); 70 } 71 72 if (mpfr_cmpabs (x, y) < 0) 73 { 74 mpfr_srcptr u; 75 u = x; 76 x = y; 77 y = u; 78 } 79 80 /* now |x| >= |y| */ 81 82 Ex = MPFR_GET_EXP (x); 83 diff_exp = (mpfr_uexp_t) Ex - MPFR_GET_EXP (y); 84 85 N = MPFR_PREC (x); /* Precision of input variable */ 86 Nz = MPFR_PREC (z); /* Precision of output variable */ 87 threshold = (MAX (N, Nz) + (rnd_mode == MPFR_RNDN ? 1 : 0)) << 1; 88 if (rnd_mode == MPFR_RNDA) 89 rnd_mode = MPFR_RNDU; /* since the result is positive, RNDA = RNDU */ 90 91 /* Is |x| a suitable approximation to the precision Nz ? 92 (see algorithms.tex for explanations) */ 93 if (diff_exp > threshold) 94 /* result is |x| or |x|+ulp(|x|,Nz) */ 95 { 96 if (MPFR_UNLIKELY (rnd_mode == MPFR_RNDU)) 97 { 98 /* If z > abs(x), then it was already rounded up; otherwise 99 z = abs(x), and we need to add one ulp due to y. */ 100 if (mpfr_abs (z, x, rnd_mode) == 0) 101 mpfr_nexttoinf (z); 102 MPFR_RET (1); 103 } 104 else /* MPFR_RNDZ, MPFR_RNDD, MPFR_RNDN */ 105 { 106 if (MPFR_LIKELY (Nz >= N)) 107 { 108 mpfr_abs (z, x, rnd_mode); /* exact */ 109 MPFR_RET (-1); 110 } 111 else 112 { 113 MPFR_SET_EXP (z, Ex); 114 MPFR_SET_SIGN (z, 1); 115 MPFR_RNDRAW_GEN (inexact, z, MPFR_MANT (x), N, rnd_mode, 1, 116 goto addoneulp, 117 if (MPFR_UNLIKELY (++ MPFR_EXP (z) > 118 __gmpfr_emax)) 119 return mpfr_overflow (z, rnd_mode, 1); 120 ); 121 122 if (MPFR_UNLIKELY (inexact == 0)) 123 inexact = -1; 124 MPFR_RET (inexact); 125 } 126 } 127 } 128 129 /* General case */ 130 131 N = MAX (MPFR_PREC (x), MPFR_PREC (y)); 132 133 /* working precision */ 134 Nt = Nz + MPFR_INT_CEIL_LOG2 (Nz) + 4; 135 136 mpfr_init2 (t, Nt); 137 mpfr_init2 (te, Nt); 138 mpfr_init2 (ti, Nt); 139 140 MPFR_SAVE_EXPO_MARK (expo); 141 142 /* Scale x and y to avoid overflow/underflow in x^2 and overflow in y^2 143 (as |x| >= |y|). The scaling of y can underflow only when the target 144 precision is huge, otherwise the case would already have been handled 145 by the diff_exp > threshold code. */ 146 sh = mpfr_get_emax () / 2 - Ex - 1; 147 148 MPFR_ZIV_INIT (loop, Nt); 149 for (;;) 150 { 151 mpfr_prec_t err; 152 153 exact = mpfr_mul_2si (te, x, sh, MPFR_RNDZ); 154 exact |= mpfr_mul_2si (ti, y, sh, MPFR_RNDZ); 155 exact |= mpfr_sqr (te, te, MPFR_RNDZ); 156 /* Use fma in order to avoid underflow when diff_exp<=MPFR_EMAX_MAX-2 */ 157 exact |= mpfr_fma (t, ti, ti, te, MPFR_RNDZ); 158 exact |= mpfr_sqrt (t, t, MPFR_RNDZ); 159 160 err = Nt < N ? 4 : 2; 161 if (MPFR_LIKELY (exact == 0 162 || MPFR_CAN_ROUND (t, Nt-err, Nz, rnd_mode))) 163 break; 164 165 MPFR_ZIV_NEXT (loop, Nt); 166 mpfr_set_prec (t, Nt); 167 mpfr_set_prec (te, Nt); 168 mpfr_set_prec (ti, Nt); 169 } 170 MPFR_ZIV_FREE (loop); 171 172 MPFR_BLOCK (flags, inexact = mpfr_div_2si (z, t, sh, rnd_mode)); 173 MPFR_ASSERTD (exact == 0 || inexact != 0); 174 175 mpfr_clear (t); 176 mpfr_clear (ti); 177 mpfr_clear (te); 178 179 /* 180 exact inexact 181 0 0 result is exact, ternary flag is 0 182 0 non zero t is exact, ternary flag given by inexact 183 1 0 impossible (see above) 184 1 non zero ternary flag given by inexact 185 */ 186 187 MPFR_SAVE_EXPO_FREE (expo); 188 189 if (MPFR_OVERFLOW (flags)) 190 mpfr_set_overflow (); 191 /* hypot(x,y) >= |x|, thus underflow is not possible. */ 192 193 return mpfr_check_range (z, inexact, rnd_mode); 194 } 195