annotate lib/floor.c @ 40196:e63f5d3edab5

relocatable-prog: Update documentation. * doc/relocatable-maint.texi (Supporting Relocation): Update to match the recent changes.
author Bruno Haible <bruno@clisp.org>
date Sun, 24 Feb 2019 01:49:15 +0100
parents b06060465f09
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Round towards negative infinity.
40057
b06060465f09 maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents: 19484
diff changeset
2 Copyright (C) 2007, 2010-2019 Free Software Foundation, Inc.
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9291
diff changeset
4 This program is free software: you can redistribute it and/or modify
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 it under the terms of the GNU General Public License as published by
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9291
diff changeset
6 the Free Software Foundation; either version 3 of the License, or
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9291
diff changeset
7 (at your option) any later version.
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 GNU General Public License for more details.
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9291
diff changeset
14 You should have received a copy of the GNU General Public License
19190
9759915b2aca all: prefer https: URLs
Paul Eggert <eggert@cs.ucla.edu>
parents: 18626
diff changeset
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007. */
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
18
15924
dfbcd662bdd1 floorl: Simplify for platforms where 'long double' == 'double'.
Bruno Haible <bruno@clisp.org>
parents: 14079
diff changeset
19 #if ! defined USE_LONG_DOUBLE
dfbcd662bdd1 floorl: Simplify for platforms where 'long double' == 'double'.
Bruno Haible <bruno@clisp.org>
parents: 14079
diff changeset
20 # include <config.h>
dfbcd662bdd1 floorl: Simplify for platforms where 'long double' == 'double'.
Bruno Haible <bruno@clisp.org>
parents: 14079
diff changeset
21 #endif
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23 /* Specification. */
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24 #include <math.h>
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
25
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
26 #include <float.h>
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
27
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
28 #ifdef USE_LONG_DOUBLE
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
29 # define FUNC floorl
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
30 # define DOUBLE long double
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
31 # define MANT_DIG LDBL_MANT_DIG
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
32 # define L_(literal) literal##L
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
33 #elif ! defined USE_FLOAT
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
34 # define FUNC floor
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
35 # define DOUBLE double
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
36 # define MANT_DIG DBL_MANT_DIG
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
37 # define L_(literal) literal
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
38 #else /* defined USE_FLOAT */
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
39 # define FUNC floorf
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
40 # define DOUBLE float
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
41 # define MANT_DIG FLT_MANT_DIG
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
42 # define L_(literal) literal##f
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
43 #endif
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
44
16506
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
45 /* MSVC with option -fp:strict refuses to compile constant initializers that
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
46 contain floating-point operations. Pacify this compiler. */
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
47 #ifdef _MSC_VER
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
48 # pragma fenv_access (off)
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
49 #endif
fa4e9b981eb4 Avoid compilation errors with MSVC option -fp:strict.
Bruno Haible <bruno@clisp.org>
parents: 16201
diff changeset
50
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
51 /* 2^(MANT_DIG-1). */
9313
59fc463c9868 Fix type of TWO_MANT_DIG.
Bruno Haible <bruno@clisp.org>
parents: 9309
diff changeset
52 static const DOUBLE TWO_MANT_DIG =
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
53 /* Assume MANT_DIG <= 5 * 31.
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
54 Use the identity
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
55 n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5). */
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
56 (DOUBLE) (1U << ((MANT_DIG - 1) / 5))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
57 * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
58 * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5));
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
61
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
62 DOUBLE
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
63 FUNC (DOUBLE x)
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
64 {
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
65 /* The use of 'volatile' guarantees that excess precision bits are dropped
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
66 at each addition step and before the following comparison at the caller's
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
67 site. It is necessary on x86 systems where double-floats are not IEEE
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
68 compliant by default, to avoid that the results become platform and compiler
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
69 option dependent. 'volatile' is a portable alternative to gcc's
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
70 -ffloat-store option. */
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
71 volatile DOUBLE y = x;
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
72 volatile DOUBLE z = y;
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
73
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
74 if (z > L_(0.0))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
75 {
13991
525bc52bc59f floor: Implement result sign according to IEEE 754.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
76 /* For 0 < x < 1, return +0.0 even if the current rounding mode is
525bc52bc59f floor: Implement result sign according to IEEE 754.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
77 FE_DOWNWARD. */
525bc52bc59f floor: Implement result sign according to IEEE 754.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
78 if (z < L_(1.0))
525bc52bc59f floor: Implement result sign according to IEEE 754.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
79 z = L_(0.0);
9332
b72a5920bf45 Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test.
Bruno Haible <bruno@clisp.org>
parents: 9313
diff changeset
80 /* Avoid rounding errors for values near 2^k, where k >= MANT_DIG-1. */
13991
525bc52bc59f floor: Implement result sign according to IEEE 754.
Bruno Haible <bruno@clisp.org>
parents: 12559
diff changeset
81 else if (z < TWO_MANT_DIG)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
82 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
83 /* Round to the next integer (nearest or up or down, doesn't matter). */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
84 z += TWO_MANT_DIG;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
85 z -= TWO_MANT_DIG;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
86 /* Enforce rounding down. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
87 if (z > y)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
88 z -= L_(1.0);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
89 }
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
90 }
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
91 else if (z < L_(0.0))
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
92 {
9332
b72a5920bf45 Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test.
Bruno Haible <bruno@clisp.org>
parents: 9313
diff changeset
93 /* Avoid rounding errors for values near -2^k, where k >= MANT_DIG-1. */
b72a5920bf45 Fix incorrect rounding of floor, floorf, floorl in some cases. Add new test.
Bruno Haible <bruno@clisp.org>
parents: 9313
diff changeset
94 if (z > - TWO_MANT_DIG)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
95 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
96 /* Round to the next integer (nearest or up or down, doesn't matter). */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
97 z -= TWO_MANT_DIG;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
98 z += TWO_MANT_DIG;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
99 /* Enforce rounding down. */
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
100 if (z > y)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
101 z -= L_(1.0);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 9332
diff changeset
102 }
9291
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
103 }
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
104 return z;
5828ff66b473 New module 'floorf'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
105 }