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 "math/decimal.h"
29 /* Canonicalise a string holding the decimal representation of a number.
30 For example, leading zeros left of the decimal point are removed, as are
31 trailing zeros to the right.
33 This function is used purely for testing, and need not and is not intended
37 canonicalise_string (const char *s)
41 bool negative = false;
43 char *temp = malloc (strlen (s) + 3);
44 char *last_leading_zero = NULL;
46 /* Strip leading - if present */
56 char *first_trailing_zero = NULL;
57 char *significant_digit = NULL;
58 for (p = temp; *p; p++)
60 if (*p == '0' && dot == NULL && significant_digit == NULL)
61 last_leading_zero = p;
63 if (*p == '0' && first_trailing_zero == NULL)
64 first_trailing_zero = p;
69 first_trailing_zero = NULL;
72 if (*p >= '1' && *p <= '9')
74 significant_digit = p;
75 first_trailing_zero = NULL;
79 if (first_trailing_zero && dot)
80 *first_trailing_zero = '\0';
82 if (last_leading_zero)
84 /* Strip leading zeros */
85 out = last_leading_zero + 1;
87 /* But if we now start with . put a zero back again */
88 if (dot == last_leading_zero + 1)
99 if (!significant_digit)
110 /* Tests both the decimal_to_string function, and the decimal_input_from_string
113 test_run (const char *input)
116 struct decimal number;
117 decimal_init_from_string (&number, input);
119 char *s = decimal_to_string (&number);
120 char *canon = canonicalise_string (input);
121 if (0 != strcmp (canon, s))
123 fprintf (stdout, "\"%s\" does not match \n\"%s\"\n", canon, s);
127 decimal_init_from_string (&test, s);
128 assert (0 == decimal_cmp (&test, &number));
135 test_can (const char *in, const char *soll)
137 char *ist = canonicalise_string (in);
138 if (0 != strcmp (soll, ist))
140 printf ("\"%s\" canonicalises to \"%s\" (should be \"%s\")\n", in, ist, soll);
146 dump_scale (const struct decimal *low, const struct decimal *interval, int n_ticks)
149 struct decimal tick = *interval;
150 printf ("Lowest: %s\n", decimal_to_string (low));
151 for (i = 0; i <= n_ticks; ++i)
153 printf ("Tick %d: %s (%g)\n", i, decimal_to_string (&tick), decimal_to_double (&tick));
154 decimal_add (&tick, interval);
164 decimal_from_double (&dx, x);
165 int act = decimal_ceil (&dx);
166 int expected = ceil (x);
168 assert (act == expected);
172 test_floor (double x)
175 decimal_from_double (&dx, x);
176 int act = decimal_floor (&dx);
177 int expected = floor (x);
179 assert (act == expected);
184 test_addition (const struct decimal *one_, const struct decimal *two)
186 struct decimal one = *one_;
187 double d1 = decimal_to_double (&one);
188 double d2 = decimal_to_double (two);
190 decimal_add (&one, two);
192 double dsum = decimal_to_double (&one);
197 snprintf (sdsum1, 256, "%s", decimal_to_string (&one));
198 snprintf (sdsum2, 256, "%g", dsum);
200 assert (strcmp (sdsum1, sdsum2) == 0);
205 test_multiplication (const struct decimal *d, int m)
209 struct decimal dest = *d;
210 double x = decimal_to_double (&dest);
212 decimal_int_multiply (&dest, m);
214 double y = decimal_to_double (&dest);
216 snprintf (b1, 256, "%g", m * x);
217 snprintf (b2, 256, "%g", y);
218 assert (0 == strcmp (b1, b2));
224 main (int argc, char **argv)
226 /* Test that our canonicalise function works for all corner cases we
229 test_can ("500", "500");
231 test_can ("-3", "-3");
232 test_can ("-3.001", "-3.001");
233 test_can ("-03.001", "-3.001");
234 test_can ("-.0301", "-0.0301");
235 test_can ("0314.09", "314.09");
236 test_can ("0314.090", "314.09");
237 test_can ("0314.0900340", "314.090034");
238 test_can ("0.0", "0");
239 test_can ("0.", "0");
240 test_can (".0", "0");
241 test_can ("-.1", "-0.1");
242 test_can (".090", "0.09");
243 test_can ("03410.098700", "3410.0987");
244 test_can ("-03410.098700", "-3410.0987");
246 /* Test the conversion functions */
257 test_run ("666666666");
258 test_run ("6000000000");
259 test_run ("0.000000005");
260 test_run ("0.00000000000000000000000000000000000000005");
263 test_run ("-0123.45600");
277 struct decimal high = {2, 0};
278 struct decimal low = {2, -1};
280 test_addition (&high, &low);
285 struct decimal high = {10, 0};
286 struct decimal low = {2, -1};
288 test_addition (&high, &low);
293 struct decimal high = {10, 0};
294 struct decimal low = {-2, -1};
296 test_addition (&high, &low);
300 struct decimal high = {12, -5};
301 struct decimal low = {-2, -1};
303 test_addition (&high, &low);
307 struct decimal high = {-112, -1};
308 struct decimal low = {2, -1};
310 test_addition (&high, &low);
315 struct decimal m = {10, 0};
317 test_multiplication (&m, 11);
322 struct decimal m = {ORD_MAX - 2, 0};
324 test_multiplication (&m, 11);
329 struct decimal m = {34, 0};
331 test_multiplication (&m, 0);
335 struct decimal m = {34, -20};
337 test_multiplication (&m, 33);
341 struct decimal m = {304, 2};
343 test_multiplication (&m, -33);