Tesseract
3.02
|
00001 /****************************************************************************** 00002 ** Filename: intfx.c 00003 ** Purpose: Integer character normalization & feature extraction 00004 ** Author: Robert Moss 00005 ** History: Tue May 21 15:51:57 MDT 1991, RWM, Created. 00006 ** 00007 ** (c) Copyright Hewlett-Packard Company, 1988. 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 ******************************************************************************/ 00021 #include "intfx.h" 00022 #include "intmatcher.h" 00023 #include "const.h" 00024 #include "helpers.h" 00025 #include "ccutil.h" 00026 #include "statistc.h" 00027 #include "trainingsample.h" 00028 #ifdef __UNIX__ 00029 #endif 00030 00031 using tesseract::TrainingSample; 00032 00036 int SaveFeature(); 00037 uinT8 BinaryAnglePlusPi(inT32 Y, inT32 X); 00038 uinT8 MySqrt2(); 00039 void ClipRadius(); 00040 00041 INT_VAR(classify_radius_gyr_min_man, 255, 00042 "Minimum Radius of Gyration Mantissa 0-255: "); 00043 00044 INT_VAR(classify_radius_gyr_min_exp, 0, 00045 "Minimum Radius of Gyration Exponent 0-255: "); 00046 00047 INT_VAR(classify_radius_gyr_max_man, 158, 00048 "Maximum Radius of Gyration Mantissa 0-255: "); 00049 00050 INT_VAR(classify_radius_gyr_max_exp, 8, 00051 "Maximum Radius of Gyration Exponent 0-255: "); 00052 00056 #define ATAN_TABLE_SIZE 64 00057 00058 // Look up table for arc tangent containing: 00059 // atan(0.0) ... atan(ATAN_TABLE_SIZE - 1 / ATAN_TABLE_SIZE) 00060 // The entries are in binary degrees where a full circle is 256 binary degrees. 00061 static uinT8 AtanTable[ATAN_TABLE_SIZE]; 00062 // Look up table for cos and sin to turn the intfx feature angle to a vector. 00063 // Also protected by atan_table_mutex. 00064 static float cos_table[INT_CHAR_NORM_RANGE]; 00065 static float sin_table[INT_CHAR_NORM_RANGE]; 00066 // Guards write access to AtanTable so we dont create it more than once. 00067 tesseract::CCUtilMutex atan_table_mutex; 00068 00069 00073 /*---------------------------------------------------------------------------*/ 00074 void InitIntegerFX() { 00075 static bool atan_table_init = false; 00076 atan_table_mutex.Lock(); 00077 if (!atan_table_init) { 00078 for (int i = 0; i < ATAN_TABLE_SIZE; i++) { 00079 AtanTable[i] = 00080 (uinT8) (atan ((i / (float) ATAN_TABLE_SIZE)) * 128.0 / PI + 0.5); 00081 } 00082 for (int i = 0; i < INT_CHAR_NORM_RANGE; ++i) { 00083 cos_table[i] = cos(i * 2 * PI / INT_CHAR_NORM_RANGE + PI); 00084 sin_table[i] = sin(i * 2 * PI / INT_CHAR_NORM_RANGE + PI); 00085 } 00086 atan_table_init = true; 00087 } 00088 atan_table_mutex.Unlock(); 00089 } 00090 00091 // Returns a vector representing the direction of a feature with the given 00092 // theta direction in an INT_FEATURE_STRUCT. 00093 FCOORD FeatureDirection(uinT8 theta) { 00094 return FCOORD(cos_table[theta], sin_table[theta]); 00095 } 00096 00097 TrainingSample* GetIntFeatures(tesseract::NormalizationMode mode, 00098 TBLOB *blob, const DENORM& denorm) { 00099 INT_FEATURE_ARRAY blfeatures; 00100 INT_FEATURE_ARRAY cnfeatures; 00101 INT_FX_RESULT_STRUCT fx_info; 00102 ExtractIntFeat(blob, denorm, blfeatures, cnfeatures, &fx_info, NULL); 00103 TrainingSample* sample = NULL; 00104 if (mode == tesseract::NM_CHAR_ANISOTROPIC) { 00105 int num_features = fx_info.NumCN; 00106 if (num_features > 0) { 00107 sample = TrainingSample::CopyFromFeatures(fx_info, cnfeatures, 00108 num_features); 00109 } 00110 } else if (mode == tesseract::NM_BASELINE) { 00111 int num_features = fx_info.NumBL; 00112 if (num_features > 0) { 00113 sample = TrainingSample::CopyFromFeatures(fx_info, blfeatures, 00114 num_features); 00115 } 00116 } else { 00117 ASSERT_HOST(!"Unsupported normalization mode!"); 00118 } 00119 return sample; 00120 } 00121 00122 00123 /*--------------------------------------------------------------------------*/ 00124 // Extract a set of standard-sized features from Blobs and write them out in 00125 // two formats: baseline normalized and character normalized. 00126 // 00127 // We presume the Blobs are already scaled so that x-height=128 units 00128 // 00129 // Standard Features: 00130 // We take all outline segments longer than 7 units and chop them into 00131 // standard-sized segments of approximately 13 = (64 / 5) units. 00132 // When writing these features out, we output their center and angle as 00133 // measured counterclockwise from the vector <-1, 0> 00134 // 00135 // Baseline Normalized Output: 00136 // We center the grapheme by aligning the x-coordinate of its centroid with 00137 // x=0 and subtracting 128 from the y-coordinate. 00138 // 00139 // Character Normalized Output: 00140 // We align the grapheme's centroid at the origin and scale it asymmetrically 00141 // in x and y so that the result is vaguely square. 00142 // 00143 int ExtractIntFeat(TBLOB *Blob, 00144 const DENORM& denorm, 00145 INT_FEATURE_ARRAY BLFeat, 00146 INT_FEATURE_ARRAY CNFeat, 00147 INT_FX_RESULT_STRUCT* Results, 00148 inT32 *FeatureOutlineArray) { 00149 00150 TESSLINE *OutLine; 00151 EDGEPT *Loop, *LoopStart, *Segment; 00152 inT16 LastX, LastY, Xmean, Ymean; 00153 inT32 NormX, NormY, DeltaX, DeltaY; 00154 inT32 Xsum, Ysum; 00155 uinT32 Ix, Iy, LengthSum; 00156 uinT16 n; 00157 // n - the number of features to extract from a given outline segment. 00158 // We extract features from every outline segment longer than ~6 units. 00159 // We chop these long segments into standard-sized features approximately 00160 // 13 (= 64 / 5) units in length. 00161 uinT8 Theta; 00162 uinT16 NumBLFeatures, NumCNFeatures; 00163 uinT8 RxInv, RyInv; /* x.xxxxxxx * 2^Exp */ 00164 uinT8 RxExp, RyExp; 00165 /* sxxxxxxxxxxxxxxxxxxxxxxx.xxxxxxxx */ 00166 register inT32 pfX, pfY, dX, dY; 00167 uinT16 Length; 00168 register int i; 00169 00170 Results->Length = 0; 00171 Results->Xmean = 0; 00172 Results->Ymean = 0; 00173 Results->Rx = 0; 00174 Results->Ry = 0; 00175 Results->NumBL = 0; 00176 Results->NumCN = 0; 00177 Results->YBottom = MAX_UINT8; 00178 Results->YTop = 0; 00179 00180 // Calculate the centroid (Xmean, Ymean) for the blob. 00181 // We use centroid (instead of center of bounding box or center of smallest 00182 // enclosing circle) so the algorithm will not be too greatly influenced by 00183 // small amounts of information at the edge of a character's bounding box. 00184 NumBLFeatures = 0; 00185 NumCNFeatures = 0; 00186 OutLine = Blob->outlines; 00187 Xsum = 0; 00188 Ysum = 0; 00189 LengthSum = 0; 00190 while (OutLine != NULL) { 00191 LoopStart = OutLine->loop; 00192 Loop = LoopStart; 00193 LastX = Loop->pos.x; 00194 LastY = Loop->pos.y; 00195 /* Check for bad loops */ 00196 if ((Loop == NULL) || (Loop->next == NULL) || (Loop->next == LoopStart)) 00197 return FALSE; 00198 do { 00199 Segment = Loop; 00200 Loop = Loop->next; 00201 NormX = Loop->pos.x; 00202 NormY = Loop->pos.y; 00203 00204 n = 1; 00205 if (!Segment->IsHidden()) { 00206 DeltaX = NormX - LastX; 00207 DeltaY = NormY - LastY; 00208 Length = MySqrt(DeltaX, DeltaY); 00209 n = ((Length << 2) + Length + 32) >> 6; 00210 if (n != 0) { 00211 Xsum += ((LastX << 1) + DeltaX) * (int) Length; 00212 Ysum += ((LastY << 1) + DeltaY) * (int) Length; 00213 LengthSum += Length; 00214 } 00215 } 00216 if (n != 0) { /* Throw away a point that is too close */ 00217 LastX = NormX; 00218 LastY = NormY; 00219 } 00220 } 00221 while (Loop != LoopStart); 00222 OutLine = OutLine->next; 00223 } 00224 if (LengthSum == 0) 00225 return FALSE; 00226 Xmean = (Xsum / (inT32) LengthSum) >> 1; 00227 Ymean = (Ysum / (inT32) LengthSum) >> 1; 00228 00229 Results->Length = LengthSum; 00230 Results->Xmean = Xmean; 00231 Results->Ymean = Ymean; 00232 00233 // Extract Baseline normalized features, 00234 // and find 2nd moments (Ix, Iy) & radius of gyration (Rx, Ry). 00235 // 00236 // Ix = Sum y^2 dA, where: 00237 // Ix: the second moment of area about the axis x 00238 // dA = 1 for our standard-sized piece of outline 00239 // y: the perependicular distance to the x axis 00240 // Rx = sqrt(Ix / A) 00241 // Note: 1 <= Rx <= height of blob / 2 00242 // Ry = sqrt(Iy / A) 00243 // Note: 1 <= Ry <= width of blob / 2 00244 Ix = 0; 00245 Iy = 0; 00246 NumBLFeatures = 0; 00247 OutLine = Blob->outlines; 00248 int min_x = 0; 00249 int max_x = 0; 00250 while (OutLine != NULL) { 00251 LoopStart = OutLine->loop; 00252 Loop = LoopStart; 00253 LastX = Loop->pos.x - Xmean; 00254 LastY = Loop->pos.y; 00255 /* Check for bad loops */ 00256 if ((Loop == NULL) || (Loop->next == NULL) || (Loop->next == LoopStart)) 00257 return FALSE; 00258 do { 00259 Segment = Loop; 00260 Loop = Loop->next; 00261 NormX = Loop->pos.x - Xmean; 00262 NormY = Loop->pos.y; 00263 if (NormY < Results->YBottom) 00264 Results->YBottom = ClipToRange(NormY, 0, MAX_UINT8); 00265 if (NormY > Results->YTop) 00266 Results->YTop = ClipToRange(NormY, 0, MAX_UINT8); 00267 UpdateRange(NormX, &min_x, &max_x); 00268 00269 n = 1; 00270 if (!Segment->IsHidden()) { 00271 DeltaX = NormX - LastX; 00272 DeltaY = NormY - LastY; 00273 Length = MySqrt(DeltaX, DeltaY); 00274 n = ((Length << 2) + Length + 32) >> 6; 00275 if (n != 0) { 00276 Theta = BinaryAnglePlusPi(DeltaY, DeltaX); 00277 dX = (DeltaX << 8) / n; 00278 dY = (DeltaY << 8) / n; 00279 pfX = (LastX << 8) + (dX >> 1); 00280 pfY = (LastY << 8) + (dY >> 1); 00281 Ix += ((pfY >> 8) - Ymean) * ((pfY >> 8) - Ymean); 00282 // TODO(eger): Hmmm... Xmean is not necessarily 0. 00283 // Figure out if we should center against Xmean for these 00284 // features, and if so fix Iy & SaveFeature(). 00285 Iy += (pfX >> 8) * (pfX >> 8); 00286 if (SaveFeature(BLFeat, 00287 NumBLFeatures, 00288 (inT16) (pfX >> 8), 00289 (inT16) ((pfY >> 8) - 128), 00290 Theta) == FALSE) 00291 return FALSE; 00292 NumBLFeatures++; 00293 for (i = 1; i < n; i++) { 00294 pfX += dX; 00295 pfY += dY; 00296 Ix += ((pfY >> 8) - Ymean) * ((pfY >> 8) - Ymean); 00297 Iy += (pfX >> 8) * (pfX >> 8); 00298 if (SaveFeature(BLFeat, 00299 NumBLFeatures, 00300 (inT16) (pfX >> 8), 00301 (inT16) ((pfY >> 8) - 128), 00302 Theta) == FALSE) 00303 return FALSE; 00304 NumBLFeatures++; 00305 } 00306 } 00307 } 00308 if (n != 0) { /* Throw away a point that is too close */ 00309 LastX = NormX; 00310 LastY = NormY; 00311 } 00312 } 00313 while (Loop != LoopStart); 00314 OutLine = OutLine->next; 00315 } 00316 Results->Width = max_x - min_x; 00317 if (Ix == 0) 00318 Ix = 1; 00319 if (Iy == 0) 00320 Iy = 1; 00321 RxInv = MySqrt2 (NumBLFeatures, Ix, &RxExp); 00322 RyInv = MySqrt2 (NumBLFeatures, Iy, &RyExp); 00323 ClipRadius(&RxInv, &RxExp, &RyInv, &RyExp); 00324 00325 Results->Rx = (inT16) (51.2 / (double) RxInv * pow (2.0, (double) RxExp)); 00326 Results->Ry = (inT16) (51.2 / (double) RyInv * pow (2.0, (double) RyExp)); 00327 if (Results->Ry == 0) { 00328 /* 00329 This would result in features having 'nan' values. 00330 Since the expression is always > 0, assign a value of 1. 00331 */ 00332 Results->Ry = 1; 00333 } 00334 Results->NumBL = NumBLFeatures; 00335 00336 // Extract character normalized features 00337 // 00338 // Rescale the co-ordinates to "equalize" distribution in X and Y, making 00339 // all of the following unichars be sized to look similar: , ' 1 i 00340 // 00341 // We calculate co-ordinates relative to the centroid, and then scale them 00342 // as follows (accomplishing a scale of up to 102.4 / dimension): 00343 // y *= 51.2 / Rx [ y scaled by 0.0 ... 102.4 / height of glyph ] 00344 // x *= 51.2 / Ry [ x scaled by 0.0 ... 102.4 / width of glyph ] 00345 // Although tempting to think so, this does not guarantee that our range 00346 // is within [-102.4...102.4] x [-102.4...102.4] because (Xmean, Ymean) 00347 // is the centroid, not the center of the bounding box. Instead, we can 00348 // only bound the result to [-204 ... 204] x [-204 ... 204] 00349 // 00350 NumCNFeatures = 0; 00351 OutLine = Blob->outlines; 00352 int OutLineIndex = -1; 00353 while (OutLine != NULL) { 00354 LoopStart = OutLine->loop; 00355 Loop = LoopStart; 00356 LastX = (Loop->pos.x - Xmean) * RyInv; 00357 LastY = (Loop->pos.y - Ymean) * RxInv; 00358 LastX >>= (inT8) RyExp; 00359 LastY >>= (inT8) RxExp; 00360 OutLineIndex++; 00361 00362 /* Check for bad loops */ 00363 if ((Loop == NULL) || (Loop->next == NULL) || (Loop->next == LoopStart)) 00364 return FALSE; 00365 do { 00366 Segment = Loop; 00367 Loop = Loop->next; 00368 NormX = (Loop->pos.x - Xmean) * RyInv; 00369 NormY = (Loop->pos.y - Ymean) * RxInv; 00370 NormX >>= (inT8) RyExp; 00371 NormY >>= (inT8) RxExp; 00372 00373 n = 1; 00374 if (!Segment->IsHidden()) { 00375 DeltaX = NormX - LastX; 00376 DeltaY = NormY - LastY; 00377 Length = MySqrt(DeltaX, DeltaY); 00378 n = ((Length << 2) + Length + 32) >> 6; 00379 if (n != 0) { 00380 Theta = BinaryAnglePlusPi(DeltaY, DeltaX); 00381 dX = (DeltaX << 8) / n; 00382 dY = (DeltaY << 8) / n; 00383 pfX = (LastX << 8) + (dX >> 1); 00384 pfY = (LastY << 8) + (dY >> 1); 00385 if (SaveFeature(CNFeat, 00386 NumCNFeatures, 00387 (inT16) (pfX >> 8), 00388 (inT16) (pfY >> 8), 00389 Theta) == FALSE) 00390 return FALSE; 00391 if (FeatureOutlineArray) { 00392 FeatureOutlineArray[NumCNFeatures] = OutLineIndex; 00393 } 00394 NumCNFeatures++; 00395 for (i = 1; i < n; i++) { 00396 pfX += dX; 00397 pfY += dY; 00398 if (SaveFeature(CNFeat, 00399 NumCNFeatures, 00400 (inT16) (pfX >> 8), 00401 (inT16) (pfY >> 8), 00402 Theta) == FALSE) 00403 return FALSE; 00404 if (FeatureOutlineArray) { 00405 FeatureOutlineArray[NumCNFeatures] = OutLineIndex; 00406 } 00407 NumCNFeatures++; 00408 } 00409 } 00410 } 00411 if (n != 0) { /* Throw away a point that is too close */ 00412 LastX = NormX; 00413 LastY = NormY; 00414 } 00415 } 00416 while (Loop != LoopStart); 00417 OutLine = OutLine->next; 00418 } 00419 00420 Results->NumCN = NumCNFeatures; 00421 return TRUE; 00422 } 00423 00424 00425 /*--------------------------------------------------------------------------*/ 00426 // Return the "binary angle" [0..255] 00427 // made by vector <X, Y> as measured counterclockwise from <-1, 0> 00428 // The order of the arguments follows the convention of atan2(3) 00429 uinT8 BinaryAnglePlusPi(inT32 Y, inT32 X) { 00430 inT16 Angle, Atan; 00431 uinT16 Ratio; 00432 uinT32 AbsX, AbsY; 00433 00434 assert ((X != 0) || (Y != 0)); 00435 if (X < 0) 00436 AbsX = -X; 00437 else 00438 AbsX = X; 00439 if (Y < 0) 00440 AbsY = -Y; 00441 else 00442 AbsY = Y; 00443 if (AbsX > AbsY) 00444 Ratio = AbsY * ATAN_TABLE_SIZE / AbsX; 00445 else 00446 Ratio = AbsX * ATAN_TABLE_SIZE / AbsY; 00447 if (Ratio >= ATAN_TABLE_SIZE) 00448 Ratio = ATAN_TABLE_SIZE - 1; 00449 Atan = AtanTable[Ratio]; 00450 if (X >= 0) 00451 if (Y >= 0) 00452 if (AbsX > AbsY) 00453 Angle = Atan; 00454 else 00455 Angle = 64 - Atan; 00456 else if (AbsX > AbsY) 00457 Angle = 256 - Atan; 00458 else 00459 Angle = 192 + Atan; 00460 else if (Y >= 0) 00461 if (AbsX > AbsY) 00462 Angle = 128 - Atan; 00463 else 00464 Angle = 64 + Atan; 00465 else if (AbsX > AbsY) 00466 Angle = 128 + Atan; 00467 else 00468 Angle = 192 - Atan; 00469 00470 /* reverse angles to match old feature extractor: Angle += PI */ 00471 Angle += 128; 00472 Angle &= 255; 00473 return (uinT8) Angle; 00474 } 00475 00476 00477 /*--------------------------------------------------------------------------*/ 00478 int SaveFeature(INT_FEATURE_ARRAY FeatureArray, 00479 uinT16 FeatureNum, 00480 inT16 X, 00481 inT16 Y, 00482 uinT8 Theta) { 00483 INT_FEATURE Feature; 00484 00485 if (FeatureNum >= MAX_NUM_INT_FEATURES) 00486 return FALSE; 00487 00488 Feature = &(FeatureArray[FeatureNum]); 00489 00490 X = X + 128; 00491 Y = Y + 128; 00492 00493 Feature->X = ClipToRange<inT16>(X, 0, 255); 00494 Feature->Y = ClipToRange<inT16>(Y, 0, 255); 00495 Feature->Theta = Theta; 00496 Feature->CP_misses = 0; 00497 00498 return TRUE; 00499 } 00500 00501 00502 /*---------------------------------------------------------------------------*/ 00503 // Return floor(sqrt(min(emm, x)^2 + min(emm, y)^2)) 00504 // where emm = EvidenceMultMask. 00505 uinT16 MySqrt(inT32 X, inT32 Y) { 00506 register uinT16 SqRoot; 00507 register uinT32 Square; 00508 register uinT16 BitLocation; 00509 register uinT32 Sum; 00510 const uinT32 EvidenceMultMask = 00511 ((1 << IntegerMatcher::kIntEvidenceTruncBits) - 1); 00512 00513 if (X < 0) 00514 X = -X; 00515 if (Y < 0) 00516 Y = -Y; 00517 00518 if (X > EvidenceMultMask) 00519 X = EvidenceMultMask; 00520 if (Y > EvidenceMultMask) 00521 Y = EvidenceMultMask; 00522 00523 Sum = X * X + Y * Y; 00524 00525 BitLocation = (EvidenceMultMask + 1) << 1; 00526 SqRoot = 0; 00527 do { 00528 Square = (SqRoot | BitLocation) * (SqRoot | BitLocation); 00529 if (Square <= Sum) 00530 SqRoot |= BitLocation; 00531 BitLocation >>= 1; 00532 } 00533 while (BitLocation); 00534 00535 return SqRoot; 00536 } 00537 00538 00539 /*--------------------------------------------------------------------------*/ 00540 // Return two integers which can be used to express the sqrt(I/N): 00541 // sqrt(I/N) = 51.2 * 2^(*Exp) / retval 00542 uinT8 MySqrt2(uinT16 N, uinT32 I, uinT8 *Exp) { 00543 register inT8 k; 00544 register uinT32 N2; 00545 register uinT8 SqRoot; 00546 register uinT16 Square; 00547 register uinT8 BitLocation; 00548 register uinT16 Ratio; 00549 00550 N2 = N * 41943; 00551 00552 k = 9; 00553 while ((N2 & 0xc0000000) == 0) { 00554 N2 <<= 2; 00555 k += 1; 00556 } 00557 00558 while ((I & 0xc0000000) == 0) { 00559 I <<= 2; 00560 k -= 1; 00561 } 00562 00563 if (((N2 & 0x80000000) == 0) && ((I & 0x80000000) == 0)) { 00564 N2 <<= 1; 00565 I <<= 1; 00566 } 00567 00568 N2 &= 0xffff0000; 00569 I >>= 14; 00570 Ratio = N2 / I; 00571 00572 BitLocation = 128; 00573 SqRoot = 0; 00574 do { 00575 Square = (SqRoot | BitLocation) * (SqRoot | BitLocation); 00576 if (Square <= Ratio) 00577 SqRoot |= BitLocation; 00578 BitLocation >>= 1; 00579 } 00580 while (BitLocation); 00581 00582 if (k < 0) { 00583 *Exp = 0; 00584 return 255; 00585 } 00586 else { 00587 *Exp = k; 00588 return SqRoot; 00589 } 00590 } 00591 00592 00593 /*-------------------------------------------------------------------------*/ 00594 void ClipRadius(uinT8 *RxInv, uinT8 *RxExp, uinT8 *RyInv, uinT8 *RyExp) { 00595 register uinT8 AM, BM, AE, BE; 00596 register uinT8 BitN, LastCarry; 00597 int RxInvLarge, RyInvSmall; 00598 00599 AM = classify_radius_gyr_min_man; 00600 AE = classify_radius_gyr_min_exp; 00601 BM = *RxInv; 00602 BE = *RxExp; 00603 LastCarry = 1; 00604 while ((AM != 0) || (BM != 0)) { 00605 if (AE > BE) { 00606 BitN = LastCarry + (AM & 1) + 1; 00607 AM >>= 1; 00608 AE--; 00609 } 00610 else if (AE < BE) { 00611 BitN = LastCarry + (!(BM & 1)); 00612 BM >>= 1; 00613 BE--; 00614 } 00615 else { /* AE == BE */ 00616 BitN = LastCarry + (AM & 1) + (!(BM & 1)); 00617 AM >>= 1; 00618 BM >>= 1; 00619 AE--; 00620 BE--; 00621 } 00622 LastCarry = (BitN & 2) > 1; 00623 BitN = BitN & 1; 00624 } 00625 BitN = LastCarry + 1; 00626 LastCarry = (BitN & 2) > 1; 00627 BitN = BitN & 1; 00628 00629 if (BitN == 1) { 00630 *RxInv = classify_radius_gyr_min_man; 00631 *RxExp = classify_radius_gyr_min_exp; 00632 } 00633 00634 AM = classify_radius_gyr_min_man; 00635 AE = classify_radius_gyr_min_exp; 00636 BM = *RyInv; 00637 BE = *RyExp; 00638 LastCarry = 1; 00639 while ((AM != 0) || (BM != 0)) { 00640 if (AE > BE) { 00641 BitN = LastCarry + (AM & 1) + 1; 00642 AM >>= 1; 00643 AE--; 00644 } 00645 else if (AE < BE) { 00646 BitN = LastCarry + (!(BM & 1)); 00647 BM >>= 1; 00648 BE--; 00649 } 00650 else { /* AE == BE */ 00651 BitN = LastCarry + (AM & 1) + (!(BM & 1)); 00652 AM >>= 1; 00653 BM >>= 1; 00654 AE--; 00655 BE--; 00656 } 00657 LastCarry = (BitN & 2) > 1; 00658 BitN = BitN & 1; 00659 } 00660 BitN = LastCarry + 1; 00661 LastCarry = (BitN & 2) > 1; 00662 BitN = BitN & 1; 00663 00664 if (BitN == 1) { 00665 *RyInv = classify_radius_gyr_min_man; 00666 *RyExp = classify_radius_gyr_min_exp; 00667 } 00668 00669 AM = classify_radius_gyr_max_man; 00670 AE = classify_radius_gyr_max_exp; 00671 BM = *RxInv; 00672 BE = *RxExp; 00673 LastCarry = 1; 00674 while ((AM != 0) || (BM != 0)) { 00675 if (AE > BE) { 00676 BitN = LastCarry + (AM & 1) + 1; 00677 AM >>= 1; 00678 AE--; 00679 } 00680 else if (AE < BE) { 00681 BitN = LastCarry + (!(BM & 1)); 00682 BM >>= 1; 00683 BE--; 00684 } 00685 else { /* AE == BE */ 00686 BitN = LastCarry + (AM & 1) + (!(BM & 1)); 00687 AM >>= 1; 00688 BM >>= 1; 00689 AE--; 00690 BE--; 00691 } 00692 LastCarry = (BitN & 2) > 1; 00693 BitN = BitN & 1; 00694 } 00695 BitN = LastCarry + 1; 00696 LastCarry = (BitN & 2) > 1; 00697 BitN = BitN & 1; 00698 00699 if (BitN == 1) 00700 RxInvLarge = 1; 00701 else 00702 RxInvLarge = 0; 00703 00704 AM = *RyInv; 00705 AE = *RyExp; 00706 BM = classify_radius_gyr_max_man; 00707 BE = classify_radius_gyr_max_exp; 00708 LastCarry = 1; 00709 while ((AM != 0) || (BM != 0)) { 00710 if (AE > BE) { 00711 BitN = LastCarry + (AM & 1) + 1; 00712 AM >>= 1; 00713 AE--; 00714 } 00715 else if (AE < BE) { 00716 BitN = LastCarry + (!(BM & 1)); 00717 BM >>= 1; 00718 BE--; 00719 } 00720 else { /* AE == BE */ 00721 BitN = LastCarry + (AM & 1) + (!(BM & 1)); 00722 AM >>= 1; 00723 BM >>= 1; 00724 AE--; 00725 BE--; 00726 } 00727 LastCarry = (BitN & 2) > 1; 00728 BitN = BitN & 1; 00729 } 00730 BitN = LastCarry + 1; 00731 LastCarry = (BitN & 2) > 1; 00732 BitN = BitN & 1; 00733 00734 if (BitN == 1) 00735 RyInvSmall = 1; 00736 else 00737 RyInvSmall = 0; 00738 00739 if (RxInvLarge && RyInvSmall) { 00740 *RyInv = classify_radius_gyr_max_man; 00741 *RyExp = classify_radius_gyr_max_exp; 00742 } 00743 00744 }