"Fossies" - the Fresh Open Source Software Archive

Member "gcal-4.1/lib/floor.c" (22 Jan 2017, 3367 Bytes) of package /linux/misc/gcal-4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "floor.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4_vs_4.1.

    1 /* Round towards negative infinity.
    2    Copyright (C) 2007, 2010-2017 Free Software Foundation, Inc.
    3 
    4    This program is free software: you can redistribute it and/or modify
    5    it under the terms of the GNU General Public License as published by
    6    the Free Software Foundation; either version 3 of the License, or
    7    (at your option) any later version.
    8 
    9    This program is distributed in the hope that it will be useful,
   10    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12    GNU General Public License for more details.
   13 
   14    You should have received a copy of the GNU General Public License
   15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   16 
   17 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
   18 
   19 #if ! defined USE_LONG_DOUBLE
   20 # include <config.h>
   21 #endif
   22 
   23 /* Specification.  */
   24 #include <math.h>
   25 
   26 #include <float.h>
   27 
   28 #ifdef USE_LONG_DOUBLE
   29 # define FUNC floorl
   30 # define DOUBLE long double
   31 # define MANT_DIG LDBL_MANT_DIG
   32 # define L_(literal) literal##L
   33 #elif ! defined USE_FLOAT
   34 # define FUNC floor
   35 # define DOUBLE double
   36 # define MANT_DIG DBL_MANT_DIG
   37 # define L_(literal) literal
   38 #else /* defined USE_FLOAT */
   39 # define FUNC floorf
   40 # define DOUBLE float
   41 # define MANT_DIG FLT_MANT_DIG
   42 # define L_(literal) literal##f
   43 #endif
   44 
   45 /* MSVC with option -fp:strict refuses to compile constant initializers that
   46    contain floating-point operations.  Pacify this compiler.  */
   47 #ifdef _MSC_VER
   48 # pragma fenv_access (off)
   49 #endif
   50 
   51 /* 2^(MANT_DIG-1).  */
   52 static const DOUBLE TWO_MANT_DIG =
   53   /* Assume MANT_DIG <= 5 * 31.
   54      Use the identity
   55        n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5).  */
   56   (DOUBLE) (1U << ((MANT_DIG - 1) / 5))
   57   * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5))
   58   * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5))
   59   * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5))
   60   * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5));
   61 
   62 DOUBLE
   63 FUNC (DOUBLE x)
   64 {
   65   /* The use of 'volatile' guarantees that excess precision bits are dropped
   66      at each addition step and before the following comparison at the caller's
   67      site.  It is necessary on x86 systems where double-floats are not IEEE
   68      compliant by default, to avoid that the results become platform and compiler
   69      option dependent.  'volatile' is a portable alternative to gcc's
   70      -ffloat-store option.  */
   71   volatile DOUBLE y = x;
   72   volatile DOUBLE z = y;
   73 
   74   if (z > L_(0.0))
   75     {
   76       /* For 0 < x < 1, return +0.0 even if the current rounding mode is
   77          FE_DOWNWARD.  */
   78       if (z < L_(1.0))
   79         z = L_(0.0);
   80       /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1.  */
   81       else if (z < TWO_MANT_DIG)
   82         {
   83           /* Round to the next integer (nearest or up or down, doesn't matter).  */
   84           z += TWO_MANT_DIG;
   85           z -= TWO_MANT_DIG;
   86           /* Enforce rounding down.  */
   87           if (z > y)
   88             z -= L_(1.0);
   89         }
   90     }
   91   else if (z < L_(0.0))
   92     {
   93       /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1.  */
   94       if (z > - TWO_MANT_DIG)
   95         {
   96           /* Round to the next integer (nearest or up or down, doesn't matter).  */
   97           z -= TWO_MANT_DIG;
   98           z += TWO_MANT_DIG;
   99           /* Enforce rounding down.  */
  100           if (z > y)
  101             z -= L_(1.0);
  102         }
  103     }
  104   return z;
  105 }