/* * $Header: /home/gene/library/website/docsrc/test-rpc/src/src/RCS/test0016.c,v 395.1 2008/04/20 17:25:55 gene Exp $ * * Copyright (c) 2006 Gene Michael Stover. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ /* * Test that we can XDR encode float numbers to a temporary * file, then read them again. * For this test to be valid, we must already now that XDR * decodes float numbers correctly. */ #include "this.h" /* */ static char S_pathname[] = "./tmp/test0016.data"; /* */ static float S_a[] = { 0.0, -1.1e-1, M_PI, -2.2e2, 3.3e3, 4.4e-4, -5.5e5, 6.6e-6 }; static int S_alen = sizeof S_a / sizeof S_a[0]; /* */ static int S_Write () { int rc = 0; FILE *fp; XDR xdr; int i; fp = fopen (S_pathname, "wb"); if (fp != NULL) { xdrstdio_create (&xdr, fp, XDR_ENCODE); for (i = 0; rc == 0 && i < S_alen; ++i) { if (xdr_float (&xdr, &S_a[i])) { /* good so far */ } else { printf ("\n%s:%d: xdr_float: %s", __FILE__, __LINE__, strerror (errno)); printf ("%s:%d: xdr_float failed for a[%d] = %.3e.", __FILE__, __LINE__, i, S_a[i]); rc = -26; } } xdr_destroy (&xdr); fclose (fp); } else { printf ("\n%s:%d: fopen: %s", __FILE__, __LINE__, strerror (errno)); printf ("%s:%d: Could not open \"%s\" for binary output.", __FILE__, __LINE__, S_pathname); rc = 22; } return rc; } /* * Compare a decoded float value with an expected value. * Because we are dealing with floating point, we cannot * use a simple "=" comparison. Instead, we check that * the numbers are close enough. * They are close enough if: * * 1. They have the same sign, * * 2. They have the same magnitude (exponent), & * * 3. The different in the mantissas is at most the two * least significant bits. */ static bool_t S_EqualDouble (double a, double b) { static double mantissa = 23; /* bits in the mantissa */ static double forgiven_bits = 2; /* bits of error we can ignore */ double maximum_error; double error, relative_error; /* * The maximum error we're willing to accept is the "forgiven_bits" * most insignificant bits. Here, we convert that to a scalar. */ maximum_error = pow (2.0, forgiven_bits - mantissa); error = fabs (a - b); #if 0 printf ("\n%s:%d: error is %.3e.", __FILE__, __LINE__, error); #endif if (error > 0.0) { relative_error = error / b; } else { /* * Absolute error is 0.0. It has no representation as a * relative error. So we'll treat it as a relative error * of zero. */ relative_error = 0.0; } #if 0 printf ("\n%s:%d: relative error is %.3e.", __FILE__, __LINE__, relative_error); #endif /* * A & B are equivalent if their error is less than the maximum * acceptable error, which was computed from a number of bits. */ return relative_error < maximum_error; } /* */ static int S_Read () { int rc = 0; FILE *fp; XDR xdr; int i; float x; fp = fopen (S_pathname, "rb"); if (fp != NULL) { xdrstdio_create (&xdr, fp, XDR_DECODE); for (i = 0; rc == 0 && i < S_alen; ++i) { if (xdr_float (&xdr, &x)) { if (S_EqualDouble (x, S_a[i])) { /* good so far */ } else { printf ("\n%s:%d: xdr_float decoded %.18e.", __FILE__, __LINE__, x); printf (" Expected a[%d] = %.10e.", i, S_a[i]); rc = -47; } } else { printf ("\n%s:%d: xdr_float: %s", __FILE__, __LINE__, strerror (errno)); rc = -46; } } xdr_destroy (&xdr); fclose (fp); } else { printf ("\n%s:%d: fopen: %s", __FILE__, __LINE__, strerror (errno)); printf ("%s:%d: Could not open \"%s\" for binary input.", __FILE__, __LINE__, S_pathname); rc = 45; } return rc; } int main () { int rc = 0; if (S_Write () == 0) { if (S_Read () == 0) { /* good */ } else { printf ("\n%s:%d: S_Read failed", __FILE__, __LINE__); rc = -31; } } else { printf ("\n%s:%d: S_Write failed", __FILE__, __LINE__); rc = 31; } remove (S_pathname); return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } /* --- end of file --- */