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 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 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