a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald/*
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * This file and its contents are supplied under the terms of the
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Common Development and Distribution License ("CDDL"), version 1.0.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * You may only use this file in accordance with the terms of version
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * 1.0 of the CDDL.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald *
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * A full copy of the text of the CDDL should have accompanied this
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * source. A copy of the CDDL is also available via the Internet at
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * http://www.illumos.org/license/CDDL.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald/*
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Copyright 2014 PALO, Richard. All rights reserved.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Copyright 2014 OmniTI Computer Consulting, Inc. All rights reserved.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald/*
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Test rounding of floating point numbers in libc's *printf() routines.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald *
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * C99 must be enabled to get DECIMAL_DIG defined, but it looks like all
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * of usr/src/test/libc is compiled that way.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald#include <float.h>
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald#include <fenv.h>
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald#include <stdio.h>
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald#include <strings.h>
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald#include "test_common.h"
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald/*
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Returns negative if snprintf() fails. Returns 0 upon
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * successful execution of the test, return 1 upon a failure.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald * Spews output if verbose is TRUE.
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonaldint
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonaldrun_one(test_t t, int i, int j, int precision, boolean_t verbose)
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald{
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald const int size = 100;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald char buffer[size], check[size];
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald double val;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald int status;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald val = (double)(0.0 + j) / i;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald /* first get max precision for control check */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald status = snprintf(check, size, "%+-.*f", DECIMAL_DIG, val);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (status < 0) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald test_failed(t, "Max precision snprintf() "
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald "(i = %d, j = %d) returned %d\n", i, j, status);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (status);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald /* then get specific precision */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald status = snprintf(buffer, size, "%+-#.*f", precision, val);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (status < 0) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald test_failed(t, "Specific precision snprintf() "
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald "(i = %d, j = %d, precision = %d) returned %d\n", i, j,
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald precision, status);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (status);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (strlen(check) > strlen(buffer) &&
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald strncmp(buffer, check, strlen(buffer))) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald /* last check if correctly rounded up */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (check[strlen(buffer)] < '5' &&
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald buffer[strlen(buffer) - 1] > check[strlen(buffer) - 1]) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (verbose)
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald (void) printf("failure:f precision %d "
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald "for %02d/%02d => %s (%s)\n",
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald precision, j, i, buffer, check);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (1);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (0);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald}
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonaldint
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonaldmain(int argc, char *argv[])
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald{
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald int status, i, j, precision;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald int failures = 0;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald int runs = 0;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald test_t t;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald /* NOTE: Any argument after the command enables "VERBOSE" mode. */
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald boolean_t verbose = (argc > 1);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald t = test_start("*printf() floating-point rounding tests.");
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald (void) fesetround(FE_TONEAREST);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald for (j = 1; j < 100; j++) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald for (i = 2; i < 100; i++) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald for (precision = DBL_DIG - 1; precision <= DECIMAL_DIG;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald precision++) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald runs++;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald status = run_one(t, i, j, precision, verbose);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (status < 0)
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (status);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald failures += status;
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald }
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald if (failures > 0) {
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald test_failed(t, "Tests failed %d times out of %d attempts.\n"
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald "Run '%s full' to see the %d failures individually.\n",
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald failures, runs, argv[0], failures);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald } else
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald test_passed(t);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald return (0);
a2290a3621fa5498b33edb7037d8e95c15ddf455Dan McDonald}