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