1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2015 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 #include "libpspp/compiler.h"
25 #include "math/decimal.h"
30 /* Canonicalise a string holding the decimal representation of a number.
31 For example, leading zeros left of the decimal point are removed, as are
32 trailing zeros to the right.
34 This function is used purely for testing, and need not and is not intended
38 canonicalise_string (const char *s)
42 bool negative = false;
44 char *temp = malloc (strlen (s) + 3);
45 char *last_leading_zero = NULL;
47 /* Strip leading - if present */
57 char *first_trailing_zero = NULL;
58 char *significant_digit = NULL;
59 for (p = temp; *p; p++)
61 if (*p == '0' && dot == NULL && significant_digit == NULL)
62 last_leading_zero = p;
64 if (*p == '0' && first_trailing_zero == NULL)
65 first_trailing_zero = p;
70 first_trailing_zero = NULL;
73 if (*p >= '1' && *p <= '9')
75 significant_digit = p;
76 first_trailing_zero = NULL;
80 if (first_trailing_zero && dot)
81 *first_trailing_zero = '\0';
83 if (last_leading_zero)
85 /* Strip leading zeros */
86 out = last_leading_zero + 1;
88 /* But if we now start with . put a zero back again */
89 if (dot == last_leading_zero + 1)
100 if (!significant_digit)
111 /* Tests both the decimal_to_string function, and the decimal_input_from_string
114 test_run (const char *input)
117 struct decimal number;
118 decimal_init_from_string (&number, input);
120 char *s = decimal_to_string (&number);
121 char *canon = canonicalise_string (input);
122 if (0 != strcmp (canon, s))
124 fprintf (stdout, "\"%s\" does not match \n\"%s\"\n", canon, s);
128 decimal_init_from_string (&test, s);
129 assert (0 == decimal_cmp (&test, &number));
136 test_can (const char *in, const char *soll)
138 char *ist = canonicalise_string (in);
139 if (0 != strcmp (soll, ist))
141 printf ("\"%s\" canonicalises to \"%s\" (should be \"%s\")\n", in, ist, soll);
148 dump_scale (const struct decimal *low, const struct decimal *interval, int n_ticks)
151 struct decimal tick = *interval;
152 printf ("Lowest: %s\n", decimal_to_string (low));
153 for (i = 0; i <= n_ticks; ++i)
155 printf ("Tick %d: %s (%g)\n", i, decimal_to_string (&tick), decimal_to_double (&tick));
156 decimal_add (&tick, interval);
167 decimal_from_double (&dx, x);
168 int act = decimal_ceil (&dx);
169 int expected = ceil (x);
171 assert (act == expected);
175 test_floor (double x)
178 decimal_from_double (&dx, x);
179 int act = decimal_floor (&dx);
180 int expected = floor (x);
182 assert (act == expected);
187 test_addition (const struct decimal *one_, const struct decimal *two)
189 struct decimal one = *one_;
191 decimal_add (&one, two);
193 double dsum = decimal_to_double (&one);
198 snprintf (sdsum1, 256, "%s", decimal_to_string (&one));
199 snprintf (sdsum2, 256, "%g", dsum);
201 assert (strcmp (sdsum1, sdsum2) == 0);
206 test_multiplication (const struct decimal *d, int m)
210 struct decimal dest = *d;
211 double x = decimal_to_double (&dest);
213 decimal_int_multiply (&dest, m);
215 double y = decimal_to_double (&dest);
217 snprintf (b1, 256, "%g", m * x);
218 snprintf (b2, 256, "%g", y);
219 assert (0 == strcmp (b1, b2));
225 main (int argc UNUSED, char **argv UNUSED)
227 /* Test that our canonicalise function works for all corner cases we
230 test_can ("500", "500");
232 test_can ("-3", "-3");
233 test_can ("-3.001", "-3.001");
234 test_can ("-03.001", "-3.001");
235 test_can ("-.0301", "-0.0301");
236 test_can ("0314.09", "314.09");
237 test_can ("0314.090", "314.09");
238 test_can ("0314.0900340", "314.090034");
239 test_can ("0.0", "0");
240 test_can ("0.", "0");
241 test_can (".0", "0");
242 test_can ("-.1", "-0.1");
243 test_can (".090", "0.09");
244 test_can ("03410.098700", "3410.0987");
245 test_can ("-03410.098700", "-3410.0987");
247 /* Test the conversion functions */
258 test_run ("666666666");
259 test_run ("6000000000");
260 test_run ("0.000000005");
261 test_run ("0.00000000000000000000000000000000000000005");
264 test_run ("-0123.45600");
278 struct decimal high = {2, 0};
279 struct decimal low = {2, -1};
281 test_addition (&high, &low);
286 struct decimal high = {10, 0};
287 struct decimal low = {2, -1};
289 test_addition (&high, &low);
294 struct decimal high = {10, 0};
295 struct decimal low = {-2, -1};
297 test_addition (&high, &low);
301 struct decimal high = {12, -5};
302 struct decimal low = {-2, -1};
304 test_addition (&high, &low);
308 struct decimal high = {-112, -1};
309 struct decimal low = {2, -1};
311 test_addition (&high, &low);
316 struct decimal m = {10, 0};
318 test_multiplication (&m, 11);
323 struct decimal m = {ORD_MAX - 2, 0};
325 test_multiplication (&m, 11);
330 struct decimal m = {34, 0};
332 test_multiplication (&m, 0);
336 struct decimal m = {34, -20};
338 test_multiplication (&m, 33);
342 struct decimal m = {304, 2};
344 test_multiplication (&m, -33);