Back to index

nagios-plugins  1.4.16
floor.c
Go to the documentation of this file.
00001 /* Round towards negative infinity.
00002    Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc.
00003 
00004    This program is free software: you can redistribute it and/or modify
00005    it under the terms of the GNU General Public License as published by
00006    the Free Software Foundation; either version 3 of the License, or
00007    (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012    GNU General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00016 
00017 /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
00018 
00019 #include <config.h>
00020 
00021 /* Specification.  */
00022 #include <math.h>
00023 
00024 #include <float.h>
00025 
00026 #ifdef USE_LONG_DOUBLE
00027 # define FUNC floorl
00028 # define DOUBLE long double
00029 # define MANT_DIG LDBL_MANT_DIG
00030 # define L_(literal) literal##L
00031 #elif ! defined USE_FLOAT
00032 # define FUNC floor
00033 # define DOUBLE double
00034 # define MANT_DIG DBL_MANT_DIG
00035 # define L_(literal) literal
00036 #else /* defined USE_FLOAT */
00037 # define FUNC floorf
00038 # define DOUBLE float
00039 # define MANT_DIG FLT_MANT_DIG
00040 # define L_(literal) literal##f
00041 #endif
00042 
00043 /* 2^(MANT_DIG-1).  */
00044 static const DOUBLE TWO_MANT_DIG =
00045   /* Assume MANT_DIG <= 5 * 31.
00046      Use the identity
00047        n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5).  */
00048   (DOUBLE) (1U << ((MANT_DIG - 1) / 5))
00049   * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5))
00050   * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5))
00051   * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5))
00052   * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5));
00053 
00054 DOUBLE
00055 FUNC (DOUBLE x)
00056 {
00057   /* The use of 'volatile' guarantees that excess precision bits are dropped
00058      at each addition step and before the following comparison at the caller's
00059      site.  It is necessary on x86 systems where double-floats are not IEEE
00060      compliant by default, to avoid that the results become platform and compiler
00061      option dependent.  'volatile' is a portable alternative to gcc's
00062      -ffloat-store option.  */
00063   volatile DOUBLE y = x;
00064   volatile DOUBLE z = y;
00065 
00066   if (z > L_(0.0))
00067     {
00068       /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1.  */
00069       if (z < TWO_MANT_DIG)
00070         {
00071           /* Round to the next integer (nearest or up or down, doesn't matter).  */
00072           z += TWO_MANT_DIG;
00073           z -= TWO_MANT_DIG;
00074           /* Enforce rounding down.  */
00075           if (z > y)
00076             z -= L_(1.0);
00077         }
00078     }
00079   else if (z < L_(0.0))
00080     {
00081       /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1.  */
00082       if (z > - TWO_MANT_DIG)
00083         {
00084           /* Round to the next integer (nearest or up or down, doesn't matter).  */
00085           z -= TWO_MANT_DIG;
00086           z += TWO_MANT_DIG;
00087           /* Enforce rounding down.  */
00088           if (z > y)
00089             z -= L_(1.0);
00090         }
00091     }
00092   return z;
00093 }