1ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
2ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* tarith.c
3ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
4ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Copyright (c) 2011-2013 John Cunningham Bowler
5ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
6ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Last changed in libpng 1.6.0 [February 14, 2013]
7ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
8ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * This code is released under the libpng license.
9ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * For conditions of distribution and use, see the disclaimer
10ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * and license in png.h
11ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
12ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Test internal arithmetic functions of libpng.
13ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
14ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * This code must be linked against a math library (-lm), but does not require
15ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * libpng or zlib to work.  Because it includes the complete source of 'png.c'
16ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * it tests the code with whatever compiler options are used to build it.
17ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Changing these options can substantially change the errors in the
18ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * calculations that the compiler chooses!
19ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
20ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define _POSIX_SOURCE 1
21ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define _ISOC99_SOURCE 1
22ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
23ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Obtain a copy of the code to be tested (plus other things), disabling
24ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * stuff that is not required.
25ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
26ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <math.h>
27ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <stdlib.h>
28ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <ctype.h>
29ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <string.h>
30ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include <assert.h>
31ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
32ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include "../../pngpriv.h"
33ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
34ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_error png_warning
35ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
36ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikvoid png_warning(png_const_structrp png_ptr, png_const_charp msg)
37ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
38ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "validation: %s\n", msg);
39ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
40ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
41ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_fixed_error png_fixed_warning
42ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
43ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikvoid png_fixed_warning(png_const_structrp png_ptr, png_const_charp msg)
44ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
45ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "overflow in: %s\n", msg);
46ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
47ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
48ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_set_error_fn(pp, ep, efp, wfp) ((void)0)
49ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_malloc(pp, s) malloc(s)
50ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_malloc_warn(pp, s) malloc(s)
51ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_malloc_base(pp, s) malloc(s)
52ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_calloc(pp, s) calloc(1, (s))
53ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_free(pp, s) free(s)
54ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
55ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_safecat(b, sb, pos, str) (pos)
56ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_format_number(start, end, format, number) (start)
57ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
58ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define crc32(crc, pp, s) (crc)
59ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define inflateReset(zs) Z_OK
60ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
61ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_create_struct(type) (0)
62ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_destroy_struct(pp) ((void)0)
63ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_create_struct_2(type, m, mm) (0)
64ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define png_destroy_struct_2(pp, f, mm) ((void)0)
65ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
66ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#undef PNG_SIMPLIFIED_READ_SUPPORTED
67ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#undef PNG_SIMPLIFIED_WRITE_SUPPORTED
68ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#undef PNG_USER_MEM_SUPPORTED
69ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
70ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#include "../../png.c"
71ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
72ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Validate ASCII to fp routines. */
73ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int verbose = 0;
74ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
75ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint validation_ascii_to_fp(int count, int argc, char **argv)
76ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
77ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    showall = 0;
78ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double max_error=2;      /* As a percentage error-in-last-digit/.5 */
79ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double max_error_abs=17; /* Used when precision is DBL_DIG */
80ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double max = 0;
81ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double max_abs = 0;
82ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double test = 0; /* Important to test this. */
83ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    precision = 5;
84ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    nonfinite = 0;
85ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    finite = 0;
86ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    ok = 0;
87ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    failcount = 0;
88ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int    minorarith = 0;
89ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
90ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--argc > 0)
91ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(*++argv, "-a") == 0)
92ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         showall = 1;
93ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(*argv, "-e") == 0 && argc > 0)
94ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
95ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         --argc;
96ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         max_error = atof(*++argv);
97ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
98ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(*argv, "-E") == 0 && argc > 0)
99ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
100ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         --argc;
101ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         max_error_abs = atof(*++argv);
102ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
103ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
104ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
105ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "unknown argument %s\n", *argv);
106ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
107ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
108ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
109ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   do
110ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
111ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_size_t index;
112ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      int state, failed = 0;
113ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      char buffer[64];
114ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
115ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (isfinite(test))
116ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++finite;
117ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
118ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++nonfinite;
119ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
120ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (verbose)
121ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%.*g %d\n", DBL_DIG, test, precision);
122ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
123ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Check for overflow in the buffer by setting a marker. */
124ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      memset(buffer, 71, sizeof buffer);
125ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
126ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_ascii_from_fp(0, buffer, precision+10, test, precision);
127ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
128ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Allow for a three digit exponent, this stuff will fail if
129ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * the exponent is bigger than this!
130ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
131ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (buffer[precision+7] != 71)
132ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
133ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%g[%d] -> '%s'[%lu] buffer overflow\n", test,
134ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            precision, buffer, (unsigned long)strlen(buffer));
135ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         failed = 1;
136ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
137ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
138ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Following are used for the number parser below and must be
139ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * initialized to zero.
140ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
141ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      state = 0;
142ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      index = 0;
143ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!isfinite(test))
144ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
145ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Expect 'inf' */
146ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (test >= 0 && strcmp(buffer, "inf") ||
147ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             test <  0 && strcmp(buffer, "-inf"))
148ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
149ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "%g[%d] -> '%s' but expected 'inf'\n", test,
150ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               precision, buffer);
151ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            failed = 1;
152ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
153ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
154ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (!png_check_fp_number(buffer, precision+10, &state, &index) ||
155ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          buffer[index] != 0)
156ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
157ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%g[%d] -> '%s' but has bad format ('%c')\n", test,
158ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         precision, buffer, buffer[index]);
159ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         failed = 1;
160ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
161ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (PNG_FP_IS_NEGATIVE(state) && !(test < 0))
162ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
163ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%g[%d] -> '%s' but negative value not so reported\n",
164ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            test, precision, buffer);
165ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         failed = 1;
166ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_ZERO(state));
167ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_POSITIVE(state));
168ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
169ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (PNG_FP_IS_ZERO(state) && !(test == 0))
170ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
171ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%g[%d] -> '%s' but zero value not so reported\n",
172ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            test, precision, buffer);
173ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         failed = 1;
174ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_NEGATIVE(state));
175ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_POSITIVE(state));
176ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
177ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (PNG_FP_IS_POSITIVE(state) && !(test > 0))
178ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
179ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%g[%d] -> '%s' but postive value not so reported\n",
180ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            test, precision, buffer);
181ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         failed = 1;
182ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_NEGATIVE(state));
183ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         assert(!PNG_FP_IS_ZERO(state));
184ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
185ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
186ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
187ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Check the result against the original. */
188ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double out = atof(buffer);
189ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double change = fabs((out - test)/test);
190ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double allow = .5/pow(10,
191ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (precision >= DBL_DIG) ? DBL_DIG-1 : precision-1);
192ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
193ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* NOTE: if you hit this error case are you compiling with gcc
194ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          * and -O0?  Try -O2 - the errors can accumulate if the FP
195ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          * code above is not optimized and may drift outside the .5 in
196ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          * DBL_DIG allowed.  In any case a small number of errors may
197ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          * occur (very small ones - 1 or 2%) because of rounding in the
198ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          * calculations, either in the conversion API or in atof.
199ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik          */
200ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (change >= allow && (isfinite(out) ||
201ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             fabs(test/DBL_MAX) <= 1-allow))
202ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
203ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            double percent = (precision >= DBL_DIG) ? max_error_abs : max_error;
204ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            double allowp = (change-allow)*100/allow;
205ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
206ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (precision >= DBL_DIG)
207ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
208ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               if (max_abs < allowp) max_abs = allowp;
209ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
210ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
211ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            else
212ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
213ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               if (max < allowp) max = allowp;
214ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
215ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
216ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (showall || allowp >= percent)
217ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
218ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               fprintf(stderr,
219ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  "%.*g[%d] -> '%s' -> %.*g number changed (%g > %g (%d%%))\n",
220ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  DBL_DIG, test, precision, buffer, DBL_DIG, out, change, allow,
221ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  (int)round(allowp));
222ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               failed = 1;
223ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
224ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            else
225ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               ++minorarith;
226ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
227ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
228ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
229ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (failed)
230ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++failcount;
231ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
232ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++ok;
233ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
234ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikskip:
235ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Generate a new number and precision. */
236ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      precision = rand();
237ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (precision & 1) test = -test;
238ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      precision >>= 1;
239ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
240ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Generate random numbers. */
241ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (test == 0 || !isfinite(test))
242ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         test = precision+1;
243ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
244ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
245ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Derive the exponent from the previous rand() value. */
246ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int exponent = precision % (DBL_MAX_EXP - DBL_MIN_EXP) + DBL_MIN_EXP;
247ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int tmp;
248ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         test = frexp(test * rand(), &tmp);
249ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         test = ldexp(test, exponent);
250ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         precision >>= 8; /* arbitrary */
251ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
252ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
253ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* This limits the precision to 32 digits, enough for standard
254ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * IEEE implementations which have at most 15 digits.
255ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
256ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      precision = (precision & 0x1f) + 1;
257ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
258ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--count);
259ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
260ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf("Tested %d finite values, %d non-finite, %d OK (%d failed) %d minor "
261ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      "arithmetic errors\n", finite, nonfinite, ok, failcount, minorarith);
262ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf(" Error with >=%d digit precision %.2f%%\n", DBL_DIG, max_abs);
263ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf(" Error with < %d digit precision %.2f%%\n", DBL_DIG, max);
264ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
265ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
266ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
267ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
268ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Observe that valid FP numbers have the forms listed in the PNG extensions
269ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * specification:
270ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
271ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * [+,-]{integer,integer.fraction,.fraction}[{e,E}[+,-]integer]
272ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
273ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * Test each of these in turn, including invalid cases.
274ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
275ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craiktypedef enum checkfp_state
276ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
277ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   start, fraction, exponent, states
278ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik} checkfp_state;
279ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
280ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* The characters (other than digits) that characterize the states: */
281ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic const char none[] = "";
282ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic const char hexdigits[16] = "0123456789ABCDEF";
283ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
284ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic const struct
285ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
286ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *start; /* Characters valid at the start */
287ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *end;   /* Valid characters that end the state */
288ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *tests; /* Characters to test after 2 digits seen */
289ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
290ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstate_characters[states] =
291ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
292ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* start:    */ { "+-.", ".eE", "+-.e*0369" },
293ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* fraction: */ { none, "eE",  "+-.E#0147" },
294ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* exponent: */ { "+-", none,  "+-.eE^0258" }
295ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik};
296ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
297ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craiktypedef struct
298ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
299ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   char number[1024];  /* Buffer for number being tested */
300ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  limit;         /* Command line limit */
301ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  verbose;       /* Shadows global variable */
302ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  ctimes;        /* Number of numbers tested */
303ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  cmillions;     /* Count of millions of numbers */
304ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  cinvalid;      /* Invalid strings checked */
305ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int  cnoaccept;     /* Characters not accepted */
306ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
307ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikcheckfp_command;
308ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
309ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craiktypedef struct
310ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
311ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           cnumber;          /* Index into number string */
312ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   checkfp_state check_state;      /* Current number state */
313ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           at_start;         /* At start (first character) of state */
314ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           cdigits_in_state; /* Digits seen in that state */
315ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           limit;            /* Limit on same for checking all chars */
316ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           state;            /* Current parser state */
317ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           is_negative;      /* Number is negative */
318ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           is_zero;          /* Number is (still) zero */
319ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int           number_was_valid; /* Previous character validity */
320ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
321ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikcheckfp_control;
322ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
323ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int check_all_characters(checkfp_command *co, checkfp_control c);
324ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
325ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int check_some_characters(checkfp_command *co, checkfp_control c,
326ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *tests);
327ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
328ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int check_one_character(checkfp_command *co, checkfp_control c, int ch)
329ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
330ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Test this character (ch) to ensure the parser does the correct thing.
331ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
332ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_size_t index = 0;
333ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char test = (char)ch;
334ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const int number_is_valid = png_check_fp_number(&test, 1, &c.state, &index);
335ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const int character_accepted = (index == 1);
336ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
337ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (c.check_state != exponent && isdigit(ch) && ch != '0')
338ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      c.is_zero = 0;
339ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
340ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (c.check_state == start && c.at_start && ch == '-')
341ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      c.is_negative = 1;
342ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
343ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (isprint(ch))
344ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->number[c.cnumber++] = (char)ch;
345ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
346ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
347ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->number[c.cnumber++] = '<';
348ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->number[c.cnumber++] = hexdigits[(ch >> 4) & 0xf];
349ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->number[c.cnumber++] = hexdigits[ch & 0xf];
350ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->number[c.cnumber++] = '>';
351ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
352ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   co->number[c.cnumber] = 0;
353ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
354ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (co->verbose > 1)
355ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "%s\n", co->number);
356ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
357ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (++(co->ctimes) == 1000000)
358ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
359ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (co->verbose == 1)
360ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fputc('.', stderr);
361ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      co->ctimes = 0;
362ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++(co->cmillions);
363ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
364ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
365ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (!number_is_valid)
366ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++(co->cinvalid);
367ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
368ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (!character_accepted)
369ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++(co->cnoaccept);
370ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
371ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* This should never fail (it's a serious bug if it does): */
372ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (index != 0 && index != 1)
373ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
374ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "%s: read beyond end of string (%lu)\n", co->number,
375ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         (unsigned long)index);
376ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 0;
377ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
378ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
379ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Validate the new state, note that the PNG_FP_IS_ macros all return
380ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    * false unless the number is valid.
381ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik    */
382ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (PNG_FP_IS_NEGATIVE(c.state) !=
383ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      (number_is_valid && !c.is_zero && c.is_negative))
384ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
385ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "%s: negative when it is not\n", co->number);
386ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 0;
387ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
388ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
389ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (PNG_FP_IS_ZERO(c.state) != (number_is_valid && c.is_zero))
390ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
391ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "%s: zero when it is not\n", co->number);
392ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 0;
393ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
394ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
395ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (PNG_FP_IS_POSITIVE(c.state) !=
396ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      (number_is_valid && !c.is_zero && !c.is_negative))
397ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
398ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fprintf(stderr, "%s: positive when it is not\n", co->number);
399ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return 0;
400ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
401ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
402ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Testing a digit */
403ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (isdigit(ch))
404ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
405ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!character_accepted)
406ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
407ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: digit '%c' not accepted\n", co->number, ch);
408ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
409ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
410ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
411ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!number_is_valid)
412ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
413ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: saw a digit (%c) but number not valid\n",
414ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            co->number, ch);
415ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
416ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
417ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
418ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++c.cdigits_in_state;
419ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      c.at_start = 0;
420ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      c.number_was_valid = 1;
421ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
422ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Continue testing characters in this state.  Either test all of
423ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * them or, if we have already seen one digit in this state, just test a
424ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * limited set.
425ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
426ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (c.cdigits_in_state < 1)
427ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_all_characters(co, c);
428ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
429ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
430ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_some_characters(co, c,
431ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            state_characters[c.check_state].tests);
432ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
433ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
434ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* A non-digit; is it allowed here? */
435ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else if (((ch == '+' || ch == '-') && c.check_state != fraction &&
436ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               c.at_start) ||
437ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            (ch == '.' && c.check_state == start) ||
438ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            ((ch == 'e' || ch == 'E') && c.number_was_valid &&
439ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               c.check_state != exponent))
440ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
441ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!character_accepted)
442ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
443ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: character '%c' not accepted\n", co->number, ch);
444ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
445ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
446ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
447ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* The number remains valid after start of fraction but nowhere else. */
448ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (number_is_valid && (c.check_state != start || ch != '.'))
449ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
450ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: saw a non-digit (%c) but number valid\n",
451ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            co->number, ch);
452ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
453ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
454ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
455ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      c.number_was_valid = number_is_valid;
456ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
457ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Check for a state change.  When changing to 'fraction' if the number
458ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * is valid at this point set the at_start to false to allow an exponent
459ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * 'e' to come next.
460ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
461ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (c.check_state == start && ch == '.')
462ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
463ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.check_state = fraction;
464ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.at_start = !number_is_valid;
465ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.cdigits_in_state = 0;
466ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.limit = co->limit;
467ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_all_characters(co, c);
468ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
469ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
470ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (c.check_state < exponent && (ch == 'e' || ch == 'E'))
471ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
472ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.check_state = exponent;
473ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.at_start = 1;
474ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.cdigits_in_state = 0;
475ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.limit = co->limit;
476ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_all_characters(co, c);
477ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
478ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
479ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Else it was a sign, and the state doesn't change. */
480ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
481ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
482ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (ch != '-' && ch != '+')
483ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
484ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "checkfp: internal error (1)\n");
485ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            return 0;
486ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
487ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
488ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         c.at_start = 0;
489ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_all_characters(co, c);
490ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
491ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
492ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
493ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Testing an invalid character */
494ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   else
495ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
496ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (character_accepted)
497ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
498ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%s: character '%c' [0x%.2x] accepted\n", co->number,
499ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            ch, ch);
500ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
501ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
502ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
503ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (number_is_valid != c.number_was_valid)
504ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
505ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr,
506ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            "%s: character '%c' [0x%.2x] changed number validity\n", co->number,
507ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            ch, ch);
508ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
509ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
510ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
511ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Do nothing - the parser has stuck; return success and keep going with
512ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * the next character.
513ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
514ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
515ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
516ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Successful return (the caller will try the next character.) */
517ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 1;
518ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
519ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
520ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int check_all_characters(checkfp_command *co, checkfp_control c)
521ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
522ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int ch;
523ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
524ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (c.cnumber+4 < sizeof co->number) for (ch=0; ch<256; ++ch)
525ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
526ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!check_one_character(co, c, ch))
527ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 0;
528ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
529ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
530ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 1;
531ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
532ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
533ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic int check_some_characters(checkfp_command *co, checkfp_control c,
534ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   const char *tests)
535ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
536ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i;
537ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
538ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   --(c.limit);
539ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
540ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (c.cnumber+4 < sizeof co->number && c.limit >= 0)
541ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
542ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (c.limit > 0) for (i=0; tests[i]; ++i)
543ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
544ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (!check_one_character(co, c, tests[i]))
545ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               return 0;
546ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
547ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
548ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* At the end check all the characters. */
549ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
550ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return check_all_characters(co, c);
551ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
552ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
553ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 1;
554ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
555ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
556ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint validation_checkfp(int count, int argc, char **argv)
557ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
558ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int result;
559ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   checkfp_command command;
560ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   checkfp_control control;
561ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
562ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.number[0] = 0;
563ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.limit = 3;
564ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.verbose = verbose;
565ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.ctimes = 0;
566ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.cmillions = 0;
567ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.cinvalid = 0;
568ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   command.cnoaccept = 0;
569ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
570ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--argc > 0)
571ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
572ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++argv;
573ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (argc > 1 && strcmp(*argv, "-l") == 0)
574ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
575ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         --argc;
576ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         command.limit = atoi(*++argv);
577ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
578ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
579ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
580ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
581ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "unknown argument %s\n", *argv);
582ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
583ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
584ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
585ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
586ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.cnumber = 0;
587ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.check_state = start;
588ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.at_start = 1;
589ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.cdigits_in_state = 0;
590ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.limit = command.limit;
591ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.state = 0;
592ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.is_negative = 0;
593ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.is_zero = 1;
594ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   control.number_was_valid = 0;
595ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
596ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   result = check_all_characters(&command, control);
597ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
598ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf("checkfp: %s: checked %d,%.3d,%.3d,%.3d strings (%d invalid)\n",
599ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      result ? "pass" : "FAIL", command.cmillions / 1000,
600ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      command.cmillions % 1000, command.ctimes / 1000, command.ctimes % 1000,
601ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      command.cinvalid);
602ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
603ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return result;
604ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
605ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
606ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint validation_muldiv(int count, int argc, char **argv)
607ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
608ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int tested = 0;
609ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int overflow = 0;
610ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int error = 0;
611ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int error64 = 0;
612ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int passed = 0;
613ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int randbits = 0;
614ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_uint_32 randbuffer;
615ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_fixed_point a;
616ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   png_int_32 times, div;
617ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
618ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--argc > 0)
619ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
620ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "unknown argument %s\n", *++argv);
621ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
622ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
623ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
624ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Find out about the random number generator. */
625ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   randbuffer = RAND_MAX;
626ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (randbuffer != 0) ++randbits, randbuffer >>= 1;
627ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf("Using random number generator that makes %d bits\n", randbits);
628ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (div=0; div<32; div += randbits)
629ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      randbuffer = (randbuffer << randbits) ^ rand();
630ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
631ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   a = 0;
632ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   times = div = 0;
633ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   do
634ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
635ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_fixed_point result;
636ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* NOTE: your mileage may vary, a type is required below that can
637ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * hold 64 bits or more, if floating point is used a 64 bit or
638ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * better mantissa is required.
639ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
640ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      long long int fp, fpround;
641ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      unsigned long hi, lo;
642ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      int ok;
643ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
644ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Check the values, png_64bit_product can only handle positive
645ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * numbers, so correct for that here.
646ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
647ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
648ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         long u1, u2;
649ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         int n = 0;
650ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (a < 0) u1 = -a, n = 1; else u1 = a;
651ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (times < 0) u2 = -times, n = !n; else u2 = times;
652ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_64bit_product(u1, u2, &hi, &lo);
653ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (n)
654ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
655ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            /* -x = ~x+1 */
656ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            lo = ((~lo) + 1) & 0xffffffff;
657ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            hi = ~hi;
658ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (lo == 0) ++hi;
659ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
660ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
661ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
662ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fp = a;
663ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      fp *= times;
664ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if ((fp & 0xffffffff) != lo || ((fp >> 32) & 0xffffffff) != hi)
665ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
666ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "png_64bit_product %d * %d -> %lx|%.8lx not %llx\n",
667ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            a, times, hi, lo, fp);
668ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++error64;
669ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
670ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
671ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (div != 0)
672ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
673ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Round - this is C round to zero. */
674ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if ((fp < 0) != (div < 0))
675ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik           fp -= div/2;
676ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
677ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik           fp += div/2;
678ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
679ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fp /= div;
680ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fpround = fp;
681ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         /* Assume 2's complement here: */
682ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ok = fpround <= PNG_UINT_31_MAX &&
683ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik              fpround >= -1-(long long int)PNG_UINT_31_MAX;
684ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (!ok) ++overflow;
685ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
686ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
687ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik        ok = 0, ++overflow, fpround = fp/*misleading*/;
688ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
689ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (verbose)
690ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "TEST %d * %d / %d -> %lld (%s)\n", a, times, div,
691ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fp, ok ? "ok" : "overflow");
692ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
693ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      ++tested;
694ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (png_muldiv(&result, a, times, div) != ok)
695ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
696ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++error;
697ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (ok)
698ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             fprintf(stderr, "%d * %d / %d -> overflow (expected %lld)\n", a,
699ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                times, div, fp);
700ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         else
701ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             fprintf(stderr, "%d * %d / %d -> %d (expected overflow %lld)\n", a,
702ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                times, div, result, fp);
703ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
704ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (ok && result != fpround)
705ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
706ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++error;
707ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "%d * %d / %d -> %d not %lld\n", a, times, div, result,
708ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fp);
709ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
710ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
711ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++passed;
712ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
713ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Generate three new values, this uses rand() and rand() only returns
714ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       * up to RAND_MAX.
715ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik       */
716ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* CRUDE */
717ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      a += times;
718ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      times += div;
719ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      div = randbuffer;
720ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      randbuffer = (randbuffer << randbits) ^ rand();
721ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
722ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--count > 0);
723ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
724ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   printf("%d tests including %d overflows, %d passed, %d failed (%d 64 bit "
725ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      "errors)\n", tested, overflow, passed, error, error64);
726ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
727ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
728ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
729ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* When FP is on this just becomes a speed test - compile without FP to get real
730ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * validation.
731ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
732ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
733ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define LN2 .000010576586617430806112933839 /* log(2)/65536 */
734ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define L2INV 94548.46219969910586572651    /* 65536/log(2) */
735ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
736ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* For speed testing, need the internal functions too: */
737ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_uint_32 png_log8bit(unsigned x)
738ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
739ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (x > 0)
740ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return (png_uint_32)floor(.5-log(x/255.)*L2INV);
741ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
742ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0xffffffff;
743ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
744ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
745ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_uint_32 png_log16bit(png_uint_32 x)
746ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
747ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (x > 0)
748ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      return (png_uint_32)floor(.5-log(x/65535.)*L2INV);
749ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
750ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0xffffffff;
751ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
752ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
753ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_uint_32 png_exp(png_uint_32 x)
754ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
755ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return (png_uint_32)floor(.5 + exp(x * -LN2) * 0xffffffffU);
756ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
757ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
758ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_byte png_exp8bit(png_uint_32 log)
759ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
760ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return (png_byte)floor(.5 + exp(log * -LN2) * 255);
761ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
762ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
763ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikstatic png_uint_16 png_exp16bit(png_uint_32 log)
764ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
765ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return (png_uint_16)floor(.5 + exp(log * -LN2) * 65535);
766ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
767ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#endif /* FLOATING_ARITHMETIC */
768ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
769ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint validation_gamma(int argc, char **argv)
770ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
771ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double gamma[9] = { 2.2, 1.8, 1.52, 1.45, 1., 1/1.45, 1/1.52, 1/1.8, 1/2.2 };
772ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   double maxerr;
773ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int i, silent=0, onlygamma=0;
774ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
775ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Silence the output with -s, just test the gamma functions with -g: */
776ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (--argc > 0)
777ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(*++argv, "-s") == 0)
778ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         silent = 1;
779ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(*argv, "-g") == 0)
780ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         onlygamma = 1;
781ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
782ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
783ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         fprintf(stderr, "unknown argument %s\n", *argv);
784ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return 1;
785ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
786ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
787ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (!onlygamma)
788ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
789ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* First validate the log functions: */
790ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
791ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=0; i<256; ++i)
792ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
793ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = -log(i/255.)/log(2.)*65536;
794ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = png_log8bit(i) - correct;
795ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
796ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (i != 0 && fabs(error) > maxerr)
797ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
798ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
799ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (i == 0 && png_log8bit(i) != 0xffffffff ||
800ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             i != 0 && png_log8bit(i) != floor(correct+.5))
801ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
802ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "8 bit log error: %d: got %u, expected %f\n",
803ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               i, png_log8bit(i), correct);
804ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
805ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
806ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
807ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
808ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("maximum 8 bit log error = %f\n", maxerr);
809ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
810ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
811ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=0; i<65536; ++i)
812ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
813ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = -log(i/65535.)/log(2.)*65536;
814ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = png_log16bit(i) - correct;
815ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
816ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (i != 0 && fabs(error) > maxerr)
817ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
818ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
819ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (i == 0 && png_log16bit(i) != 0xffffffff ||
820ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik             i != 0 && png_log16bit(i) != floor(correct+.5))
821ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
822ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            if (error > .68) /* By experiment error is less than .68 */
823ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            {
824ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               fprintf(stderr, "16 bit log error: %d: got %u, expected %f"
825ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  " error: %f\n", i, png_log16bit(i), correct, error);
826ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            }
827ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
828ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
829ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
830ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
831ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("maximum 16 bit log error = %f\n", maxerr);
832ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
833ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      /* Now exponentiations. */
834ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
835ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=0; i<=0xfffff; ++i)
836ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
837ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = exp(-i/65536. * log(2.)) * (65536. * 65536);
838ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = png_exp(i) - correct;
839ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
840ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > maxerr)
841ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
842ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > 1883) /* By experiment. */
843ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
844ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "32 bit exp error: %d: got %u, expected %f"
845ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  " error: %f\n", i, png_exp(i), correct, error);
846ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
847ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
848ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
849ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
850ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("maximum 32 bit exp error = %f\n", maxerr);
851ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
852ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
853ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=0; i<=0xfffff; ++i)
854ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
855ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = exp(-i/65536. * log(2.)) * 255;
856ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = png_exp8bit(i) - correct;
857ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
858ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > maxerr)
859ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
860ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > .50002) /* By experiment */
861ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
862ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "8 bit exp error: %d: got %u, expected %f"
863ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  " error: %f\n", i, png_exp8bit(i), correct, error);
864ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
865ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
866ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
867ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
868ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("maximum 8 bit exp error = %f\n", maxerr);
869ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
870ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
871ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (i=0; i<=0xfffff; ++i)
872ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
873ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = exp(-i/65536. * log(2.)) * 65535;
874ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = png_exp16bit(i) - correct;
875ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
876ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > maxerr)
877ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
878ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > .524) /* By experiment */
879ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
880ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "16 bit exp error: %d: got %u, expected %f"
881ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik                  " error: %f\n", i, png_exp16bit(i), correct, error);
882ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
883ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
884ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
885ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
886ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("maximum 16 bit exp error = %f\n", maxerr);
887ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   } /* !onlygamma */
888ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
889ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Test the overall gamma correction. */
890ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   for (i=0; i<9; ++i)
891ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
892ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      unsigned j;
893ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      double g = gamma[i];
894ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      png_fixed_point gfp = floor(g * PNG_FP_1 + .5);
895ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
896ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
897ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("Test gamma %f\n", g);
898ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
899ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
900ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (j=0; j<256; ++j)
901ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
902ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = pow(j/255., g) * 255;
903ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_byte out = png_gamma_8bit_correct(j, gfp);
904ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = out - correct;
905ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
906ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > maxerr)
907ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
908ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (out != floor(correct+.5))
909ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
910ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "8bit %d ^ %f: got %d expected %f error %f\n",
911ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               j, g, out, correct, error);
912ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
913ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
914ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
915ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
916ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("gamma %f: maximum 8 bit error %f\n", g, maxerr);
917ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
918ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      maxerr = 0;
919ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      for (j=0; j<65536; ++j)
920ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
921ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double correct = pow(j/65535., g) * 65535;
922ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         png_uint_16 out = png_gamma_16bit_correct(j, gfp);
923ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         double error = out - correct;
924ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
925ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > maxerr)
926ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            maxerr = fabs(error);
927ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         if (fabs(error) > 1.62)
928ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         {
929ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik            fprintf(stderr, "16bit %d ^ %f: got %d expected %f error %f\n",
930ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik               j, g, out, correct, error);
931ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         }
932ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
933ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
934ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (!silent)
935ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         printf("gamma %f: maximum 16 bit error %f\n", g, maxerr);
936ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
937ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
938ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 0;
939ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
940ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
941ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/**************************** VALIDATION TESTS ********************************/
942ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* Various validation routines are included herein, they require some
943ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * definition for png_warning and png_error, seetings of VALIDATION:
944ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik *
945ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 1: validates the ASCII to floating point conversions
946ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 2: validates png_muldiv
947ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * 3: accuracy test of fixed point gamma tables
948ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
949ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
950ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik/* The following COUNT (10^8) takes about 1 hour on a 1GHz Pentium IV
951ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik * processor.
952ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik */
953ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik#define COUNT 1000000000
954ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
955ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craikint main(int argc, char **argv)
956ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik{
957ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   int count = COUNT;
958ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
959ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   while (argc > 1)
960ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
961ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (argc > 2 && strcmp(argv[1], "-c") == 0)
962ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
963ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         count = atoi(argv[2]);
964ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         argc -= 2;
965ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         argv += 2;
966ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
967ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
968ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(argv[1], "-v") == 0)
969ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      {
970ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++verbose;
971ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         --argc;
972ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         ++argv;
973ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      }
974ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
975ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else
976ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         break;
977ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
978ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
979ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   if (count > 0 && argc > 1)
980ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   {
981ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      if (strcmp(argv[1], "ascii") == 0)
982ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return validation_ascii_to_fp(count, argc-1, argv+1);
983ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(argv[1], "checkfp") == 0)
984ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return validation_checkfp(count, argc-1, argv+1);
985ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(argv[1], "muldiv") == 0)
986ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return validation_muldiv(count, argc-1, argv+1);
987ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      else if (strcmp(argv[1], "gamma") == 0)
988ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik         return validation_gamma(argc-1, argv+1);
989ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   }
990ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik
991ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   /* Bad argument: */
992ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr,
993ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik      "usage: tarith [-v] [-c count] {ascii,muldiv,gamma} [args]\n");
994ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, " arguments: ascii [-a (all results)] [-e error%%]\n");
995ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "            checkfp [-l max-number-chars]\n");
996ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "            muldiv\n");
997ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   fprintf(stderr, "            gamma -s (silent) -g (only gamma; no log)\n");
998ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik   return 1;
999ca2bf81b02c99afa2e76b3b2c6eb232c239221e0Chris Craik}
1000