(root)/
gmp-6.3.0/
mpz/
cmpabs_d.c
       1  /* mpz_cmpabs_d -- compare absolute values of mpz and double.
       2  
       3  Copyright 2001-2003, 2012 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library.
       6  
       7  The GNU MP Library is free software; you can redistribute it and/or modify
       8  it under the terms of either:
       9  
      10    * the GNU Lesser General Public License as published by the Free
      11      Software Foundation; either version 3 of the License, or (at your
      12      option) any later version.
      13  
      14  or
      15  
      16    * the GNU General Public License as published by the Free Software
      17      Foundation; either version 2 of the License, or (at your option) any
      18      later version.
      19  
      20  or both in parallel, as here.
      21  
      22  The GNU MP Library is distributed in the hope that it will be useful, but
      23  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      24  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      25  for more details.
      26  
      27  You should have received copies of the GNU General Public License and the
      28  GNU Lesser General Public License along with the GNU MP Library.  If not,
      29  see https://www.gnu.org/licenses/.  */
      30  
      31  #include "config.h"
      32  
      33  #if HAVE_FLOAT_H
      34  #include <float.h>  /* for DBL_MAX */
      35  #endif
      36  
      37  #include "gmp-impl.h"
      38  
      39  
      40  #define RETURN_CMP(zl, dl)              \
      41    do {                                  \
      42      zlimb = (zl);                       \
      43      dlimb = (dl);                       \
      44      if (zlimb != dlimb)                 \
      45        return (zlimb >= dlimb ? 1 : -1); \
      46    } while (0)
      47  
      48  #define RETURN_NONZERO(ptr, size, val)          \
      49    do {                                          \
      50      mp_size_t __i;                              \
      51      for (__i = (size)-1; __i >= 0; __i--)       \
      52        if ((ptr)[__i] != 0)                      \
      53          return val;                             \
      54      return 0;                                   \
      55    } while (0)
      56  
      57  
      58  int
      59  mpz_cmpabs_d (mpz_srcptr z, double d)
      60  {
      61    mp_limb_t  darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
      62    mp_srcptr  zp;
      63    mp_size_t  zsize;
      64    int        dexp;
      65  
      66    /* d=NaN is an invalid operation, there's no sensible return value.
      67       d=Inf or -Inf is always bigger than z.  */
      68    DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), return -1);
      69  
      70    /* 1. Check for either operand zero. */
      71    zsize = SIZ(z);
      72    if (d == 0.0)
      73      return (zsize != 0);
      74    if (zsize == 0)
      75      return -1; /* d != 0 */
      76  
      77    /* 2. Ignore signs. */
      78    zsize = ABS(zsize);
      79    d = ABS(d);
      80  
      81    /* 3. Small d, knowing abs(z) >= 1. */
      82    if (d < 1.0)
      83      return 1;
      84  
      85    dexp = __gmp_extract_double (darray, d);
      86    ASSERT (dexp >= 1);
      87  
      88    /* 4. Check for different high limb positions. */
      89    if (zsize != dexp)
      90      return (zsize >= dexp ? 1 : -1);
      91  
      92    /* 5. Limb data. */
      93    zp = PTR(z);
      94  
      95  #if LIMBS_PER_DOUBLE == 2
      96    RETURN_CMP (zp[zsize-1], darray[1]);
      97    if (zsize == 1)
      98      return (darray[0] != 0 ? -1 : 0);
      99  
     100    RETURN_CMP (zp[zsize-2], darray[0]);
     101    RETURN_NONZERO (zp, zsize-2, 1);
     102  #endif
     103  
     104  #if LIMBS_PER_DOUBLE == 3
     105    RETURN_CMP (zp[zsize-1], darray[2]);
     106    if (zsize == 1)
     107      return ((darray[0] | darray[1]) != 0 ? -1 : 0);
     108  
     109    RETURN_CMP (zp[zsize-2], darray[1]);
     110    if (zsize == 2)
     111      return (darray[0] != 0 ? -1 : 0);
     112  
     113    RETURN_CMP (zp[zsize-3], darray[0]);
     114    RETURN_NONZERO (zp, zsize-3, 1);
     115  #endif
     116  
     117  #if LIMBS_PER_DOUBLE >= 4
     118    {
     119      int i;
     120      for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
     121        {
     122  	RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
     123  	if (i >= zsize)
     124  	  RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -1);
     125        }
     126      RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, 1);
     127    }
     128  #endif
     129  }