chromium / native_client / nacl-gcc / f80d6b9ee7f94755c697ffb7194fb01dd0c537dd / . / mpfr-2.4.1 / get_f.c

/* mpfr_get_f -- convert a MPFR number to a GNU MPF number | |

Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. | |

Contributed by the Arenaire and Cacao projects, INRIA. | |

This file is part of the GNU MPFR Library. | |

The GNU MPFR Library is free software; you can redistribute it and/or modify | |

it under the terms of the GNU Lesser General Public License as published by | |

the Free Software Foundation; either version 2.1 of the License, or (at your | |

option) any later version. | |

The GNU MPFR Library is distributed in the hope that it will be useful, but | |

WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |

or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |

License for more details. | |

You should have received a copy of the GNU Lesser General Public License | |

along with the GNU MPFR Library; see the file COPYING.LIB. If not, write to | |

the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |

MA 02110-1301, USA. */ | |

#include "mpfr-impl.h" | |

/* return value is 0 iff no error occurred in the conversion | |

(1 for NaN, +Inf, -Inf that have no equivalent in mpf) | |

*/ | |

int | |

mpfr_get_f (mpf_ptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) | |

{ | |

mp_size_t sx, sy; | |

mp_prec_t precx, precy; | |

mp_limb_t *xp; | |

int sh; | |

if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(y))) | |

{ | |

if (MPFR_IS_ZERO(y)) | |

{ | |

mpf_set_ui (x, 0); | |

return 0; | |

} | |

else /* NaN or Inf */ | |

return 1; | |

} | |

sx = PREC(x); /* number of limbs of the mantissa of x */ | |

precy = MPFR_PREC(y); | |

precx = (mp_prec_t) sx * BITS_PER_MP_LIMB; | |

sy = MPFR_LIMB_SIZE (y); | |

xp = PTR (x); | |

/* since mpf numbers are represented in base 2^BITS_PER_MP_LIMB, | |

we loose -EXP(y) % BITS_PER_MP_LIMB bits in the most significant limb */ | |

sh = MPFR_GET_EXP(y) % BITS_PER_MP_LIMB; | |

sh = sh <= 0 ? - sh : BITS_PER_MP_LIMB - sh; | |

MPFR_ASSERTD (sh >= 0); | |

if (precy + sh <= precx) /* we can copy directly */ | |

{ | |

mp_size_t ds; | |

MPFR_ASSERTN (sx >= sy); | |

ds = sx - sy; | |

if (sh != 0) | |

{ | |

mp_limb_t out; | |

out = mpn_rshift (xp + ds, MPFR_MANT(y), sy, sh); | |

MPFR_ASSERTN (ds > 0 || out == 0); | |

if (ds > 0) | |

xp[--ds] = out; | |

} | |

else | |

MPN_COPY (xp + ds, MPFR_MANT (y), sy); | |

if (ds > 0) | |

MPN_ZERO (xp, ds); | |

EXP(x) = (MPFR_GET_EXP(y) + sh) / BITS_PER_MP_LIMB; | |

} | |

else /* we have to round to precx - sh bits */ | |

{ | |

mpfr_t z; | |

mp_size_t sz, ds; | |

/* Recall that precx = (mp_prec_t) sx * BITS_PER_MP_LIMB */ | |

mpfr_init2 (z, precx - sh); | |

sz = MPFR_LIMB_SIZE (z); | |

mpfr_set (z, y, rnd_mode); | |

/* warning, sh may change due to rounding, but then z is a power of two, | |

thus we can safely ignore its last bit which is 0 */ | |

sh = MPFR_GET_EXP(z) % BITS_PER_MP_LIMB; | |

sh = sh <= 0 ? - sh : BITS_PER_MP_LIMB - sh; | |

MPFR_ASSERTD (sx >= sz); | |

ds = sx - sz; | |

MPFR_ASSERTD (sh >= 0 && ds <= 1); | |

if (sh != 0) | |

{ | |

mp_limb_t out; | |

out = mpn_rshift (xp + ds, MPFR_MANT(z), sz, sh); | |

/* If sh hasn't changed, it is the number of the non-significant | |

bits in the lowest limb of z. Therefore out == 0. */ | |

MPFR_ASSERTD (out == 0); | |

} | |

else | |

MPN_COPY (xp + ds, MPFR_MANT(z), sz); | |

if (ds != 0) | |

xp[0] = 0; | |

EXP(x) = (MPFR_GET_EXP(z) + sh) / BITS_PER_MP_LIMB; | |

mpfr_clear (z); | |

} | |

/* set size and sign */ | |

SIZ(x) = (MPFR_FROM_SIGN_TO_INT(MPFR_SIGN(y)) < 0) ? -sx : sx; | |

return 0; | |

} |