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