1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2014 PALO, Richard. All rights reserved.
14 * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
15 */
16
17 /*
18 * Test rounding of floating point numbers in libc's *printf() routines.
19 *
20 * C99 must be enabled to get DECIMAL_DIG defined, but it looks like all
21 * of usr/src/test/libc is compiled that way.
22 */
23
24 #include <float.h>
25 #include <fenv.h>
26 #include <stdio.h>
27 #include <strings.h>
28 #include "test_common.h"
29
30 /*
31 * Returns negative if snprintf() fails. Returns 0 upon
32 * successful execution of the test, return 1 upon a failure.
33 * Spews output if verbose is TRUE.
34 */
35 int
run_one(test_t t,int i,int j,int precision,boolean_t verbose)36 run_one(test_t t, int i, int j, int precision, boolean_t verbose)
37 {
38 const int size = 100;
39 char buffer[size], check[size];
40 double val;
41 int status;
42
43 val = (double)(0.0 + j) / i;
44 /* first get max precision for control check */
45 status = snprintf(check, size, "%+-.*f", DECIMAL_DIG, val);
46 if (status < 0) {
47 test_failed(t, "Max precision snprintf() "
48 "(i = %d, j = %d) returned %d\n", i, j, status);
49 return (status);
50 }
51 /* then get specific precision */
52 status = snprintf(buffer, size, "%+-#.*f", precision, val);
53 if (status < 0) {
54 test_failed(t, "Specific precision snprintf() "
55 "(i = %d, j = %d, precision = %d) returned %d\n", i, j,
56 precision, status);
57 return (status);
58 }
59
60 if (strlen(check) > strlen(buffer) &&
61 strncmp(buffer, check, strlen(buffer))) {
62 /* last check if correctly rounded up */
63 if (check[strlen(buffer)] < '5' &&
64 buffer[strlen(buffer) - 1] > check[strlen(buffer) - 1]) {
65 if (verbose)
66 (void) printf("failure:f precision %d "
67 "for %02d/%02d => %s (%s)\n",
68 precision, j, i, buffer, check);
69 return (1);
70 }
71 }
72
73 return (0);
74 }
75
76 int
main(int argc,char * argv[])77 main(int argc, char *argv[])
78 {
79 int status, i, j, precision;
80 int failures = 0;
81 int runs = 0;
82 test_t t;
83 /* NOTE: Any argument after the command enables "VERBOSE" mode. */
84 boolean_t verbose = (argc > 1);
85
86 t = test_start("*printf() floating-point rounding tests.");
87
88 (void) fesetround(FE_TONEAREST);
89
90 for (j = 1; j < 100; j++) {
91 for (i = 2; i < 100; i++) {
92 for (precision = DBL_DIG - 1; precision <= DECIMAL_DIG;
93 precision++) {
94 runs++;
95 status = run_one(t, i, j, precision, verbose);
96 if (status < 0)
97 return (status);
98 failures += status;
99 }
100 }
101 }
102
103 if (failures > 0) {
104 test_failed(t, "Tests failed %d times out of %d attempts.\n"
105 "Run '%s full' to see the %d failures individually.\n",
106 failures, runs, argv[0], failures);
107 } else
108 test_passed(t);
109
110 return (0);
111 }
112