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