Commit | Line | Data |
---|---|---|
0c1f2b0e | 1 | /* Copyright (C) 2004, 2006, 2008, 2009, 2011, 2014 Free Software Foundation, Inc. |
370b8399 KR |
2 | * |
3 | * This library is free software; you can redistribute it and/or | |
53befeb7 NJ |
4 | * modify it under the terms of the GNU Lesser General Public License |
5 | * as published by the Free Software Foundation; either version 3 of | |
6 | * the License, or (at your option) any later version. | |
370b8399 | 7 | * |
53befeb7 NJ |
8 | * This library is distributed in the hope that it will be useful, but |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
370b8399 KR |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
11 | * Lesser General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU Lesser General Public | |
14 | * License along with this library; if not, write to the Free Software | |
53befeb7 NJ |
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
16 | * 02110-1301 USA | |
370b8399 KR |
17 | */ |
18 | ||
5995c6d8 LC |
19 | #if HAVE_CONFIG_H |
20 | # include <config.h> | |
21 | #endif | |
370b8399 | 22 | |
0c1f2b0e LC |
23 | #undef NDEBUG |
24 | ||
370b8399 KR |
25 | #include <assert.h> |
26 | #include <math.h> | |
27 | #include <stdio.h> | |
28 | ||
29 | #if HAVE_FENV_H | |
41249947 LC |
30 | # if defined __GNUC__ && defined __GLIBC__ |
31 | /* In Glibc 2.17, <bits/fenv.h> defines `feraiseexcept' as an inline | |
32 | without declaring it first, so ignore the warning. */ | |
33 | # pragma GCC diagnostic push | |
34 | # pragma GCC diagnostic ignored "-Wmissing-prototypes" | |
35 | # endif | |
36 | # include <fenv.h> | |
37 | # if defined __GNUC__ && defined __GLIBC__ | |
38 | # pragma GCC diagnostic pop | |
39 | # endif | |
66818dbb | 40 | #elif defined HAVE_MACHINE_FPU_H |
13ff4740 LC |
41 | /* On Tru64 5.1b, the declaration of fesetround(3) is in <machine/fpu.h>. |
42 | On NetBSD, this header has to be included along with <sys/types.h>. */ | |
43 | # ifdef HAVE_SYS_TYPES_H | |
44 | # include <sys/types.h> | |
45 | # endif | |
66818dbb | 46 | # include <machine/fpu.h> |
370b8399 KR |
47 | #endif |
48 | ||
5995c6d8 | 49 | #include <libguile.h> |
370b8399 KR |
50 | |
51 | ||
52 | #define numberof(x) (sizeof (x) / sizeof ((x)[0])) | |
53 | ||
54 | static void | |
ee3e40b7 | 55 | test_scm_c_round () |
370b8399 KR |
56 | { |
57 | /* FE constants are defined only where supported, in particular for | |
58 | instance some ARM systems have been seen with only a couple of modes */ | |
59 | static const int modes[] = { | |
60 | 0, | |
61 | #ifdef FE_TONEAREST | |
62 | FE_TONEAREST, | |
63 | #endif | |
64 | #ifdef FE_UPWARD | |
65 | FE_UPWARD, | |
66 | #endif | |
67 | #ifdef FE_DOWNWARD | |
68 | FE_DOWNWARD, | |
69 | #endif | |
70 | #ifdef FE_TOWARDZERO | |
71 | FE_TOWARDZERO, | |
72 | #endif | |
73 | }; | |
74 | ||
75 | double x, want; | |
76 | int i; | |
77 | ||
78 | for (i = 0; i < numberof (modes); i++) | |
79 | { | |
80 | /* First iteration is the default rounding mode, ie. no call to | |
81 | fesetround. Subsequent iterations are the FE modes from the | |
82 | table. */ | |
83 | if (i != 0) | |
84 | { | |
d6cf9697 | 85 | #ifdef HAVE_FESETROUND |
370b8399 KR |
86 | fesetround (modes[i]); |
87 | #endif | |
88 | } | |
89 | ||
ee3e40b7 MV |
90 | assert (scm_c_round (0.0) == 0.0); |
91 | assert (scm_c_round (1.0) == 1.0); | |
92 | assert (scm_c_round (-1.0) == -1.0); | |
370b8399 | 93 | |
ee3e40b7 MV |
94 | assert (scm_c_round (0.5) == 0.0); |
95 | assert (scm_c_round (1.5) == 2.0); | |
96 | assert (scm_c_round (-1.5) == -2.0); | |
97 | assert (scm_c_round (2.5) == 2.0); | |
98 | assert (scm_c_round (-2.5) == -2.0); | |
99 | assert (scm_c_round (3.5) == 4.0); | |
100 | assert (scm_c_round (-3.5) == -4.0); | |
370b8399 KR |
101 | |
102 | /* 2^(DBL_MANT_DIG-1)-1+0.5 */ | |
103 | x = ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5; | |
104 | want = ldexp (1.0, DBL_MANT_DIG - 1); | |
ee3e40b7 | 105 | assert (scm_c_round (x) == want); |
370b8399 KR |
106 | |
107 | /* -(2^(DBL_MANT_DIG-1)-1+0.5) */ | |
108 | x = - (ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5); | |
109 | want = - ldexp (1.0, DBL_MANT_DIG - 1); | |
ee3e40b7 | 110 | assert (scm_c_round (x) == want); |
370b8399 KR |
111 | |
112 | /* 2^DBL_MANT_DIG-1 | |
ee3e40b7 | 113 | In the past scm_c_round had incorrectly incremented this value, due |
370b8399 KR |
114 | to the way that x+0.5 would round upwards (in the usual default |
115 | nearest-even mode on most systems). */ | |
116 | x = ldexp (1.0, DBL_MANT_DIG) - 1.0; | |
117 | assert (x == floor (x)); /* should be an integer already */ | |
ee3e40b7 | 118 | assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */ |
370b8399 KR |
119 | |
120 | /* -(2^DBL_MANT_DIG-1) */ | |
121 | x = - (ldexp (1.0, DBL_MANT_DIG) - 1.0); | |
122 | assert (x == floor (x)); /* should be an integer already */ | |
ee3e40b7 | 123 | assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */ |
370b8399 KR |
124 | |
125 | /* 2^64 */ | |
126 | x = ldexp (1.0, 64); | |
ee3e40b7 | 127 | assert (scm_c_round (x) == x); |
370b8399 KR |
128 | |
129 | /* -2^64 | |
ee3e40b7 | 130 | In the past scm_c_round had incorrectely gone to the next highest |
370b8399 KR |
131 | representable value in FE_UPWARD, due to x+0.5 rounding. */ |
132 | x = - ldexp (1.0, 64); | |
ee3e40b7 | 133 | assert (scm_c_round (x) == x); |
370b8399 KR |
134 | } |
135 | } | |
136 | ||
8ab3d8a0 KR |
137 | static void |
138 | tests (void *data, int argc, char **argv) | |
139 | { | |
140 | test_scm_c_round (); | |
141 | } | |
142 | ||
370b8399 KR |
143 | int |
144 | main (int argc, char *argv[]) | |
145 | { | |
8ab3d8a0 | 146 | scm_boot_guile (argc, argv, tests, NULL); |
370b8399 KR |
147 | return 0; |
148 | } |