Commit | Line | Data |
---|---|---|
d6cf9697 | 1 | /* Copyright (C) 2004, 2006, 2008, 2009, 2011 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 KR |
22 | |
23 | #include <assert.h> | |
24 | #include <math.h> | |
25 | #include <stdio.h> | |
26 | ||
27 | #if HAVE_FENV_H | |
41249947 LC |
28 | # if defined __GNUC__ && defined __GLIBC__ |
29 | /* In Glibc 2.17, <bits/fenv.h> defines `feraiseexcept' as an inline | |
30 | without declaring it first, so ignore the warning. */ | |
31 | # pragma GCC diagnostic push | |
32 | # pragma GCC diagnostic ignored "-Wmissing-prototypes" | |
33 | # endif | |
34 | # include <fenv.h> | |
35 | # if defined __GNUC__ && defined __GLIBC__ | |
36 | # pragma GCC diagnostic pop | |
37 | # endif | |
66818dbb | 38 | #elif defined HAVE_MACHINE_FPU_H |
13ff4740 LC |
39 | /* On Tru64 5.1b, the declaration of fesetround(3) is in <machine/fpu.h>. |
40 | On NetBSD, this header has to be included along with <sys/types.h>. */ | |
41 | # ifdef HAVE_SYS_TYPES_H | |
42 | # include <sys/types.h> | |
43 | # endif | |
66818dbb | 44 | # include <machine/fpu.h> |
370b8399 KR |
45 | #endif |
46 | ||
5995c6d8 | 47 | #include <libguile.h> |
370b8399 KR |
48 | |
49 | ||
50 | #define numberof(x) (sizeof (x) / sizeof ((x)[0])) | |
51 | ||
52 | static void | |
ee3e40b7 | 53 | test_scm_c_round () |
370b8399 KR |
54 | { |
55 | /* FE constants are defined only where supported, in particular for | |
56 | instance some ARM systems have been seen with only a couple of modes */ | |
57 | static const int modes[] = { | |
58 | 0, | |
59 | #ifdef FE_TONEAREST | |
60 | FE_TONEAREST, | |
61 | #endif | |
62 | #ifdef FE_UPWARD | |
63 | FE_UPWARD, | |
64 | #endif | |
65 | #ifdef FE_DOWNWARD | |
66 | FE_DOWNWARD, | |
67 | #endif | |
68 | #ifdef FE_TOWARDZERO | |
69 | FE_TOWARDZERO, | |
70 | #endif | |
71 | }; | |
72 | ||
73 | double x, want; | |
74 | int i; | |
75 | ||
76 | for (i = 0; i < numberof (modes); i++) | |
77 | { | |
78 | /* First iteration is the default rounding mode, ie. no call to | |
79 | fesetround. Subsequent iterations are the FE modes from the | |
80 | table. */ | |
81 | if (i != 0) | |
82 | { | |
d6cf9697 | 83 | #ifdef HAVE_FESETROUND |
370b8399 KR |
84 | fesetround (modes[i]); |
85 | #endif | |
86 | } | |
87 | ||
ee3e40b7 MV |
88 | assert (scm_c_round (0.0) == 0.0); |
89 | assert (scm_c_round (1.0) == 1.0); | |
90 | assert (scm_c_round (-1.0) == -1.0); | |
370b8399 | 91 | |
ee3e40b7 MV |
92 | assert (scm_c_round (0.5) == 0.0); |
93 | assert (scm_c_round (1.5) == 2.0); | |
94 | assert (scm_c_round (-1.5) == -2.0); | |
95 | assert (scm_c_round (2.5) == 2.0); | |
96 | assert (scm_c_round (-2.5) == -2.0); | |
97 | assert (scm_c_round (3.5) == 4.0); | |
98 | assert (scm_c_round (-3.5) == -4.0); | |
370b8399 KR |
99 | |
100 | /* 2^(DBL_MANT_DIG-1)-1+0.5 */ | |
101 | x = ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5; | |
102 | want = ldexp (1.0, DBL_MANT_DIG - 1); | |
ee3e40b7 | 103 | assert (scm_c_round (x) == want); |
370b8399 KR |
104 | |
105 | /* -(2^(DBL_MANT_DIG-1)-1+0.5) */ | |
106 | x = - (ldexp (1.0, DBL_MANT_DIG - 1) - 1.0 + 0.5); | |
107 | want = - ldexp (1.0, DBL_MANT_DIG - 1); | |
ee3e40b7 | 108 | assert (scm_c_round (x) == want); |
370b8399 KR |
109 | |
110 | /* 2^DBL_MANT_DIG-1 | |
ee3e40b7 | 111 | In the past scm_c_round had incorrectly incremented this value, due |
370b8399 KR |
112 | to the way that x+0.5 would round upwards (in the usual default |
113 | nearest-even mode on most systems). */ | |
114 | x = ldexp (1.0, DBL_MANT_DIG) - 1.0; | |
115 | assert (x == floor (x)); /* should be an integer already */ | |
ee3e40b7 | 116 | assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */ |
370b8399 KR |
117 | |
118 | /* -(2^DBL_MANT_DIG-1) */ | |
119 | x = - (ldexp (1.0, DBL_MANT_DIG) - 1.0); | |
120 | assert (x == floor (x)); /* should be an integer already */ | |
ee3e40b7 | 121 | assert (scm_c_round (x) == x); /* scm_c_round should return it unchanged */ |
370b8399 KR |
122 | |
123 | /* 2^64 */ | |
124 | x = ldexp (1.0, 64); | |
ee3e40b7 | 125 | assert (scm_c_round (x) == x); |
370b8399 KR |
126 | |
127 | /* -2^64 | |
ee3e40b7 | 128 | In the past scm_c_round had incorrectely gone to the next highest |
370b8399 KR |
129 | representable value in FE_UPWARD, due to x+0.5 rounding. */ |
130 | x = - ldexp (1.0, 64); | |
ee3e40b7 | 131 | assert (scm_c_round (x) == x); |
370b8399 KR |
132 | } |
133 | } | |
134 | ||
8ab3d8a0 KR |
135 | static void |
136 | tests (void *data, int argc, char **argv) | |
137 | { | |
138 | test_scm_c_round (); | |
139 | } | |
140 | ||
370b8399 KR |
141 | int |
142 | main (int argc, char *argv[]) | |
143 | { | |
8ab3d8a0 | 144 | scm_boot_guile (argc, argv, tests, NULL); |
370b8399 KR |
145 | return 0; |
146 | } |