annotate lib/trunc.c @ 9309:bbbbbf4cd1c5

Change copyright notice from GPLv2+ to GPLv3+.
author Bruno Haible <bruno@clisp.org>
date Sun, 07 Oct 2007 19:14:58 +0200
parents 79e67a783774
children 59fc463c9868
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Round towards zero.
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
2 Copyright (C) 2007 Free Software Foundation, Inc.
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9285
diff changeset
4 This program is free software: you can redistribute it and/or modify
9282
9a26e94f946a New module 'trunc'.
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: 9285
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: 9285
diff changeset
7 (at your option) any later version.
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 GNU General Public License for more details.
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13
9309
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9285
diff changeset
14 You should have received a copy of the GNU General Public License
bbbbbf4cd1c5 Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents: 9285
diff changeset
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
17 /* Written by Bruno Haible <bruno@clisp.org>, 2007. */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
18
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
19 #include <config.h>
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
20
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
21 /* Specification. */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22 #include <math.h>
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24 #include <float.h>
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
25
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
26 #ifdef USE_LONG_DOUBLE
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
27 # define FUNC truncl
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
28 # define DOUBLE long double
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
29 # define MANT_DIG LDBL_MANT_DIG
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
30 # define L_(literal) literal##L
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
31 #elif ! defined USE_FLOAT
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
32 # define FUNC trunc
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
33 # define DOUBLE double
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
34 # define MANT_DIG DBL_MANT_DIG
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
35 # define L_(literal) literal
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
36 #else /* defined USE_FLOAT */
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
37 # define FUNC truncf
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
38 # define DOUBLE float
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
39 # define MANT_DIG FLT_MANT_DIG
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
40 # define L_(literal) literal##f
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
41 #endif
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
42
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
43 /* 2^(MANT_DIG-1). */
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
44 static const double TWO_MANT_DIG =
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
45 /* Assume MANT_DIG <= 5 * 31.
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
46 Use the identity
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
47 n = floor(n/5) + floor((n+1)/5) + ... + floor((n+4)/5). */
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
48 (DOUBLE) (1U << ((MANT_DIG - 1) / 5))
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
49 * (DOUBLE) (1U << ((MANT_DIG - 1 + 1) / 5))
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
50 * (DOUBLE) (1U << ((MANT_DIG - 1 + 2) / 5))
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
51 * (DOUBLE) (1U << ((MANT_DIG - 1 + 3) / 5))
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
52 * (DOUBLE) (1U << ((MANT_DIG - 1 + 4) / 5));
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
53
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
54 DOUBLE
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
55 FUNC (DOUBLE x)
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
56 {
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
57 /* The use of 'volatile' guarantees that excess precision bits are dropped
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
58 at each addition step and before the following comparison at the caller's
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 site. It is necessary on x86 systems where double-floats are not IEEE
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 compliant by default, to avoid that the results become platform and compiler
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
61 option dependent. 'volatile' is a portable alternative to gcc's
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
62 -ffloat-store option. */
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
63 volatile DOUBLE y = x;
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
64 volatile DOUBLE z = y;
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
65
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
66 if (z > L_(0.0))
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
67 {
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
68 /* Round to the next integer (nearest or up or down, doesn't matter). */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
69 z += TWO_MANT_DIG;
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
70 z -= TWO_MANT_DIG;
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
71 /* Enforce rounding down. */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
72 if (z > y)
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
73 z -= L_(1.0);
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
74 }
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
75 else if (z < L_(0.0))
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
76 {
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
77 /* Round to the next integer (nearest or up or down, doesn't matter). */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
78 z -= TWO_MANT_DIG;
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
79 z += TWO_MANT_DIG;
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
80 /* Enforce rounding up. */
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
81 if (z < y)
9285
79e67a783774 New module 'truncf'.
Bruno Haible <bruno@clisp.org>
parents: 9282
diff changeset
82 z += L_(1.0);
9282
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
83 }
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
84 return z;
9a26e94f946a New module 'trunc'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
85 }