Tesseract
3.02
|
00001 /********************************************************************** 00002 * File: statistc.c (Formerly stats.c) 00003 * Description: Simple statistical package for integer values. 00004 * Author: Ray Smith 00005 * Created: Mon Feb 04 16:56:05 GMT 1991 00006 * 00007 * (C) Copyright 1991, Hewlett-Packard Ltd. 00008 ** Licensed under the Apache License, Version 2.0 (the "License"); 00009 ** you may not use this file except in compliance with the License. 00010 ** You may obtain a copy of the License at 00011 ** http://www.apache.org/licenses/LICENSE-2.0 00012 ** Unless required by applicable law or agreed to in writing, software 00013 ** distributed under the License is distributed on an "AS IS" BASIS, 00014 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 ** See the License for the specific language governing permissions and 00016 ** limitations under the License. 00017 * 00018 **********************************************************************/ 00019 00020 #include "mfcpch.h" //precompiled headers 00021 #include "statistc.h" 00022 #include <string.h> 00023 #include <math.h> 00024 #include <stdlib.h> 00025 #include "helpers.h" 00026 #include "scrollview.h" 00027 #include "tprintf.h" 00028 00029 // Include automatically generated configuration file if running autoconf. 00030 #ifdef HAVE_CONFIG_H 00031 #include "config_auto.h" 00032 #endif 00033 00034 /********************************************************************** 00035 * STATS::STATS 00036 * 00037 * Construct a new stats element by allocating and zeroing the memory. 00038 **********************************************************************/ 00039 STATS::STATS(inT32 min_bucket_value, inT32 max_bucket_value_plus_1) { 00040 if (max_bucket_value_plus_1 <= min_bucket_value) { 00041 min_bucket_value = 0; 00042 max_bucket_value_plus_1 = 1; 00043 } 00044 rangemin_ = min_bucket_value; // setup 00045 rangemax_ = max_bucket_value_plus_1; 00046 buckets_ = new inT32[rangemax_ - rangemin_]; 00047 clear(); 00048 } 00049 00050 STATS::STATS() { 00051 rangemax_ = 0; 00052 rangemin_ = 0; 00053 buckets_ = NULL; 00054 } 00055 00056 /********************************************************************** 00057 * STATS::set_range 00058 * 00059 * Alter the range on an existing stats element. 00060 **********************************************************************/ 00061 bool STATS::set_range(inT32 min_bucket_value, inT32 max_bucket_value_plus_1) { 00062 if (max_bucket_value_plus_1 <= min_bucket_value) { 00063 return false; 00064 } 00065 if (rangemax_ - rangemin_ != max_bucket_value_plus_1 - min_bucket_value) { 00066 delete [] buckets_; 00067 buckets_ = new inT32[max_bucket_value_plus_1 - min_bucket_value]; 00068 } 00069 rangemin_ = min_bucket_value; // setup 00070 rangemax_ = max_bucket_value_plus_1; 00071 clear(); // zero it 00072 return true; 00073 } 00074 00075 /********************************************************************** 00076 * STATS::clear 00077 * 00078 * Clear out the STATS class by zeroing all the buckets. 00079 **********************************************************************/ 00080 void STATS::clear() { // clear out buckets 00081 total_count_ = 0; 00082 if (buckets_ != NULL) 00083 memset(buckets_, 0, (rangemax_ - rangemin_) * sizeof(buckets_[0])); 00084 } 00085 00086 /********************************************************************** 00087 * STATS::~STATS 00088 * 00089 * Destructor for a stats class. 00090 **********************************************************************/ 00091 STATS::~STATS () { 00092 if (buckets_ != NULL) { 00093 delete [] buckets_; 00094 buckets_ = NULL; 00095 } 00096 } 00097 00098 /********************************************************************** 00099 * STATS::add 00100 * 00101 * Add a set of samples to (or delete from) a pile. 00102 **********************************************************************/ 00103 void STATS::add(inT32 value, inT32 count) { 00104 if (buckets_ == NULL) { 00105 return; 00106 } 00107 value = ClipToRange(value, rangemin_, rangemax_ - 1); 00108 buckets_[value - rangemin_] += count; 00109 total_count_ += count; // keep count of total 00110 } 00111 00112 /********************************************************************** 00113 * STATS::mode 00114 * 00115 * Find the mode of a stats class. 00116 **********************************************************************/ 00117 inT32 STATS::mode() const { // get mode of samples 00118 if (buckets_ == NULL) { 00119 return rangemin_; 00120 } 00121 inT32 max = buckets_[0]; // max cell count 00122 inT32 maxindex = 0; // index of max 00123 for (int index = rangemax_ - rangemin_ - 1; index > 0; --index) { 00124 if (buckets_[index] > max) { 00125 max = buckets_[index]; // find biggest 00126 maxindex = index; 00127 } 00128 } 00129 return maxindex + rangemin_; // index of biggest 00130 } 00131 00132 /********************************************************************** 00133 * STATS::mean 00134 * 00135 * Find the mean of a stats class. 00136 **********************************************************************/ 00137 double STATS::mean() const { //get mean of samples 00138 if (buckets_ == NULL || total_count_ <= 0) { 00139 return static_cast<double>(rangemin_); 00140 } 00141 inT64 sum = 0; 00142 for (int index = rangemax_ - rangemin_ - 1; index >= 0; --index) { 00143 sum += static_cast<inT64>(index) * buckets_[index]; 00144 } 00145 return static_cast<double>(sum) / total_count_ + rangemin_; 00146 } 00147 00148 /********************************************************************** 00149 * STATS::sd 00150 * 00151 * Find the standard deviation of a stats class. 00152 **********************************************************************/ 00153 double STATS::sd() const { //standard deviation 00154 if (buckets_ == NULL || total_count_ <= 0) { 00155 return 0.0; 00156 } 00157 inT64 sum = 0; 00158 double sqsum = 0.0; 00159 for (int index = rangemax_ - rangemin_ - 1; index >= 0; --index) { 00160 sum += static_cast<inT64>(index) * buckets_[index]; 00161 sqsum += static_cast<double>(index) * index * buckets_[index]; 00162 } 00163 double variance = static_cast<double>(sum) / total_count_; 00164 variance = sqsum / total_count_ - variance * variance; 00165 if (variance > 0.0) 00166 return sqrt(variance); 00167 return 0.0; 00168 } 00169 00170 /********************************************************************** 00171 * STATS::ile 00172 * 00173 * Returns the fractile value such that frac fraction (in [0,1]) of samples 00174 * has a value less than the return value. 00175 **********************************************************************/ 00176 double STATS::ile(double frac) const { 00177 if (buckets_ == NULL || total_count_ == 0) { 00178 return static_cast<double>(rangemin_); 00179 } 00180 #if 0 00181 // TODO(rays) The existing code doesn't seem to be doing the right thing 00182 // with target a double but this substitute crashes the code that uses it. 00183 // Investigate and fix properly. 00184 int target = IntCastRounded(frac * total_count_); 00185 target = ClipToRange(target, 1, total_count_); 00186 #else 00187 double target = frac * total_count_; 00188 target = ClipToRange(target, 1.0, static_cast<double>(total_count_)); 00189 #endif 00190 int sum = 0; 00191 int index = 0; 00192 for (index = 0; index < rangemax_ - rangemin_ && sum < target; 00193 sum += buckets_[index++]); 00194 if (index > 0) { 00195 ASSERT_HOST(buckets_[index - 1] > 0); 00196 return rangemin_ + index - 00197 static_cast<double>(sum - target) / buckets_[index - 1]; 00198 } else { 00199 return static_cast<double>(rangemin_); 00200 } 00201 } 00202 00203 /********************************************************************** 00204 * STATS::min_bucket 00205 * 00206 * Find REAL minimum bucket - ile(0.0) isnt necessarily correct 00207 **********************************************************************/ 00208 inT32 STATS::min_bucket() const { // Find min 00209 if (buckets_ == NULL || total_count_ == 0) { 00210 return rangemin_; 00211 } 00212 inT32 min = 0; 00213 for (min = 0; (min < rangemax_ - rangemin_) && (buckets_[min] == 0); min++); 00214 return rangemin_ + min; 00215 } 00216 00217 00218 /********************************************************************** 00219 * STATS::max_bucket 00220 * 00221 * Find REAL maximum bucket - ile(1.0) isnt necessarily correct 00222 **********************************************************************/ 00223 00224 inT32 STATS::max_bucket() const { // Find max 00225 if (buckets_ == NULL || total_count_ == 0) { 00226 return rangemin_; 00227 } 00228 inT32 max; 00229 for (max = rangemax_ - rangemin_ - 1; max > 0 && buckets_[max] == 0; max--); 00230 return rangemin_ + max; 00231 } 00232 00233 /********************************************************************** 00234 * STATS::median 00235 * 00236 * Finds a more useful estimate of median than ile(0.5). 00237 * 00238 * Overcomes a problem with ile() - if the samples are, for example, 00239 * 6,6,13,14 ile(0.5) return 7.0 - when a more useful value would be midway 00240 * between 6 and 13 = 9.5 00241 **********************************************************************/ 00242 double STATS::median() const { //get median 00243 if (buckets_ == NULL) { 00244 return static_cast<double>(rangemin_); 00245 } 00246 double median = ile(0.5); 00247 int median_pile = static_cast<int>(floor(median)); 00248 if ((total_count_ > 1) && (pile_count(median_pile) == 0)) { 00249 inT32 min_pile; 00250 inT32 max_pile; 00251 /* Find preceeding non zero pile */ 00252 for (min_pile = median_pile; pile_count(min_pile) == 0; min_pile--); 00253 /* Find following non zero pile */ 00254 for (max_pile = median_pile; pile_count(max_pile) == 0; max_pile++); 00255 median = (min_pile + max_pile) / 2.0; 00256 } 00257 return median; 00258 } 00259 00260 /********************************************************************** 00261 * STATS::local_min 00262 * 00263 * Return TRUE if this point is a local min. 00264 **********************************************************************/ 00265 bool STATS::local_min(inT32 x) const { 00266 if (buckets_ == NULL) { 00267 return false; 00268 } 00269 x = ClipToRange(x, rangemin_, rangemax_ - 1) - rangemin_; 00270 if (buckets_[x] == 0) 00271 return true; 00272 inT32 index; // table index 00273 for (index = x - 1; index >= 0 && buckets_[index] == buckets_[x]; --index); 00274 if (index >= 0 && buckets_[index] < buckets_[x]) 00275 return false; 00276 for (index = x + 1; index < rangemax_ - rangemin_ && 00277 buckets_[index] == buckets_[x]; ++index); 00278 if (index < rangemax_ - rangemin_ && buckets_[index] < buckets_[x]) 00279 return false; 00280 else 00281 return true; 00282 } 00283 00284 /********************************************************************** 00285 * STATS::smooth 00286 * 00287 * Apply a triangular smoothing filter to the stats. 00288 * This makes the modes a bit more useful. 00289 * The factor gives the height of the triangle, i.e. the weight of the 00290 * centre. 00291 **********************************************************************/ 00292 void STATS::smooth(inT32 factor) { 00293 if (buckets_ == NULL || factor < 2) { 00294 return; 00295 } 00296 STATS result(rangemin_, rangemax_); 00297 int entrycount = rangemax_ - rangemin_; 00298 for (int entry = 0; entry < entrycount; entry++) { 00299 //centre weight 00300 int count = buckets_[entry] * factor; 00301 for (int offset = 1; offset < factor; offset++) { 00302 if (entry - offset >= 0) 00303 count += buckets_[entry - offset] * (factor - offset); 00304 if (entry + offset < entrycount) 00305 count += buckets_[entry + offset] * (factor - offset); 00306 } 00307 result.add(entry + rangemin_, count); 00308 } 00309 total_count_ = result.total_count_; 00310 memcpy(buckets_, result.buckets_, entrycount * sizeof(buckets_[0])); 00311 } 00312 00313 /********************************************************************** 00314 * STATS::cluster 00315 * 00316 * Cluster the samples into max_cluster clusters. 00317 * Each call runs one iteration. The array of clusters must be 00318 * max_clusters+1 in size as cluster 0 is used to indicate which samples 00319 * have been used. 00320 * The return value is the current number of clusters. 00321 **********************************************************************/ 00322 00323 inT32 STATS::cluster(float lower, // thresholds 00324 float upper, 00325 float multiple, // distance threshold 00326 inT32 max_clusters, // max no to make 00327 STATS *clusters) { // array of clusters 00328 BOOL8 new_cluster; // added one 00329 float *centres; // cluster centres 00330 inT32 entry; // bucket index 00331 inT32 cluster; // cluster index 00332 inT32 best_cluster; // one to assign to 00333 inT32 new_centre = 0; // residual mode 00334 inT32 new_mode; // pile count of new_centre 00335 inT32 count; // pile to place 00336 float dist; // from cluster 00337 float min_dist; // from best_cluster 00338 inT32 cluster_count; // no of clusters 00339 00340 if (buckets_ == NULL || max_clusters < 1) 00341 return 0; 00342 centres = new float[max_clusters + 1]; 00343 for (cluster_count = 1; cluster_count <= max_clusters 00344 && clusters[cluster_count].buckets_ != NULL 00345 && clusters[cluster_count].total_count_ > 0; 00346 cluster_count++) { 00347 centres[cluster_count] = 00348 static_cast<float>(clusters[cluster_count].ile(0.5)); 00349 new_centre = clusters[cluster_count].mode(); 00350 for (entry = new_centre - 1; centres[cluster_count] - entry < lower 00351 && entry >= rangemin_ 00352 && pile_count(entry) <= pile_count(entry + 1); 00353 entry--) { 00354 count = pile_count(entry) - clusters[0].pile_count(entry); 00355 if (count > 0) { 00356 clusters[cluster_count].add(entry, count); 00357 clusters[0].add (entry, count); 00358 } 00359 } 00360 for (entry = new_centre + 1; entry - centres[cluster_count] < lower 00361 && entry < rangemax_ 00362 && pile_count(entry) <= pile_count(entry - 1); 00363 entry++) { 00364 count = pile_count(entry) - clusters[0].pile_count(entry); 00365 if (count > 0) { 00366 clusters[cluster_count].add(entry, count); 00367 clusters[0].add(entry, count); 00368 } 00369 } 00370 } 00371 cluster_count--; 00372 00373 if (cluster_count == 0) { 00374 clusters[0].set_range(rangemin_, rangemax_); 00375 } 00376 do { 00377 new_cluster = FALSE; 00378 new_mode = 0; 00379 for (entry = 0; entry < rangemax_ - rangemin_; entry++) { 00380 count = buckets_[entry] - clusters[0].buckets_[entry]; 00381 //remaining pile 00382 if (count > 0) { //any to handle 00383 min_dist = static_cast<float>(MAX_INT32); 00384 best_cluster = 0; 00385 for (cluster = 1; cluster <= cluster_count; cluster++) { 00386 dist = entry + rangemin_ - centres[cluster]; 00387 //find distance 00388 if (dist < 0) 00389 dist = -dist; 00390 if (dist < min_dist) { 00391 min_dist = dist; //find least 00392 best_cluster = cluster; 00393 } 00394 } 00395 if (min_dist > upper //far enough for new 00396 && (best_cluster == 0 00397 || entry + rangemin_ > centres[best_cluster] * multiple 00398 || entry + rangemin_ < centres[best_cluster] / multiple)) { 00399 if (count > new_mode) { 00400 new_mode = count; 00401 new_centre = entry + rangemin_; 00402 } 00403 } 00404 } 00405 } 00406 // need new and room 00407 if (new_mode > 0 && cluster_count < max_clusters) { 00408 cluster_count++; 00409 new_cluster = TRUE; 00410 if (!clusters[cluster_count].set_range(rangemin_, rangemax_)) 00411 return 0; 00412 centres[cluster_count] = static_cast<float>(new_centre); 00413 clusters[cluster_count].add(new_centre, new_mode); 00414 clusters[0].add(new_centre, new_mode); 00415 for (entry = new_centre - 1; centres[cluster_count] - entry < lower 00416 && entry >= rangemin_ 00417 && pile_count (entry) <= pile_count(entry + 1); entry--) { 00418 count = pile_count(entry) - clusters[0].pile_count(entry); 00419 if (count > 0) { 00420 clusters[cluster_count].add(entry, count); 00421 clusters[0].add(entry, count); 00422 } 00423 } 00424 for (entry = new_centre + 1; entry - centres[cluster_count] < lower 00425 && entry < rangemax_ 00426 && pile_count (entry) <= pile_count(entry - 1); entry++) { 00427 count = pile_count(entry) - clusters[0].pile_count(entry); 00428 if (count > 0) { 00429 clusters[cluster_count].add(entry, count); 00430 clusters[0].add (entry, count); 00431 } 00432 } 00433 centres[cluster_count] = 00434 static_cast<float>(clusters[cluster_count].ile(0.5)); 00435 } 00436 } while (new_cluster && cluster_count < max_clusters); 00437 delete [] centres; 00438 return cluster_count; 00439 } 00440 00441 /********************************************************************** 00442 * STATS::print 00443 * 00444 * Prints a summary and table of the histogram. 00445 **********************************************************************/ 00446 void STATS::print() const { 00447 if (buckets_ == NULL) { 00448 return; 00449 } 00450 inT32 min = min_bucket() - rangemin_; 00451 inT32 max = max_bucket() - rangemin_; 00452 00453 int num_printed = 0; 00454 for (int index = min; index <= max; index++) { 00455 if (buckets_[index] != 0) { 00456 tprintf("%4d:%-3d ", rangemin_ + index, buckets_[index]); 00457 if (++num_printed % 8 == 0) 00458 tprintf ("\n"); 00459 } 00460 } 00461 tprintf ("\n"); 00462 print_summary(); 00463 } 00464 00465 00466 00467 /********************************************************************** 00468 * STATS::print_summary 00469 * 00470 * Print a summary of the stats. 00471 **********************************************************************/ 00472 void STATS::print_summary() const { 00473 if (buckets_ == NULL) { 00474 return; 00475 } 00476 inT32 min = min_bucket(); 00477 inT32 max = max_bucket(); 00478 tprintf("Total count=%d\n", total_count_); 00479 tprintf("Min=%.2f Really=%d\n", ile(0.0), min); 00480 tprintf("Lower quartile=%.2f\n", ile(0.25)); 00481 tprintf("Median=%.2f, ile(0.5)=%.2f\n", median(), ile(0.5)); 00482 tprintf("Upper quartile=%.2f\n", ile(0.75)); 00483 tprintf("Max=%.2f Really=%d\n", ile(1.0), max); 00484 tprintf("Range=%d\n", max + 1 - min); 00485 tprintf("Mean= %.2f\n", mean()); 00486 tprintf("SD= %.2f\n", sd()); 00487 } 00488 00489 00490 /********************************************************************** 00491 * STATS::plot 00492 * 00493 * Draw a histogram of the stats table. 00494 **********************************************************************/ 00495 00496 #ifndef GRAPHICS_DISABLED 00497 void STATS::plot(ScrollView* window, // to draw in 00498 float xorigin, // bottom left 00499 float yorigin, 00500 float xscale, // one x unit 00501 float yscale, // one y unit 00502 ScrollView::Color colour) const { // colour to draw in 00503 if (buckets_ == NULL) { 00504 return; 00505 } 00506 window->Pen(colour); 00507 00508 for (int index = 0; index < rangemax_ - rangemin_; index++) { 00509 window->Rectangle( xorigin + xscale * index, yorigin, 00510 xorigin + xscale * (index + 1), 00511 yorigin + yscale * buckets_[index]); 00512 } 00513 } 00514 #endif 00515 00516 00517 /********************************************************************** 00518 * STATS::plotline 00519 * 00520 * Draw a histogram of the stats table. (Line only) 00521 **********************************************************************/ 00522 00523 #ifndef GRAPHICS_DISABLED 00524 void STATS::plotline(ScrollView* window, // to draw in 00525 float xorigin, // bottom left 00526 float yorigin, 00527 float xscale, // one x unit 00528 float yscale, // one y unit 00529 ScrollView::Color colour) const { // colour to draw in 00530 if (buckets_ == NULL) { 00531 return; 00532 } 00533 window->Pen(colour); 00534 window->SetCursor(xorigin, yorigin + yscale * buckets_[0]); 00535 for (int index = 0; index < rangemax_ - rangemin_; index++) { 00536 window->DrawTo(xorigin + xscale * index, 00537 yorigin + yscale * buckets_[index]); 00538 } 00539 } 00540 #endif 00541 00542 00543 /********************************************************************** 00544 * choose_nth_item 00545 * 00546 * Returns the index of what would b the nth item in the array 00547 * if the members were sorted, without actually sorting. 00548 **********************************************************************/ 00549 00550 inT32 choose_nth_item(inT32 index, float *array, inT32 count) { 00551 inT32 next_sample; // next one to do 00552 inT32 next_lesser; // space for new 00553 inT32 prev_greater; // last one saved 00554 inT32 equal_count; // no of equal ones 00555 float pivot; // proposed median 00556 float sample; // current sample 00557 00558 if (count <= 1) 00559 return 0; 00560 if (count == 2) { 00561 if (array[0] < array[1]) { 00562 return index >= 1 ? 1 : 0; 00563 } 00564 else { 00565 return index >= 1 ? 0 : 1; 00566 } 00567 } 00568 else { 00569 if (index < 0) 00570 index = 0; // ensure legal 00571 else if (index >= count) 00572 index = count - 1; 00573 equal_count = (inT32) (rand() % count); 00574 pivot = array[equal_count]; 00575 // fill gap 00576 array[equal_count] = array[0]; 00577 next_lesser = 0; 00578 prev_greater = count; 00579 equal_count = 1; 00580 for (next_sample = 1; next_sample < prev_greater;) { 00581 sample = array[next_sample]; 00582 if (sample < pivot) { 00583 // shuffle 00584 array[next_lesser++] = sample; 00585 next_sample++; 00586 } 00587 else if (sample > pivot) { 00588 prev_greater--; 00589 // juggle 00590 array[next_sample] = array[prev_greater]; 00591 array[prev_greater] = sample; 00592 } 00593 else { 00594 equal_count++; 00595 next_sample++; 00596 } 00597 } 00598 for (next_sample = next_lesser; next_sample < prev_greater;) 00599 array[next_sample++] = pivot; 00600 if (index < next_lesser) 00601 return choose_nth_item (index, array, next_lesser); 00602 else if (index < prev_greater) 00603 return next_lesser; // in equal bracket 00604 else 00605 return choose_nth_item (index - prev_greater, 00606 array + prev_greater, 00607 count - prev_greater) + prev_greater; 00608 } 00609 } 00610 00611 /********************************************************************** 00612 * choose_nth_item 00613 * 00614 * Returns the index of what would be the nth item in the array 00615 * if the members were sorted, without actually sorting. 00616 **********************************************************************/ 00617 inT32 choose_nth_item(inT32 index, void *array, inT32 count, size_t size, 00618 int (*compar)(const void*, const void*)) { 00619 int result; // of compar 00620 inT32 next_sample; // next one to do 00621 inT32 next_lesser; // space for new 00622 inT32 prev_greater; // last one saved 00623 inT32 equal_count; // no of equal ones 00624 inT32 pivot; // proposed median 00625 00626 if (count <= 1) 00627 return 0; 00628 if (count == 2) { 00629 if (compar (array, (char *) array + size) < 0) { 00630 return index >= 1 ? 1 : 0; 00631 } 00632 else { 00633 return index >= 1 ? 0 : 1; 00634 } 00635 } 00636 if (index < 0) 00637 index = 0; // ensure legal 00638 else if (index >= count) 00639 index = count - 1; 00640 pivot = (inT32) (rand () % count); 00641 swap_entries (array, size, pivot, 0); 00642 next_lesser = 0; 00643 prev_greater = count; 00644 equal_count = 1; 00645 for (next_sample = 1; next_sample < prev_greater;) { 00646 result = 00647 compar ((char *) array + size * next_sample, 00648 (char *) array + size * next_lesser); 00649 if (result < 0) { 00650 swap_entries (array, size, next_lesser++, next_sample++); 00651 // shuffle 00652 } 00653 else if (result > 0) { 00654 prev_greater--; 00655 swap_entries(array, size, prev_greater, next_sample); 00656 } 00657 else { 00658 equal_count++; 00659 next_sample++; 00660 } 00661 } 00662 if (index < next_lesser) 00663 return choose_nth_item (index, array, next_lesser, size, compar); 00664 else if (index < prev_greater) 00665 return next_lesser; // in equal bracket 00666 else 00667 return choose_nth_item (index - prev_greater, 00668 (char *) array + size * prev_greater, 00669 count - prev_greater, size, 00670 compar) + prev_greater; 00671 } 00672 00673 /********************************************************************** 00674 * swap_entries 00675 * 00676 * Swap 2 entries of arbitrary size in-place in a table. 00677 **********************************************************************/ 00678 void swap_entries(void *array, // array of entries 00679 size_t size, // size of entry 00680 inT32 index1, // entries to swap 00681 inT32 index2) { 00682 char tmp; 00683 char *ptr1; // to entries 00684 char *ptr2; 00685 size_t count; // of bytes 00686 00687 ptr1 = reinterpret_cast<char*>(array) + index1 * size; 00688 ptr2 = reinterpret_cast<char*>(array) + index2 * size; 00689 for (count = 0; count < size; count++) { 00690 tmp = *ptr1; 00691 *ptr1++ = *ptr2; 00692 *ptr2++ = tmp; // tedious! 00693 } 00694 }