VirtualBox

source: vbox/trunk/src/libs/libpng-1.6.45/contrib/libtests/tarith.c@ 107813

Last change on this file since 107813 was 107813, checked in by vboxsync, 3 weeks ago

libpng-1.6.45: Applied and adjusted our libpng changes to 1.6.45. bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette