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