1/* mpf_ceil, mpf_floor -- round an mpf to an integer. 2 3Copyright 2001, 2004 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library. 6 7The GNU MP Library is free software; you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12The GNU MP Library is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20#include "gmp.h" 21#include "gmp-impl.h" 22 23 24/* dir==1 for ceil, dir==-1 for floor 25 26 Notice the use of prec+1 ensures mpf_ceil and mpf_floor are equivalent to 27 mpf_set if u is already an integer. */ 28 29static void __gmpf_ceil_or_floor __GMP_PROTO ((REGPARM_2_1 (mpf_ptr, mpf_srcptr, int))) REGPARM_ATTR (1); 30#define mpf_ceil_or_floor(r,u,dir) __gmpf_ceil_or_floor (REGPARM_2_1 (r, u, dir)) 31 32REGPARM_ATTR (1) static void 33mpf_ceil_or_floor (mpf_ptr r, mpf_srcptr u, int dir) 34{ 35 mp_ptr rp, up, p; 36 mp_size_t size, asize, prec; 37 mp_exp_t exp; 38 39 size = SIZ(u); 40 if (size == 0) 41 { 42 zero: 43 SIZ(r) = 0; 44 EXP(r) = 0; 45 return; 46 } 47 48 rp = PTR(r); 49 exp = EXP(u); 50 if (exp <= 0) 51 { 52 /* u is only a fraction */ 53 if ((size ^ dir) < 0) 54 goto zero; 55 rp[0] = 1; 56 EXP(r) = 1; 57 SIZ(r) = dir; 58 return; 59 } 60 EXP(r) = exp; 61 62 up = PTR(u); 63 asize = ABS (size); 64 up += asize; 65 66 /* skip fraction part of u */ 67 asize = MIN (asize, exp); 68 69 /* don't lose precision in the copy */ 70 prec = PREC (r) + 1; 71 72 /* skip excess over target precision */ 73 asize = MIN (asize, prec); 74 75 up -= asize; 76 77 if ((size ^ dir) >= 0) 78 { 79 /* rounding direction matches sign, must increment if ignored part is 80 non-zero */ 81 for (p = PTR(u); p != up; p++) 82 { 83 if (*p != 0) 84 { 85 if (mpn_add_1 (rp, up, asize, CNST_LIMB(1))) 86 { 87 /* was all 0xFF..FFs, which have become zeros, giving just 88 a carry */ 89 rp[0] = 1; 90 asize = 1; 91 EXP(r)++; 92 } 93 SIZ(r) = (size >= 0 ? asize : -asize); 94 return; 95 } 96 } 97 } 98 99 SIZ(r) = (size >= 0 ? asize : -asize); 100 if (rp != up) 101 MPN_COPY_INCR (rp, up, asize); 102} 103 104 105void 106mpf_ceil (mpf_ptr r, mpf_srcptr u) 107{ 108 mpf_ceil_or_floor (r, u, 1); 109} 110 111void 112mpf_floor (mpf_ptr r, mpf_srcptr u) 113{ 114 mpf_ceil_or_floor (r, u, -1); 115} 116