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