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