 Timestamp:
 May 25, 2009, 2:16:44 AM (11 years ago)
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

libpipi/trunk/examples/img2twit.cpp
r3518 r3520 12 12 #include <pipi.h> 13 13 14 #define TOTAL_POINTS 138 14 /* 15 * Userdefinable settings. 16 */ 17 18 /* The maximum message length */ 19 #define MAX_MSG_LEN 140 20 21 /* The number of characters at disposal */ 22 //#define NUM_CHARACTERS 0x7fffffff // The sky's the limit 23 //#define NUM_CHARACTERS 1111998 // Full valid Unicode set 24 //#define NUM_CHARACTERS 100507 // Full graphic Unicode 25 #define NUM_CHARACTERS 32768 // Chinese characters 26 //#define NUM_CHARACTERS 127 // ASCII 27 28 /* The maximum image size we want to support */ 29 #define MAX_W 4000 30 #define MAX_H 4000 31 32 /* How does the algorithm work: one point per cell, or two */ 15 33 #define POINTS_PER_CELL 2 16 34 17 #define RANGE_X 16 18 #define RANGE_Y 16 19 #define RANGE_R 5 20 #define RANGE_G 5 21 #define RANGE_B 5 22 #define RANGE_S 1 35 /* The range value for point parameters: X Y, red/green/blue, "strength" 36 * Tested values (on Mona Lisa) are: 37 * 16 16 5 5 5 2 > 0.06511725914 38 * 16 16 6 7 6 1 > 0.05731491348 * 39 * 16 16 7 6 6 1 > 0.06450513783 40 * 14 14 7 7 6 1 > 0.0637207893 41 * 19 19 6 6 5 1 > 0.06801999094 */ 42 static unsigned int RANGE_X = 16; 43 static unsigned int RANGE_Y = 16; 44 static unsigned int RANGE_R = 6; 45 static unsigned int RANGE_G = 6; 46 static unsigned int RANGE_B = 6; 47 static unsigned int RANGE_S = 1; 48 49 /* 50 * These values are computed at runtime 51 */ 52 53 static float TOTAL_BITS; 54 static float HEADER_BITS; 55 static float DATA_BITS; 56 static float POINT_BITS; 57 58 static unsigned int TOTAL_CELLS; 23 59 24 60 #define RANGE_SY (RANGE_S*RANGE_Y) … … 33 69 34 70 /* Global aspect ratio */ 35 static int dw, dh;71 static unsigned int dw, dh; 36 72 37 73 /* Global point encoding */ … … 49 85 } 50 86 51 static inline int float2int(float val, int range)87 static inline int range2int(float val, int range) 52 88 { 53 89 int ret = (int)(val * ((float)range  0.0001)); 54 return ret < 0 ? 0 : ret > range  1 ? range  1 : ret;55 } 56 57 static inline float int2 float(int val, int range)90 return ret < 0 ? 0 : ret > range  1 ? range  1 : ret; 91 } 92 93 static inline float int2midrange(int val, int range) 58 94 { 59 95 return (float)(1 + 2 * val) / (float)(2 * range); 60 96 } 61 97 62 static inline uint32_t set_point(int index, float x, float y, float r, 63 float g, float b, float s) 98 static inline float int2fullrange(int val, int range) 99 { 100 return range > 1 ? (float)val / (float)(range  1) : 0.0; 101 } 102 103 static inline void set_point(int index, float x, float y, float r, 104 float g, float b, float s) 64 105 { 65 106 int dx = (index / POINTS_PER_CELL) % dw; … … 69 110 float fy = (y  dy * RANGE_Y) / RANGE_Y; 70 111 71 int is = float2int(s, RANGE_S);72 73 int ix = float2int(fx, RANGE_X);74 int iy = float2int(fy, RANGE_Y);75 76 int ir = float2int(r, RANGE_R);77 int ig = float2int(g, RANGE_G);78 int ib = float2int(b, RANGE_B);112 int is = range2int(s, RANGE_S); 113 114 int ix = range2int(fx, RANGE_X); 115 int iy = range2int(fy, RANGE_Y); 116 117 int ir = range2int(r, RANGE_R); 118 int ig = range2int(g, RANGE_G); 119 int ib = range2int(b, RANGE_B); 79 120 80 121 points[index] = is + RANGE_S * (iy + RANGE_Y * (ix + RANGE_X * … … 90 131 unsigned int dy = (index / POINTS_PER_CELL) / dw; 91 132 92 float fs = int2float(pt % RANGE_S, RANGE_S); pt /= RANGE_S; 93 94 *s = fs < 0.5 ? 0.0 : 1.0; 95 96 float fy = int2float(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y; 97 float fx = int2float(pt % RANGE_X, RANGE_X); pt /= RANGE_X; 133 *s = int2fullrange(pt % RANGE_S, RANGE_S); pt /= RANGE_S; 134 135 float fy = int2midrange(pt % RANGE_Y, RANGE_Y); pt /= RANGE_Y; 136 float fx = int2midrange(pt % RANGE_X, RANGE_X); pt /= RANGE_X; 98 137 99 138 *x = (fx + dx) * RANGE_X; 100 139 *y = (fy + dy) * RANGE_Y; 101 140 102 *b = int2 float(pt % RANGE_R, RANGE_R); pt /= RANGE_R;103 *g = int2 float(pt % RANGE_G, RANGE_G); pt /= RANGE_G;104 *r = int2 float(pt % RANGE_B, RANGE_B); pt /= RANGE_B;141 *b = int2midrange(pt % RANGE_R, RANGE_R); pt /= RANGE_R; 142 *g = int2midrange(pt % RANGE_G, RANGE_G); pt /= RANGE_G; 143 *r = int2midrange(pt % RANGE_B, RANGE_B); pt /= RANGE_B; 105 144 } 106 145 … … 115 154 { 116 155 set_point(npoints, x, y, r, g, b, s); 117 get_point(npoints, &x, &y, &r, &g, &b, &s);118 156 npoints++; 119 157 } 120 158 121 #define MAX_OPS 15 159 static void add_random_point() 160 { 161 points[npoints] = det_rand(RANGE_SYXRGB); 162 npoints++; 163 } 164 165 #define NB_OPS 20 166 167 static uint8_t rand_op(void) 168 { 169 uint8_t x = det_rand(NB_OPS); 170 171 /* Randomly ignore statistically less efficient ops */ 172 if(x == 0) 173 return rand_op(); 174 if(x == 1 && (RANGE_S == 1  det_rand(2))) 175 return rand_op(); 176 if(x <= 5 && det_rand(2)) 177 return rand_op(); 178 //if((x < 10  x > 15) && !det_rand(4)) /* Favour colour changes */ 179 // return rand_op(); 180 181 return x; 182 } 122 183 123 184 static uint32_t apply_op(uint8_t op, uint32_t val) … … 128 189 { 129 190 case 0: /* Flip strength value */ 191 case 1: 192 /* Statistics show that this helps often, but does not reduce 193 * the error significantly. */ 130 194 return val ^ 1; 131 case 1: /* Move up; if impossible, down */195 case 2: /* Move up; if impossible, down */ 132 196 rem = val % RANGE_S; 133 197 ext = (val / RANGE_S) % RANGE_Y; 134 198 ext = ext > 0 ? ext  1 : ext + 1; 135 199 return (val / RANGE_SY * RANGE_Y + ext) * RANGE_S + rem; 136 case 2: /* Move down; if impossible, up */200 case 3: /* Move down; if impossible, up */ 137 201 rem = val % RANGE_S; 138 202 ext = (val / RANGE_S) % RANGE_Y; 139 203 ext = ext < RANGE_Y  1 ? ext + 1 : ext  1; 140 204 return (val / RANGE_SY * RANGE_Y + ext) * RANGE_S + rem; 141 case 3: /* Move left; if impossible, right */205 case 4: /* Move left; if impossible, right */ 142 206 rem = val % RANGE_SY; 143 207 ext = (val / RANGE_SY) % RANGE_X; 144 208 ext = ext > 0 ? ext  1 : ext + 1; 145 209 return (val / RANGE_SYX * RANGE_X + ext) * RANGE_SY + rem; 146 case 4: /* Move left; if impossible, right */210 case 5: /* Move left; if impossible, right */ 147 211 rem = val % RANGE_SY; 148 212 ext = (val / RANGE_SY) % RANGE_X; 149 213 ext = ext < RANGE_X  1 ? ext + 1 : ext  1; 150 214 return (val / RANGE_SYX * RANGE_X + ext) * RANGE_SY + rem; 151 case 5: /* Corner 1 */ 152 return apply_op(1, apply_op(3, val)); 153 case 6: /* Corner 2 */ 154 return apply_op(1, apply_op(4, val)); 155 case 7: /* Corner 3 */ 215 case 6: /* Corner 1 */ 156 216 return apply_op(2, apply_op(4, val)); 157 case 8: /* Corner 4 */ 158 return apply_op(2, apply_op(3, val)); 159 case 9: /* R (or R++) */ 217 case 7: /* Corner 2 */ 218 return apply_op(2, apply_op(5, val)); 219 case 8: /* Corner 3 */ 220 return apply_op(3, apply_op(5, val)); 221 case 9: /* Corner 4 */ 222 return apply_op(3, apply_op(4, val)); 223 case 16: /* Double up */ 224 return apply_op(2, apply_op(2, val)); 225 case 17: /* Double down */ 226 return apply_op(3, apply_op(3, val)); 227 case 18: /* Double left */ 228 return apply_op(4, apply_op(4, val)); 229 case 19: /* Double right */ 230 return apply_op(5, apply_op(5, val)); 231 case 10: /* R (or R++) */ 160 232 rem = val % RANGE_SYX; 161 233 ext = (val / RANGE_SYX) % RANGE_R; 162 234 ext = ext > 0 ? ext  1 : ext + 1; 163 235 return (val / RANGE_SYXR * RANGE_R + ext) * RANGE_SYX + rem; 164 case 1 0: /* R++ (or R) */236 case 11: /* R++ (or R) */ 165 237 rem = val % RANGE_SYX; 166 238 ext = (val / RANGE_SYX) % RANGE_R; 167 239 ext = ext < RANGE_R  1 ? ext + 1 : ext  1; 168 240 return (val / RANGE_SYXR * RANGE_R + ext) * RANGE_SYX + rem; 169 case 1 1: /* G (or G++) */241 case 12: /* G (or G++) */ 170 242 rem = val % RANGE_SYXR; 171 243 ext = (val / RANGE_SYXR) % RANGE_G; 172 244 ext = ext > 0 ? ext  1 : ext + 1; 173 245 return (val / RANGE_SYXRG * RANGE_G + ext) * RANGE_SYXR + rem; 174 case 1 2: /* G++ (or G) */246 case 13: /* G++ (or G) */ 175 247 rem = val % RANGE_SYXR; 176 248 ext = (val / RANGE_SYXR) % RANGE_G; 177 249 ext = ext < RANGE_G  1 ? ext + 1 : ext  1; 178 250 return (val / RANGE_SYXRG * RANGE_G + ext) * RANGE_SYXR + rem; 179 case 1 3: /* B (or B++) */251 case 14: /* B (or B++) */ 180 252 rem = val % RANGE_SYXRG; 181 253 ext = (val / RANGE_SYXRG) % RANGE_B; 182 254 ext = ext > 0 ? ext  1 : ext + 1; 183 255 return ext * RANGE_SYXRG + rem; 184 case 1 4: /* B++ (or B) */256 case 15: /* B++ (or B) */ 185 257 rem = val % RANGE_SYXRG; 186 258 ext = (val / RANGE_SYXRG) % RANGE_B; … … 212 284 static void render(pipi_image_t *dst, int rx, int ry, int rw, int rh) 213 285 { 214 uint8_t lookup[TOTAL_ POINTS / POINTS_PER_CELL* RANGE_X * RANGE_Y];286 uint8_t lookup[TOTAL_CELLS * RANGE_X * RANGE_Y]; 215 287 pipi_pixels_t *p = pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32); 216 288 float *data = (float *)p>pixels; 217 float fx, fy, fr, fg, fb, fs;218 289 int i, x, y; 219 290 … … 222 293 for(i = 0; i < npoints; i++) 223 294 { 295 float fx, fy, fr, fg, fb, fs; 224 296 get_point(i, &fx, &fy, &fr, &fg, &fb, &fs); 225 297 lookup[(int)fx + dw * RANGE_X * (int)fy] = i; /* Keep link to point */ … … 237 309 for(x = rx; x < rx + rw; x++) 238 310 { 239 int i1 = 0, i2 = 0, i3 = 0;240 float d1 = 1000000, d2 = 0, d3 = 0;241 242 311 K::Point_2 m(x, y); 243 312 Point_coordinate_vector coords; … … 253 322 for(it = coords.begin(); it != coords.end(); ++it) 254 323 { 255 float fx = (*it).first.x(); 256 float fy = (*it).first.y(); 324 float fx, fy, fr, fg, fb, fs; 325 326 fx = (*it).first.x(); 327 fy = (*it).first.y(); 257 328 258 329 if(fx < 0  fy < 0  fx > p>w  1  fy > p>h  1) … … 263 334 get_point(index, &fx, &fy, &fr, &fg, &fb, &fs); 264 335 265 float k = (*it).second;266 if(fs > 0.5) k = pow(k, 1.2);267 else k = pow(k, 0.8);268 //float k = (*it).second * (1.0f + fs);336 //float k = pow((*it).second * (1.0 + fs), 1.2); 337 float k = (*it).second * (1.00f + fs); 338 //float k = (*it).second * (0.60f + fs); 339 //float k = pow((*it).second, (1.0f + fs)); 269 340 270 341 r += k * fr; … … 288 359 pipi_pixels_t *p = pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32); 289 360 float *data = (float *)p>pixels; 290 int i; 291 292 for(int dy = 0; dy < dh; dy++) 293 for(int dx = 0; dx < dw; dx++) 361 362 for(unsigned int dy = 0; dy < dh; dy++) 363 for(unsigned int dx = 0; dx < dw; dx++) 294 364 { 295 365 float min = 1.1f, max = 0.1f; … … 298 368 int npixels = 0; 299 369 300 for( int iy = RANGE_Y * dy; iy < RANGE_Y * (dy + 1); iy++)301 for( int ix = RANGE_X * dx; ix < RANGE_X * (dx + 1); ix++)370 for(unsigned int iy = RANGE_Y * dy; iy < RANGE_Y * (dy + 1); iy++) 371 for(unsigned int ix = RANGE_X * dx; ix < RANGE_X * (dx + 1); ix++) 302 372 { 303 373 float lum = 0.0f; … … 331 401 if(total < min + (max  min) / 4) 332 402 wmin = 1.0, wmax = 0.0; 333 else if(total < min + (max  min) / 4 * 2)334 wmin = 0.0, wmax = 0.0;335 403 else if(total < min + (max  min) / 4 * 3) 336 404 wmin = 0.0, wmax = 0.0; … … 338 406 wmin = 0.0, wmax = 1.0; 339 407 340 //wmin = wmax = 1.0; 341 //if(total < min + (max  min) /3 ) 342 //if((dx + dy) & 1) 343 { 408 #if 0 409 add_random_point(); 410 add_random_point(); 411 #else 412 #if POINTS_PER_CELL == 1 413 if(total < min + (max  min) / 2) 414 { 415 #endif 344 416 add_point(xmin, ymin, 345 417 data[4 * (xmin + ymin * p>w) + 0], … … 347 419 data[4 * (xmin + ymin * p>w) + 2], 348 420 wmin); 349 } 350 //else 351 { 421 #if POINTS_PER_CELL == 1 422 } 423 else 424 { 425 #endif 352 426 add_point(xmax, ymax, 353 427 data[4 * (xmax + ymax * p>w) + 0], … … 355 429 data[4 * (xmax + ymax * p>w) + 2], 356 430 wmax); 357 } 431 #if POINTS_PER_CELL == 1 432 } 433 #endif 434 #endif 358 435 } 359 436 } … … 361 438 int main(int argc, char *argv[]) 362 439 { 363 int opstats[2 * MAX_OPS];440 int opstats[2 * NB_OPS]; 364 441 pipi_image_t *src, *tmp, *dst; 365 442 double error = 1.0; 366 443 int width, height, ret = 0; 444 445 /* Compute bit allocation */ 446 fprintf(stderr, "Available characters: %i\n", NUM_CHARACTERS); 447 fprintf(stderr, "Maximum message size: %i\n", MAX_MSG_LEN); 448 TOTAL_BITS = MAX_MSG_LEN * logf(NUM_CHARACTERS) / logf(2); 449 fprintf(stderr, "Available bits: %f\n", TOTAL_BITS); 450 fprintf(stderr, "Maximum image resolution: %ix%i\n", MAX_W, MAX_H); 451 HEADER_BITS = logf(MAX_W * MAX_H) / logf(2); 452 fprintf(stderr, "Header bits: %f\n", HEADER_BITS); 453 DATA_BITS = TOTAL_BITS  HEADER_BITS; 454 fprintf(stderr, "Bits available for data: %f\n", DATA_BITS); 455 #if POINTS_PER_CELL == 1 456 POINT_BITS = logf(RANGE_SYXRGB) / logf(2); 457 #else 458 float coord_bits = logf((RANGE_Y * RANGE_X) * (RANGE_Y * RANGE_X + 1) / 2); 459 float other_bits = logf(RANGE_R * RANGE_G * RANGE_B * RANGE_S); 460 POINT_BITS = (coord_bits + 2 * other_bits) / logf(2); 461 #endif 462 fprintf(stderr, "Cell bits: %f\n", POINT_BITS); 463 TOTAL_CELLS = (int)(DATA_BITS / POINT_BITS); 464 fprintf(stderr, "Available cells: %i\n", TOTAL_CELLS); 465 fprintf(stderr, "Wasted bits: %f\n", DATA_BITS  POINT_BITS * TOTAL_CELLS); 367 466 368 467 /* Load image */ … … 373 472 374 473 /* Compute best w/h ratio */ 375 dw = 1; 376 for( int i = 1; i <= TOTAL_POINTS / POINTS_PER_CELL; i++)474 dw = 1; dh = TOTAL_CELLS; 475 for(unsigned int i = 1; i <= TOTAL_CELLS; i++) 377 476 { 477 int j = TOTAL_CELLS / i; 478 378 479 float r = (float)width / (float)height; 379 float ir = (float)i / (float) (TOTAL_POINTS / POINTS_PER_CELL / i);380 float dwr = (float)dw / (float) (TOTAL_POINTS / POINTS_PER_CELL / dw);480 float ir = (float)i / (float)j; 481 float dwr = (float)dw / (float)dh; 381 482 382 483 if(fabs(logf(r / ir)) < fabs(logf(r / dwr))) 484 { 383 485 dw = i; 486 dh = TOTAL_CELLS / dw; 487 } 384 488 } 385 dh = TOTAL_POINTS / POINTS_PER_CELL / dw; 386 fprintf(stderr, "Chosen image ratio: %i:%i\n", dw, dh); 489 while((dh + 1) * dw <= TOTAL_CELLS) dh++; 490 while(dw * (dh + 1) <= TOTAL_CELLS) dw++; 491 fprintf(stderr, "Chosen image ratio: %i:%i (wasting %i point cells)\n", 492 dw, dh, TOTAL_CELLS  dw * dh); 493 fprintf(stderr, "Total wasted bits: %f\n", 494 DATA_BITS  POINT_BITS * dw * dh); 387 495 388 496 /* Resize and filter image to better state */ 389 497 tmp = pipi_resize(src, dw * RANGE_X, dh * RANGE_Y); 390 498 pipi_free(src); 391 src = pipi_median_ext(tmp, 2, 2); 499 src = pipi_median_ext(tmp, 1, 1); 500 pipi_free(tmp); 392 501 393 502 /* Analyse image */ … … 402 511 403 512 memset(opstats, 0, sizeof(opstats)); 404 for(int iter = 0, failures = 0; /*failures < 200 &&*/ iter < 3000; iter++) 513 for(int iter = 0, stuck = 0, failures = 0, success = 0; 514 /*stuck < 5 && */iter < 10000; 515 iter++) 405 516 { 406 uint32_t oldval; 517 if(failures > 500) 518 { 519 stuck++; 520 failures = 0; 521 } 522 407 523 pipi_image_t *scrap = pipi_copy(tmp); 408 524 409 525 /* Choose a point at random */ 410 526 int pt = det_rand(npoints); 411 oldval = points[pt]; 412 413 /* Apply a random operation and measure its effect */ 414 uint8_t op = det_rand(MAX_OPS); 415 points[pt] = apply_op(op, oldval); 416 render(scrap, 0, 0, dw * RANGE_X, dh * RANGE_Y); 417 418 opstats[op * 2]++; 419 420 double newerr = pipi_measure_rmsd(src, scrap); 421 if(newerr < error) 527 uint32_t oldval = points[pt]; 528 529 /* Compute the affected image zone */ 530 float fx, fy, fr, fg, fb, fs; 531 get_point(pt, &fx, &fy, &fr, &fg, &fb, &fs); 532 int zonex = (int)fx / RANGE_X  1; 533 int zoney = (int)fy / RANGE_Y  1; 534 int zonew = 3; 535 int zoneh = 3; 536 if(zonex < 0) { zonex = 0; zonew; } 537 if(zoney < 0) { zoney = 0; zoneh; } 538 if(zonex + zonew >= (int)dw) { zonew; } 539 if(zoney + zoneh >= (int)dh) { zoneh; } 540 541 /* Choose random operations and measure their effect */ 542 uint8_t op1 = rand_op(); 543 //uint8_t op2 = rand_op(); 544 545 uint32_t candidates[3]; 546 double besterr = error + 1.0; 547 int bestop = 1; 548 candidates[0] = apply_op(op1, oldval); 549 //candidates[1] = apply_op(op2, oldval); 550 //candidates[2] = apply_op(op1, apply_op(op2, oldval)); 551 552 for(int i = 0; i < 1; i++) 553 //for(int i = 0; i < 3; i++) 422 554 { 555 if(oldval == candidates[i]) 556 continue; 557 558 points[pt] = candidates[i]; 559 560 render(scrap, zonex * RANGE_X, zoney * RANGE_Y, 561 zonew * RANGE_X, zoneh * RANGE_Y); 562 563 double newerr = pipi_measure_rmsd(src, scrap); 564 if(newerr < besterr) 565 { 566 besterr = newerr; 567 bestop = i; 568 } 569 } 570 571 opstats[op1 * 2]++; 572 //opstats[op2 * 2]++; 573 574 if(besterr < error) 575 { 576 points[pt] = candidates[bestop]; 577 /* Redraw image if the last check wasn't the best one */ 578 if(bestop != 2) 579 render(scrap, zonex * RANGE_X, zoney * RANGE_Y, 580 zonew * RANGE_X, zoneh * RANGE_Y); 581 423 582 pipi_free(tmp); 424 583 tmp = scrap; 425 error = newerr; 426 fprintf(stderr, "%06i %2.010g after op%i(%i)\n", 427 iter, error, op, pt); 428 opstats[op * 2 + 1]++; 584 //fprintf(stderr, "%08i %2.010g %2.010g after op%i(%i)\n", 585 // iter, besterr  error, error, op1, pt); 586 fprintf(stderr, "%08i .%08i %2.010g after op%i(%i)\n", iter, 587 (int)((error  besterr) * 100000000), error, op1, pt); 588 error = besterr; 589 opstats[op1 * 2 + 1]++; 590 //opstats[op2 * 2 + 1]++; 429 591 failures = 0; 592 success++; 593 594 /* Save image! */ 595 //char buf[128]; 596 //sprintf(buf, "twit%08i.bmp", success); 597 //if((success % 10) == 0) 598 // pipi_save(tmp, buf); 430 599 } 431 600 else … … 437 606 } 438 607 439 fprintf(stderr, "operation: "); 440 for(int i = 0; i < MAX_OPS; i++) 441 fprintf(stderr, "%3i ", i); 442 fprintf(stderr, "\nattempts: "); 443 for(int i = 0; i < MAX_OPS; i++) 444 fprintf(stderr, "%3i ", opstats[i * 2]); 445 fprintf(stderr, "\nsuccesses: "); 446 for(int i = 0; i < MAX_OPS; i++) 447 fprintf(stderr, "%3i ", opstats[i * 2 + 1]); 448 fprintf(stderr, "\n"); 608 for(int j = 0; j < 2; j++) 609 { 610 fprintf(stderr, "operation: "); 611 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 612 fprintf(stderr, "%4i ", i); 613 fprintf(stderr, "\nattempts: "); 614 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 615 fprintf(stderr, "%4i ", opstats[i * 2]); 616 fprintf(stderr, "\nsuccesses: "); 617 for(int i = NB_OPS / 2 * j; i < NB_OPS / 2 * (j + 1); i++) 618 fprintf(stderr, "%4i ", opstats[i * 2 + 1]); 619 fprintf(stderr, "\n"); 620 } 449 621 450 622 fprintf(stderr, "Distance: %2.10g\n", error);
Note: See TracChangeset
for help on using the changeset viewer.