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