| /* |
| * |
| * Copyright (c) International Business Machines Corp., 2002 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU 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 General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* 01/02/2003 Port to LTP avenkat@us.ibm.com */ |
| /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ |
| |
| /* |
| * NAME |
| * atof1 -- ascii to floating point test |
| * |
| * CALLS |
| * atof(3), sprintf(3), ( doprnt.s ) |
| * |
| * ALGORITHM |
| * Do some checks of floating point to ascii and back, arbitrate |
| * with a 3rd algorithm written in C. |
| * |
| * RESTRICTIONS |
| */ |
| |
| #include <stdio.h> |
| #include <ctype.h> |
| #include <math.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| /** LTP Port **/ |
| #include "test.h" |
| |
| #define FAILED 0 |
| #define PASSED 1 |
| |
| /***** *****/ |
| #define ERR 0.0000001 |
| |
| double pi; |
| |
| double atof(); |
| |
| /*char progname[]= "atof1()"; */ |
| /** LTP Port **/ |
| char *TCID = "atof01"; /* Test program identifier */ |
| |
| int local_flag = PASSED; |
| int block_number; |
| int errno; |
| FILE *temp; |
| int TST_TOTAL = 1; |
| |
| void setup(); |
| void blenter(); |
| void blexit(); |
| int numin(char *, double *); |
| int checkbuf(char *, int, int); |
| |
| /*--------------------------------------------------------------*/ |
| int main(int argc, char *argv[]) |
| { |
| register int i, j; |
| double r1, r2, x; |
| char buf[100]; |
| |
| setup(); /* temp file is now open */ |
| pi = 4.0 * atan(1.0); |
| |
| /*--------------------------------------------------------------*/ |
| blenter(); |
| |
| for (i = 0; i < 30; i++) |
| for (j = 0; j < 30; j++) { |
| sprintf(buf, "%*.*f", i, j, pi); |
| if (checkbuf(buf, i, j)) { |
| fprintf(temp, "output conversion incorrect."); |
| fprintf(temp, "%*.*f = '%s'", i, j, pi, buf); |
| local_flag = FAILED; |
| } |
| r1 = atof(buf); |
| if (numin(buf, &r2)) { |
| fprintf(temp, "\tnumin('%s') failed\n", buf); |
| local_flag = FAILED; |
| } |
| x = fabs(r1 - r2); |
| if (x > ERR) { |
| fprintf(temp, "\tcompare fails, %f vs %f\n", |
| r1, r2); |
| fprintf(temp, "\terr value is %f\n", x); |
| local_flag = FAILED; |
| } |
| if (local_flag == FAILED) |
| break; |
| } |
| |
| blexit(); |
| /*--------------------------------------------------------------*/ |
| blenter(); |
| |
| x = 1.0 - exp(-100.0); /* 1.0 - very small number */ |
| sprintf(buf, "%f", x); |
| r1 = atof(buf); |
| if (r1 != 1.0) { |
| fprintf(temp, "\tsprintf small # failed\n"); |
| fprintf(temp, "\t printed '%s', expected 1.0\n", buf); |
| local_flag = FAILED; |
| } |
| |
| blexit(); |
| /*--------------------------------------------------------------*/ |
| blenter(); |
| |
| for (i = 1; i < 200; i++) { |
| x = 100.0 / (double)i; |
| sprintf(buf, "%f", x); |
| r1 = atof(buf); |
| if (numin(buf, &r2)) { |
| fprintf(temp, "\tnumin('%s') failed\n", buf); |
| local_flag = FAILED; |
| } |
| /* |
| * Order subtraction to produce a positive number. |
| * Then subtrace "fudge" factor which should give us |
| * a negative number, as the result fo subtraction should |
| * always be smaller than the fudge factor. |
| */ |
| if (r1 > r2) |
| x = r1 - r2 - 1e-10; |
| else |
| x = r2 - r1 - 1e-10; |
| if (x > 0.0) { |
| fprintf(temp, "\tx = %.15f = %e\n", x, x); |
| fprintf(temp, "\titeration %d\n", i); |
| fprintf(temp, "\tcompare fails, %f vs %f\n", r1, r2); |
| fprintf(temp, "\tcompare fails, %.15f vs %.15f\n", |
| r1, r2); |
| fprintf(temp, "\tbuf = '%s'\n", buf); |
| x = r1 - r2; |
| if (x == 0.0) |
| fprintf(temp, "\tx == 0.0\n"); |
| else |
| fprintf(temp, "\tx != 0.0\n"); |
| fprintf(temp, "\tx = %.15f = %e\n", x, x); |
| local_flag = FAILED; |
| } |
| if (local_flag == FAILED) |
| break; |
| } |
| |
| blexit(); |
| /*--------------------------------------------------------------*/ |
| blenter(); |
| |
| for (i = -1; i > -200; i--) { |
| x = 100.0 / (double)i; |
| sprintf(buf, "%f", x); |
| r1 = atof(buf); |
| if (numin(buf, &r2)) { |
| fprintf(temp, "\tnumin('%s') failed\n", buf); |
| local_flag = FAILED; |
| } |
| /* |
| * Same ordering of subtraction as above. |
| */ |
| if (r1 > r2) |
| x = r1 - r2 - 1e-10; |
| else |
| x = r2 - r1 - 1e-10; |
| if (x > 0.0) { |
| fprintf(temp, "\tcompare fails, %f vs %f\n", r1, r2); |
| fprintf(temp, "\tcompare fails, %.15f vs %.15f\n", |
| r1, r2); |
| x = r1 - r2; |
| if (x == 0.0) |
| fprintf(temp, "\tx == 0.0)\n"); |
| else |
| fprintf(temp, "\tx != 0.0\n"); |
| fprintf(temp, "\tx = %.15f = %e\n", x, x); |
| local_flag = FAILED; |
| } |
| if (local_flag == FAILED) |
| break; |
| } |
| |
| blexit(); |
| /*--------------------------------------------------------------*/ |
| tst_exit(); |
| } |
| |
| /* FUNCTIONS GO HERE */ |
| |
| int numin(str, rval) |
| char *str; |
| double *rval; |
| { |
| register int i, v3, e_flag; |
| register char c; |
| double val, v1, v2, k; |
| int neg_flag = 0; |
| |
| val = v1 = v2 = 0.0; |
| v3 = 0; |
| k = 0.1; |
| |
| while (*str == ' ') /* scan past white space */ |
| str++; |
| |
| if (*str == '-') { /* negitive value test */ |
| neg_flag++; |
| str++; |
| } |
| |
| for (;;) { |
| c = *str; |
| if (!isdigit(c)) |
| break; |
| v1 *= 10.0; |
| v1 += (double)(c - '0'); |
| str++; |
| } |
| |
| val = v1; |
| |
| #ifdef DEBUG |
| printf("First conversion, val = %f = %e\n", val, val); |
| #endif |
| |
| if (*str == '.') { |
| str++; |
| for (;;) { |
| c = *str; |
| if (!isdigit(c)) |
| break; |
| v2 += k * (double)(c - '0'); |
| k /= 10.0; |
| str++; |
| } |
| val += v2; |
| } |
| #ifdef DEBUG |
| printf("Second conversion, val = %f = %e\n", val, val); |
| #endif |
| |
| if (*str == 'e') { |
| str++; |
| switch (*str) { |
| case '+': |
| e_flag = 1; |
| break; |
| case '-': |
| e_flag = -1; |
| break; |
| default: |
| fprintf(temp, "\tbad char '%c' after 'e'\n", *str); |
| printf("bad char '%c' after 'e'\n", *str); |
| return (-1); |
| } |
| str++; |
| if (!isdigit(*str)) { |
| fprintf(temp, "\tbad exponent field\n"); |
| printf("bad exponent field\n"); |
| return (-1); |
| } |
| v3 = 10 * (int)(*str - '0'); |
| str++; |
| if (!isdigit(*str)) { |
| fprintf(temp, "\tbad exponent field\n"); |
| printf("bad exponent field\n"); |
| return (-1); |
| } |
| v3 += (int)(*str - '0'); |
| str++; |
| for (i = 0; i < v3; i++) { |
| if (e_flag > 0) |
| val *= 10.0; |
| else |
| val *= 0.1; |
| } |
| } |
| |
| if (neg_flag) |
| val *= -1.0; |
| |
| #ifdef DEBUG |
| printf("Third conversion, val = %f = %e\n", val, val); |
| printf("v1 = %f, v2 = %f, v3 = %d\n", v1, v2, v3); |
| #endif |
| |
| switch (*str) { |
| case '\0': |
| case ' ': |
| case '\t': |
| case '\n': |
| break; |
| default: |
| printf("unexpected char '%c'\n", *str); |
| return (-1); |
| } |
| |
| *rval = val; |
| return (0); |
| } |
| |
| int checkbuf(str, n1, n2) |
| char *str; |
| int n1; |
| int n2; |
| { |
| register int bd; /* before decimal point */ |
| register int ad; /* after decimal point */ |
| register int tw; /* total width */ |
| register int dp; /* decimal point */ |
| char *buf; |
| |
| bd = ad = dp = 0; |
| buf = str; |
| |
| while (*str && *str != '.') { |
| bd++; |
| str++; |
| } |
| if (*str == '.') { |
| dp++; |
| str++; |
| if (*str) { |
| while (*str) { |
| ad++; |
| str++; |
| } |
| } |
| } |
| |
| tw = bd + dp + ad; |
| if (!n1) |
| n1++; |
| if (tw < n1) { |
| fprintf(temp, "\tWidth too small.\n"); |
| fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf); |
| return (-1); |
| } |
| |
| if (ad != n2) { |
| fprintf(temp, "\tNumber after decimal wrong.\n"); |
| fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf); |
| return (-1); |
| } |
| |
| if (n2 && !dp) { |
| fprintf(temp, "\tMissed decimal point.\n"); |
| fprintf(temp, "\tn1 = %d, n2 = %d, buf= '%s'\n", n1, n2, buf); |
| return (-1); |
| } |
| |
| return (0); |
| } |
| |
| /** LTP Port **/ |
| void setup() |
| { |
| temp = stderr; |
| } |
| |
| void blenter() |
| { |
| local_flag = PASSED; |
| } |
| |
| void blexit() |
| { |
| if (local_flag == PASSED) |
| tst_resm(TPASS, "Test passed"); |
| else |
| tst_resm(TFAIL, "Test failed"); |
| } |