1 /* mpfr_round_near_x -- Round a floating point number nears another one. 2 3 Copyright 2005-2023 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramba 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 https://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 #include "mpfr-impl.h" 24 25 /* Use MPFR_FAST_COMPUTE_IF_SMALL_INPUT instead (a simple wrapper) */ 26 27 /* int mpfr_round_near_x (mpfr_ptr y, mpfr_srcptr v, mpfr_uexp_t err, int dir, 28 mpfr_rnd_t rnd) 29 30 TODO: fix this description. 31 Assuming y = o(f(x)) = o(x + g(x)) with |g(x)| < 2^(EXP(v)-error) 32 If x is small enough, y ~= v. This function checks and does this. 33 34 It assumes that f(x) is not representable exactly as a FP number. 35 v must not be a singular value (NAN, INF or ZERO), usual values are 36 v=1 or v=x. 37 38 y is the destination (a mpfr_t), v the value to set (a mpfr_t), 39 err the error term (a mpfr_uexp_t) such that |g(x)| < 2^(EXP(x)-err), 40 dir (an int) is the direction of the error (if dir = 0, 41 it rounds toward 0, if dir=1, it rounds away from 0), 42 rnd the rounding mode. 43 44 It returns 0 if it can't round. 45 Otherwise it returns the ternary flag (It can't return an exact value). 46 */ 47 48 /* What "small enough" means? 49 50 We work with the positive values. 51 Assuming err > Prec (y)+1 52 53 i = [ y = o(x)] // i = inexact flag 54 If i == 0 55 Setting x in y is exact. We have: 56 y = [XXXXXXXXX[...]]0[...] + error where [..] are optional zeros 57 if dirError = ToInf, 58 x < f(x) < x + 2^(EXP(x)-err) 59 since x=y, and ulp (y)/2 > 2^(EXP(x)-err), we have: 60 y < f(x) < y+ulp(y) and |y-f(x)| < ulp(y)/2 61 if rnd = RNDN, nothing 62 if rnd = RNDZ, nothing 63 if rnd = RNDA, addoneulp 64 elif dirError = ToZero 65 x -2^(EXP(x)-err) < f(x) < x 66 since x=y, and ulp (y)/2 > 2^(EXP(x)-err), we have: 67 y-ulp(y) < f(x) < y and |y-f(x)| < ulp(y)/2 68 if rnd = RNDN, nothing 69 if rnd = RNDZ, nexttozero 70 if rnd = RNDA, nothing 71 NOTE: err > prec (y)+1 is needed only for RNDN. 72 elif i > 0 and i = EVEN_ROUNDING 73 So rnd = RNDN and we have y = x + ulp(y)/2 74 if dirError = ToZero, 75 we have x -2^(EXP(x)-err) < f(x) < x 76 so y - ulp(y)/2 - 2^(EXP(x)-err) < f(x) < y-ulp(y)/2 77 so y -ulp(y) < f(x) < y-ulp(y)/2 78 => nexttozero(y) 79 elif dirError = ToInf 80 we have x < f(x) < x + 2^(EXP(x)-err) 81 so y - ulp(y)/2 < f(x) < y+ulp(y)/2-ulp(y)/2 82 so y - ulp(y)/2 < f(x) < y 83 => do nothing 84 elif i < 0 and i = -EVEN_ROUNDING 85 So rnd = RNDN and we have y = x - ulp(y)/2 86 if dirError = ToZero, 87 y < f(x) < y + ulp(y)/2 => do nothing 88 if dirError = ToInf 89 y + ulp(y)/2 < f(x) < y + ulp(y) => AddOneUlp 90 elif i > 0 91 we can't have rnd = RNDZ, and prec(x) > prec(y), so ulp(x) < ulp(y) 92 we have y - ulp (y) < x < y 93 or more exactly y - ulp(y) + ulp(x)/2 <= x <= y - ulp(x)/2 94 if rnd = RNDA, 95 if dirError = ToInf, 96 we have x < f(x) < x + 2^(EXP(x)-err) 97 if err > prec (x), 98 we have 2^(EXP(x)-err) < ulp(x), so 2^(EXP(x)-err) <= ulp(x)/2 99 so f(x) <= y - ulp(x)/2+ulp(x)/2 <= y 100 and y - ulp(y) < x < f(x) 101 so we have y - ulp(y) < f(x) < y 102 so do nothing. 103 elif we can round, ie y - ulp(y) < x + 2^(EXP(x)-err) < y 104 we have y - ulp(y) < x < f(x) < x + 2^(EXP(x)-err) < y 105 so do nothing 106 otherwise 107 Wrong. Example X=[0.11101]111111110000 108 + 1111111111111111111.... 109 elif dirError = ToZero 110 we have x - 2^(EXP(x)-err) < f(x) < x 111 so f(x) < x < y 112 if err > prec (x) 113 x-2^(EXP(x)-err) >= x-ulp(x)/2 >= y - ulp(y) + ulp(x)/2-ulp(x)/2 114 so y - ulp(y) < f(x) < y 115 so do nothing 116 elif we can round, ie y - ulp(y) < x - 2^(EXP(x)-err) < y 117 y - ulp(y) < x - 2^(EXP(x)-err) < f(x) < y 118 so do nothing 119 otherwise 120 Wrong. Example: X=[1.111010]00000010 121 - 10000001000000000000100.... 122 elif rnd = RNDN, 123 y - ulp(y)/2 < x < y and we can't have x = y-ulp(y)/2: 124 so we have: 125 y - ulp(y)/2 + ulp(x)/2 <= x <= y - ulp(x)/2 126 if dirError = ToInf 127 we have x < f(x) < x+2^(EXP(x)-err) and ulp(y) > 2^(EXP(x)-err) 128 so y - ulp(y)/2 + ulp (x)/2 < f(x) < y + ulp (y)/2 - ulp (x)/2 129 we can round but we can't compute inexact flag. 130 if err > prec (x) 131 y - ulp(y)/2 + ulp (x)/2 < f(x) < y + ulp(x)/2 - ulp(x)/2 132 so y - ulp(y)/2 + ulp (x)/2 < f(x) < y 133 we can round and compute inexact flag. do nothing 134 elif we can round, ie y - ulp(y)/2 < x + 2^(EXP(x)-err) < y 135 we have y - ulp(y)/2 + ulp (x)/2 < f(x) < y 136 so do nothing 137 otherwise 138 Wrong 139 elif dirError = ToZero 140 we have x -2^(EXP(x)-err) < f(x) < x and ulp(y)/2 > 2^(EXP(x)-err) 141 so y-ulp(y)+ulp(x)/2 < f(x) < y - ulp(x)/2 142 if err > prec (x) 143 x- ulp(x)/2 < f(x) < x 144 so y - ulp(y)/2+ulp(x)/2 - ulp(x)/2 < f(x) < x <= y - ulp(x)/2 < y 145 do nothing 146 elif we can round, ie y-ulp(y)/2 < x-2^(EXP(x)-err) < y 147 we have y-ulp(y)/2 < x-2^(EXP(x)-err) < f(x) < x < y 148 do nothing 149 otherwise 150 Wrong 151 elif i < 0 152 same thing? 153 */ 154 155 int 156 mpfr_round_near_x (mpfr_ptr y, mpfr_srcptr v, mpfr_uexp_t err, int dir, 157 mpfr_rnd_t rnd) 158 { 159 int inexact, sign; 160 mpfr_flags_t old_flags = __gmpfr_flags; 161 162 if (rnd == MPFR_RNDF) 163 rnd = MPFR_RNDZ; 164 165 MPFR_ASSERTD (!MPFR_IS_SINGULAR (v)); 166 MPFR_ASSERTD (dir == 0 || dir == 1); 167 168 /* First check if we can round. The test is more restrictive than 169 necessary. Note that if err is not representable in an mpfr_exp_t, 170 then err > MPFR_PREC (v) and the conversion to mpfr_exp_t will not 171 occur. */ 172 if (!(err > MPFR_PREC (y) + 1 173 && (err > MPFR_PREC (v) 174 || mpfr_round_p (MPFR_MANT (v), MPFR_LIMB_SIZE (v), 175 (mpfr_exp_t) err, 176 MPFR_PREC (y) + (rnd == MPFR_RNDN))))) 177 /* If we assume we can not round, return 0, and y is not modified */ 178 return 0; 179 180 /* First round v in y */ 181 sign = MPFR_SIGN (v); 182 MPFR_SET_EXP (y, MPFR_GET_EXP (v)); 183 MPFR_SET_SIGN (y, sign); 184 MPFR_RNDRAW_GEN (inexact, y, MPFR_MANT (v), MPFR_PREC (v), rnd, sign, 185 if (dir == 0) 186 { 187 inexact = -sign; 188 goto trunc_doit; 189 } 190 else 191 goto addoneulp; 192 , if (MPFR_UNLIKELY (++MPFR_EXP (y) > __gmpfr_emax)) 193 mpfr_overflow (y, rnd, sign) 194 ); 195 196 /* Fix it in some cases */ 197 MPFR_ASSERTD (!MPFR_IS_NAN (y) && !MPFR_IS_ZERO (y)); 198 /* If inexact == 0, setting y from v is exact but we haven't 199 take into account yet the error term */ 200 if (inexact == 0) 201 { 202 if (dir == 0) /* The error term is negative for v positive */ 203 { 204 inexact = sign; 205 if (MPFR_IS_LIKE_RNDZ (rnd, MPFR_IS_NEG_SIGN (sign))) 206 { 207 /* case nexttozero */ 208 /* The underflow flag should be set if the result is zero */ 209 __gmpfr_flags = old_flags; 210 inexact = -sign; 211 mpfr_nexttozero (y); 212 if (MPFR_UNLIKELY (MPFR_IS_ZERO (y))) 213 MPFR_SET_UNDERFLOW (); 214 } 215 } 216 else /* The error term is positive for v positive */ 217 { 218 inexact = -sign; 219 /* Round Away */ 220 if (MPFR_IS_LIKE_RNDA (rnd, MPFR_IS_NEG_SIGN(sign))) 221 { 222 /* case nexttoinf */ 223 /* The overflow flag should be set if the result is infinity */ 224 inexact = sign; 225 mpfr_nexttoinf (y); 226 if (MPFR_UNLIKELY (MPFR_IS_INF (y))) 227 MPFR_SET_OVERFLOW (); 228 } 229 } 230 } 231 232 /* the inexact flag cannot be 0, since this would mean an exact value, 233 and in this case we cannot round correctly */ 234 MPFR_ASSERTD(inexact != 0); 235 MPFR_RET (inexact); 236 } 237