xref: /trunk/main/tools/source/generic/fract.cxx (revision 19285428922eb95f9cc429ce6a3328e433bd6af3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_tools.hxx"
24 
25 #ifndef _LIMITS_H
26 #include <limits.h>
27 #endif
28 #include <tools/debug.hxx>
29 #include <tools/fract.hxx>
30 #include <tools/stream.hxx>
31 
32 #include <tools/bigint.hxx>
33 
34 /*************************************************************************
35 |*
36 |*    GetGGT()
37 |*
38 |*    Beschreibung      Berechnet den gr��ten gemeinsamen Teiler von
39 |*                      nVal1 und nVal2
40 |*    Parameter         long nVal1, long nVal2
41 |*    Ersterstellung    DV 20.09.90
42 |*    Letzte �nderung   DV 21.12.92
43 |*
44 *************************************************************************/
45 
46 // Die Funktion GetGGT berechnet den gr��ten gemeinsamen Teiler der
47 // beiden als Parameter �bergebenen Werte nVal1 und nVal2 nach dem
48 // Algorithmus von Euklid. Hat einer der beiden Parameter den Wert 0 oder
49 // 1, so wird als Ergebnis der Wert 1 zur�ckgegeben. Da der Algorithmus
50 // nur mit positiven Zahlen arbeitet, werden die beiden Parameter
51 // entsprechend umgewandelt.
52 // Zum Algorithmus: die beiden Parameter werden solange durcheinander
53 //              geteilt, bis sie beide gleich sind oder bis bei der Division
54 //              kein Rest bleibt. Der kleinere der beiden Werte ist dann der
55 //              GGT.
56 
57 static long GetGGT( long nVal1, long nVal2 )
58 {
59     nVal1 = Abs( nVal1 );
60     nVal2 = Abs( nVal2 );
61 
62     if ( nVal1 <= 1 || nVal2 <= 1 )
63         return 1;
64 
65     while ( nVal1 != nVal2 )
66     {
67         if ( nVal1 > nVal2 )
68         {
69             nVal1 %= nVal2;
70             if ( nVal1 == 0 )
71                 return nVal2;
72         }
73         else
74         {
75             nVal2 %= nVal1;
76             if ( nVal2 == 0 )
77                 return nVal1;
78         }
79     }
80 
81     return nVal1;
82 }
83 
84 static void Reduce( BigInt &rVal1, BigInt &rVal2 )
85 {
86     BigInt nA( rVal1 );
87     BigInt nB( rVal2 );
88     nA.Abs();
89     nB.Abs();
90 
91     if ( nA.IsOne() || nB.IsOne() || nA.IsZero() || nB.IsZero() )
92         return;
93 
94     while ( nA != nB )
95     {
96         if ( nA > nB )
97         {
98             nA %= nB;
99             if ( nA.IsZero() )
100             {
101                 rVal1 /= nB;
102                 rVal2 /= nB;
103                 return;
104             }
105         }
106         else
107         {
108             nB %= nA;
109             if ( nB.IsZero() )
110             {
111                 rVal1 /= nA;
112                 rVal2 /= nA;
113                 return;
114             }
115         }
116     }
117 
118     rVal1 /= nA;
119     rVal2 /= nB;
120 }
121 
122 /*************************************************************************
123 |*
124 |*    Fraction::Fraction()
125 |*
126 |*    Beschreibung      FRACT.SDW
127 |*    Ersterstellung    WP 07.03.97
128 |*    Letzte �nderung
129 |*
130 *************************************************************************/
131 
132 Fraction::Fraction( long nN1, long nN2, long nD1, long nD2 )
133 {
134     long n;
135     int  i = 1;
136 
137     if( nN1 < 0 ) { i = -i; nN1 = -nN1; }
138     if( nN2 < 0 ) { i = -i; nN2 = -nN2; }
139     if( nD1 < 0 ) { i = -i; nD1 = -nD1; }
140     if( nD2 < 0 ) { i = -i; nD2 = -nD2; }
141 
142     n = GetGGT( nN1, nD1 ); if( n > 1 ) { nN1 /= n; nD1 /= n; }
143     n = GetGGT( nN1, nD2 ); if( n > 1 ) { nN1 /= n; nD2 /= n; }
144     n = GetGGT( nN2, nD1 ); if( n > 1 ) { nN2 /= n; nD1 /= n; }
145     n = GetGGT( nN2, nD2 ); if( n > 1 ) { nN2 /= n; nD2 /= n; }
146 
147     BigInt nN( nN1 );
148     nN *= BigInt( nN2 );
149 
150     BigInt nD( nD1 );
151     nD *= BigInt( nD2 );
152 
153     while ( nN.bIsBig || nD.bIsBig )
154     {
155         BigInt n1 = 1;
156         BigInt n2 = 2;
157 
158         nN += n1;
159         nN /= n2;
160         nD += n1;
161         nD /= n2;
162 
163         // K�rzen �ber Gr��te Gemeinsame Teiler
164         Reduce( nN, nD );
165     }
166 
167     nNumerator   = i * (long)nN;
168     nDenominator = (long)nD;
169 }
170 
171 /*************************************************************************
172 |*
173 |*    Fraction::Fraction()
174 |*
175 |*    Beschreibung      FRACT.SDW
176 |*    Ersterstellung    DV 20.09.90
177 |*    Letzte �nderung   DV 21.12.92
178 |*
179 *************************************************************************/
180 
181 // Zur Initialisierung eines Bruches wird nNum dem Z�hler und nDen dem
182 // Nenner zugewiesen. Da negative Werte des Nenners einen Bruch als
183 // ung�ltig kennzeichnen, wird bei der Eingabe eines negativen Nenners
184 // sowohl das Vorzeichen des Nenners und des Z�hlers invertiert um wieder
185 // einen g�ltigen Wert f�r den Bruch zu erhalten.
186 
187 Fraction::Fraction( long nNum, long nDen )
188 {
189     nNumerator = nNum;
190     nDenominator = nDen;
191     if ( nDenominator < 0 )
192     {
193         nDenominator = -nDenominator;
194         nNumerator   = -nNumerator;
195     }
196 
197     // K�rzen �ber Gr��te Gemeinsame Teiler
198     long n = GetGGT( nNumerator, nDenominator );
199     nNumerator   /= n;
200     nDenominator /= n;
201 }
202 
203 /*************************************************************************
204 |*
205 |*    Fraction::Fraction()
206 |*
207 |*    Beschreibung      FRACT.SDW
208 |*    Ersterstellung    DV 20.09.90
209 |*    Letzte �nderung   DV 21.12.92
210 |*
211 *************************************************************************/
212 
213 // Wenn der Wert von dVal gr��er ist als LONG_MAX, dann wird der Bruch
214 // auf den Wert ung�ltig gesetzt, ansonsten werden dVal und der Nenner
215 // solange mit 10 multipliziert, bis entweder der Z�hler oder der Nenner
216 // gr��er als LONG_MAX / 10 ist. Zum Schluss wird der so entstandene Bruch
217 // gek�rzt.
218 
219 Fraction::Fraction( double dVal )
220 {
221     long nDen = 1;
222     long nMAX = LONG_MAX / 10;
223 
224     if ( dVal > LONG_MAX || dVal < LONG_MIN )
225     {
226         nNumerator   = 0;
227         nDenominator = -1;
228         return;
229     }
230 
231     while ( Abs( (long)dVal ) < nMAX && nDen < nMAX )
232     {
233         dVal *= 10;
234         nDen *= 10;
235     }
236     nNumerator   = (long)dVal;
237     nDenominator = nDen;
238 
239     // K�rzen �ber Gr��te Gemeinsame Teiler
240     long n = GetGGT( nNumerator, nDenominator );
241     nNumerator   /= n;
242     nDenominator /= n;
243 }
244 
245 /*************************************************************************
246 |*
247 |*    Fraction::operator double()
248 |*
249 |*    Beschreibung      FRACT.SDW
250 |*    Ersterstellung    DV 20.09.90
251 |*    Letzte �nderung   DV 14.05.91
252 |*
253 *************************************************************************/
254 
255 Fraction::operator double() const
256 {
257     if ( nDenominator > 0 )
258         return (double)nNumerator / (double)nDenominator;
259     else
260         return (double)0;
261 }
262 
263 /*************************************************************************
264 |*
265 |*    Fraction::operator+=()
266 |*
267 |*    Beschreibung      FRACT.SDW
268 |*    Ersterstellung    DV 20.09.90
269 |*    Letzte �nderung   DV 21.12.92
270 |*
271 *************************************************************************/
272 
273 // Zun�chst werden die beiden Parameter auf ihre G�ltigkeit �berpr�ft.
274 // Ist einer der Parameter ung�ltig, dann ist auch des Ergebnis
275 // ung�ltig. Zur Addition werden die beiden Br�che erst durch
276 // Erweiterung mit den Nenner des jeweils anderen Bruches auf einen
277 // gemeinsamen Nenner gebracht. Anschlie�end werden die beiden Z�hler
278 // addiert und das Ergebnis gek�rzt (durch Division von Z�hler und
279 // Nenner mit nGGT). Innerhalb der Funktion wird mit dem Datentyp SLong
280 // gerechnet, um einen m�glichen �berlauf erkennen zu k�nnen. Bei
281 // einem �berlauf wird das Ergebnis auf den Wert ung�ltig gesetzt.
282 
283 Fraction& Fraction::operator += ( const Fraction& rVal )
284 {
285     if ( !rVal.IsValid() )
286     {
287         nNumerator   = 0;
288         nDenominator = -1;
289     }
290     if ( !IsValid() )
291         return *this;
292 
293     // (a/b) + (c/d) = ( (a*d) + (c*b) ) / (b*d)
294     BigInt nN( nNumerator );
295     nN *= BigInt( rVal.nDenominator );
296     BigInt nW1Temp( nDenominator );
297     nW1Temp *= BigInt( rVal.nNumerator );
298     nN += nW1Temp;
299 
300     BigInt nD( nDenominator );
301     nD *= BigInt( rVal.nDenominator );
302 
303     Reduce( nN, nD );
304 
305     if ( nN.bIsBig || nD.bIsBig )
306     {
307         nNumerator   = 0;
308         nDenominator = -1;
309     }
310     else
311     {
312         nNumerator   = (long)nN,
313         nDenominator = (long)nD;
314     }
315 
316     return *this;
317 }
318 
319 /*************************************************************************
320 |*
321 |*    Fraction::operator-=()
322 |*
323 |*    Beschreibung      FRACT.SDW
324 |*    Ersterstellung    DV 20.09.90
325 |*    Letzte �nderung   DV 21.12.92
326 |*
327 *************************************************************************/
328 
329 // Zun�chst werden die beiden Parameter auf ihre G�ltigkeit �berpr�ft.
330 // Ist einer der Parameter ung�ltig, dann ist auch des Ergebnis
331 // ung�ltig. Zur Subtraktion werden die beiden Br�che erst durch
332 // Erweiterung mit den Nenner des jeweils anderen Bruches auf einen
333 // gemeinsamen Nenner gebracht. Anschlie�end werden die beiden Z�hler
334 // subtrahiert und das Ergebnis gek�rzt (durch Division von Z�hler und
335 // Nenner mit nGGT). Innerhalb der Funktion wird mit dem Datentyp BigInt
336 // gerechnet, um einen m�glichen �berlauf erkennen zu k�nnen. Bei
337 // einem �berlauf wird das Ergebnis auf den Wert ung�ltig gesetzt.
338 
339 Fraction& Fraction::operator -= ( const Fraction& rVal )
340 {
341     if ( !rVal.IsValid() )
342     {
343         nNumerator   = 0;
344         nDenominator = -1;
345     }
346     if ( !IsValid() )
347         return *this;
348 
349     // (a/b) - (c/d) = ( (a*d) - (c*b) ) / (b*d)
350     BigInt nN( nNumerator );
351     nN *= BigInt( rVal.nDenominator );
352     BigInt nW1Temp( nDenominator );
353     nW1Temp *= BigInt( rVal.nNumerator );
354     nN -= nW1Temp;
355 
356     BigInt nD( nDenominator );
357     nD *= BigInt( rVal.nDenominator );
358 
359     Reduce( nN, nD );
360 
361     if ( nN.bIsBig || nD.bIsBig )
362     {
363         nNumerator   = 0;
364         nDenominator = -1;
365     }
366     else
367     {
368         nNumerator   = (long)nN,
369         nDenominator = (long)nD;
370     }
371 
372     return *this;
373 }
374 
375 /*************************************************************************
376 |*
377 |*    Fraction::operator*=()
378 |*
379 |*    Beschreibung      FRACT.SDW
380 |*    Ersterstellung    DV 20.09.90
381 |*    Letzte �nderung   TH 19.08.92
382 |*
383 *************************************************************************/
384 
385 // Zun�chst werden die beiden Parameter auf ihre G�ltigkeit �berpr�ft.
386 // Ist einer der Parameter ung�ltig, dann ist auch des Ergebnis
387 // ung�ltig. Zur Multiplikation werden jeweils die beiden Z�hler und
388 // Nenner miteinander multipliziert. Um �berl�ufe zu vermeiden, werden
389 // vorher jeweils der GGT zwischen dem Z�hler des einen und dem Nenner
390 // des anderen Bruches bestimmt und bei der Multiplikation Z�hler und
391 // Nenner durch die entsprechenden Werte geteilt.
392 // Innerhalb der Funktion wird mit dem Datentyp BigInt gerechnet, um
393 // einen m�glichen �berlauf erkennen zu k�nnen. Bei einem �berlauf
394 // wird das Ergebnis auf den Wert ung�ltig gesetzt.
395 
396 Fraction& Fraction::operator *= ( const Fraction& rVal )
397 {
398     if ( !rVal.IsValid() )
399     {
400         nNumerator   = 0;
401         nDenominator = -1;
402     }
403     if ( !IsValid() )
404         return *this;
405 
406     long nGGT1 = GetGGT( nNumerator, rVal.nDenominator );
407     long nGGT2 = GetGGT( rVal.nNumerator, nDenominator );
408     BigInt nN( nNumerator / nGGT1 );
409     nN *= BigInt( rVal.nNumerator / nGGT2 );
410     BigInt nD( nDenominator / nGGT2 );
411     nD *= BigInt( rVal.nDenominator / nGGT1 );
412 
413     if ( nN.bIsBig || nD.bIsBig )
414     {
415         nNumerator   = 0;
416         nDenominator = -1;
417     }
418     else
419     {
420         nNumerator   = (long)nN,
421         nDenominator = (long)nD;
422     }
423 
424     return *this;
425 }
426 
427 /*************************************************************************
428 |*
429 |*    Fraction::operator/=()
430 |*
431 |*    Beschreibung      FRACT.SDW
432 |*    Ersterstellung    DV 20.09.90
433 |*    Letzte �nderung   DV 21.12.92
434 |*
435 *************************************************************************/
436 
437 // Zun�chst werden die beiden Parameter auf ihre G�ltigkeit �berpr�ft.
438 // Ist einer der Parameter ung�ltig, dann ist auch des Ergebnis
439 // ung�ltig.
440 // Um den Bruch a durch b zu teilen, wird a mit dem Kehrwert von b
441 // multipliziert. Analog zu Multiplikation wird jetzt jeweils der Z�hler
442 // des einen Bruches mit dem Nenner des anderen multipliziert.
443 // Um �berl�ufe zu vermeiden, werden vorher jeweils der GGT zwischen den
444 // beiden Z�hlern und den beiden Nennern bestimmt und bei der
445 // Multiplikation Z�hler und Nenner durch die entsprechenden Werte
446 // geteilt.
447 // Innerhalb der Funktion wird mit dem Datentyp BigInt gerechnet, um
448 // einen m�glichen �berlauf erkennen zu k�nnen. Bei einem �berlauf
449 // wird das Ergebnis auf den Wert ung�ltig gesetzt.
450 
451 Fraction& Fraction::operator /= ( const Fraction& rVal )
452 {
453     if ( !rVal.IsValid() )
454     {
455         nNumerator   = 0;
456         nDenominator = -1;
457     }
458     if ( !IsValid() )
459         return *this;
460 
461     long nGGT1 = GetGGT( nNumerator, rVal.nNumerator );
462     long nGGT2 = GetGGT( rVal.nDenominator, nDenominator );
463     BigInt nN( nNumerator / nGGT1 );
464     nN *= BigInt( rVal.nDenominator / nGGT2 );
465     BigInt nD( nDenominator / nGGT2 );
466     nD *= BigInt( rVal.nNumerator / nGGT1 );
467 
468     if ( nN.bIsBig || nD.bIsBig )
469     {
470         nNumerator   = 0;
471         nDenominator = -1;
472     }
473     else
474     {
475         nNumerator   = (long)nN,
476         nDenominator = (long)nD;
477         if ( nDenominator < 0 )
478         {
479             nDenominator = -nDenominator;
480             nNumerator   = -nNumerator;
481         }
482     }
483 
484     return *this;
485 }
486 
487 /*************************************************************************
488 |*
489 |*    Fraction::ReduceInaccurate()
490 |*
491 |*    Beschreibung      FRACT.SDW
492 |*    Ersterstellung    JOE 17.09.95
493 |*    Letzte �nderung   kendy 2007-06-13
494 |*
495 *************************************************************************/
496 
497 
498 // Similar to clz_table that can be googled
499 const char nbits_table[32] =
500 {
501     32,  1, 23,  2, 29, 24, 14,  3,
502     30, 27, 25, 18, 20, 15, 10,  4,
503     31, 22, 28, 13, 26, 17, 19,  9,
504     21, 12, 16,  8, 11,  7,  6,  5
505 };
506 
507 static int impl_NumberOfBits( unsigned long nNum )
508 {
509     // https://en.wikipedia.org/wiki/De_Bruijn_sequence
510     //
511     // background paper: Using de Bruijn Sequences to Index a 1 in a
512     // Computer Word (1998) Charles E. Leiserson,
513     // Harald Prokop, Keith H. Randall
514     // (e.g. http://citeseer.ist.psu.edu/leiserson98using.html)
515     const sal_uInt32 nDeBruijn = 0x7DCD629;
516 
517     if ( nNum == 0 )
518         return 0;
519 
520     // Get it to form like 0000001111111111b
521     nNum |= ( nNum >>  1 );
522     nNum |= ( nNum >>  2 );
523     nNum |= ( nNum >>  4 );
524     nNum |= ( nNum >>  8 );
525     nNum |= ( nNum >> 16 );
526 
527     sal_uInt32 nNumber;
528     int nBonus = 0;
529 
530 #if SAL_TYPES_SIZEOFLONG == 4
531     nNumber = nNum;
532 #elif SAL_TYPES_SIZEOFLONG == 8
533     nNum |= ( nNum >> 32 );
534 
535     if ( nNum & 0x80000000 )
536     {
537         nNumber = sal_uInt32( nNum >> 32 );
538         nBonus = 32;
539 
540         if ( nNumber == 0 )
541             return 32;
542     }
543     else
544         nNumber = sal_uInt32( nNum & 0xFFFFFFFF );
545 #else
546 #error "Unknown size of long!"
547 #endif
548 
549     // De facto shift left of nDeBruijn using multiplication (nNumber
550     // is all ones from topmost bit, thus nDeBruijn + (nDeBruijn *
551     // nNumber) => nDeBruijn * (nNumber+1) clears all those bits to
552     // zero, sets the next bit to one, and thus effectively shift-left
553     // nDeBruijn by lg2(nNumber+1). This generates a distinct 5bit
554     // sequence in the msb for each distinct position of the last
555     // leading 0 bit - that's the property of a de Bruijn number.
556     nNumber = nDeBruijn + ( nDeBruijn * nNumber );
557 
558     // 5-bit window indexes the result
559     return ( nbits_table[nNumber >> 27] ) + nBonus;
560 }
561 
562 /** Inaccurate cancellation for a fraction.
563 
564     Clip both nominator and denominator to said number of bits. If
565     either of those already have equal or less number of bits used,
566     this method does nothing.
567 
568     @param nSignificantBits denotes, how many significant binary
569     digits to maintain, in both nominator and denominator.
570 
571     @example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the
572     largest error occurs with the following pair of values:
573 
574     binary    1000000011111111111111111111111b/1000000000000000000000000000000b
575     =         1082130431/1073741824
576     = approx. 1.007812499
577 
578     A ReduceInaccurate(8) yields 1/1.
579 */
580 void Fraction::ReduceInaccurate( unsigned nSignificantBits )
581 {
582     if ( !nNumerator || !nDenominator )
583         return;
584 
585     // Count with unsigned longs only
586     const bool bNeg = ( nNumerator < 0 );
587     unsigned long nMul = (unsigned long)( bNeg? -nNumerator: nNumerator );
588     unsigned long nDiv = (unsigned long)( nDenominator );
589 
590     DBG_ASSERT(nSignificantBits<65, "More than 64 bit of significance is overkill!");
591 
592     // How much bits can we lose?
593     const int nMulBitsToLose = Max( ( impl_NumberOfBits( nMul ) - int( nSignificantBits ) ), 0 );
594     const int nDivBitsToLose = Max( ( impl_NumberOfBits( nDiv ) - int( nSignificantBits ) ), 0 );
595 
596     const int nToLose = Min( nMulBitsToLose, nDivBitsToLose );
597 
598     // Remove the bits
599     nMul >>= nToLose;
600     nDiv >>= nToLose;
601 
602     if ( !nMul || !nDiv )
603     {
604         // Return without reduction
605         DBG_ERROR( "Oops, we reduced too much..." );
606         return;
607     }
608 
609     // Reduce
610     long n1 = GetGGT( nMul, nDiv );
611     if ( n1 != 1 )
612     {
613         nMul /= n1;
614         nDiv /= n1;
615     }
616 
617     nNumerator = bNeg? -long( nMul ): long( nMul );
618     nDenominator = nDiv;
619 }
620 
621 /*************************************************************************
622 |*
623 |*    Fraction::operator ==()
624 |*
625 |*    Beschreibung      FRACT.SDW
626 |*    Ersterstellung    DV 20.09.90
627 |*    Letzte �nderung   TH 19.08.92
628 |*
629 *************************************************************************/
630 
631 sal_Bool operator == ( const Fraction& rVal1, const Fraction& rVal2 )
632 {
633     if ( !rVal1.IsValid() || !rVal2.IsValid() )
634         return sal_False;
635 
636     return rVal1.nNumerator == rVal2.nNumerator
637            && rVal1.nDenominator == rVal2.nDenominator;
638 }
639 
640 /*************************************************************************
641 |*
642 |*    Fraction::operator <()
643 |*
644 |*    Beschreibung      FRACT.SDW
645 |*    Ersterstellung    DV 20.09.90
646 |*    Letzte �nderung   DV 21.12.92
647 |*
648 *************************************************************************/
649 
650 // Beide Operanden werden zun�chst auf ihre G�ltigkeit �berpr�ft und
651 // anschlie�end zur Sicherheit noch einmal gek�rzt. Um die Br�che
652 // (a/b) und (c/d) zu vergleichen, werden sie zun�chst auf einen
653 // gemeinsamen Nenner gebracht (b*d), um dann die beiden Z�hler (a*d)
654 // und (c*b) zu vergleichen. Das Ergebnis dieses Vergleichs wird
655 // zur�ckgegeben.
656 
657 sal_Bool operator < ( const Fraction& rVal1, const Fraction& rVal2 )
658 {
659     if ( !rVal1.IsValid() || !rVal2.IsValid() )
660         return sal_False;
661 
662     BigInt nN( rVal1.nNumerator );
663     nN *= BigInt( rVal2.nDenominator );
664     BigInt nD( rVal1.nDenominator );
665     nD *= BigInt( rVal2.nNumerator );
666 
667     return nN < nD;
668 }
669 
670 /*************************************************************************
671 |*
672 |*    Fraction::operator >()
673 |*
674 |*    Beschreibung      FRACT.SDW
675 |*    Ersterstellung    DV 20.09.90
676 |*    Letzte �nderung   TH 19.08.92
677 |*
678 *************************************************************************/
679 
680 // Beide Operanden werden zun�chst auf ihre G�ltigkeit �berpr�ft und
681 // anschlie�end zur Sicherheit noch einmal gek�rzt. Um die Br�che
682 // (a/b) und (c/d) zu vergleichen, werden sie zun�chst auf einen
683 // gemeinsamen Nenner gebracht (b*d), um dann die beiden Z�hler (a*d)
684 // und (c*b) zu vergleichen. Das Ergebnis dieses Vergleichs wird
685 // zur�ckgegeben.
686 
687 sal_Bool operator > ( const Fraction& rVal1, const Fraction& rVal2 )
688 {
689     if ( !rVal1.IsValid() || !rVal2.IsValid() )
690         return sal_False;
691 
692     BigInt nN( rVal1.nNumerator );
693     nN *= BigInt( rVal2.nDenominator );
694     BigInt nD( rVal1.nDenominator);
695     nD *= BigInt( rVal2.nNumerator );
696 
697     return nN > nD;
698 }
699 
700 /*************************************************************************
701 |*
702 |*    SvStream& operator>>( SvStream& rIStream, Fraction& rFract )
703 |*
704 |*    Beschreibung      FRACT.SDW
705 |*    Ersterstellung    MM 08.01.96
706 |*    Letzte �nderung   MM 08.01.96
707 |*
708 *************************************************************************/
709 SvStream& operator >> ( SvStream& rIStream, Fraction& rFract )
710 {
711     rIStream >> rFract.nNumerator;
712     rIStream >> rFract.nDenominator;
713     return rIStream;
714 }
715 
716 /*************************************************************************
717 |*
718 |*    SvStream& operator<<( SvStream& rIStream, Fraction& rFract )
719 |*
720 |*    Beschreibung      FRACT.SDW
721 |*    Ersterstellung    MM 08.01.96
722 |*    Letzte �nderung   MM 08.01.96
723 |*
724 *************************************************************************/
725 SvStream& operator << ( SvStream& rOStream, const Fraction& rFract )
726 {
727     rOStream << rFract.nNumerator;
728     rOStream << rFract.nDenominator;
729     return rOStream;
730 }
731 
732 /* vim: set noet sw=4 ts=4: */
733