Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/rational/rational.html @ 35

Last change on this file since 35 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 29.5 KB
Line 
1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3<head>
4<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
5<title>Rational Number Library</title>
6</head>
7<body>
8<h1><img src="../../boost.png" alt="boost.png (6897 bytes)"
9     align="middle" width="277" height="86">
10Rational Numbers</h1>
11
12<h2><a name="Contents">Contents</a></h2>
13
14<ol>
15    <li><a href="#Class%20rational%20synopsis">Class rational synopsis</a></li>
16    <li><a href="#Rationale">Rationale</a></li>
17    <li><a href="#Background">Background</a></li>
18    <li><a href="#Integer%20Type%20Requirements">Integer Type Requirements</a></li>
19    <li><a href="#Interface">Interface</a>
20    <ul>
21        <li><a href="#Utility%20functions">Utility functions</a></li>
22        <li><a href="#Constructors">Constructors</a></li>
23        <li><a href="#Arithmetic%20operations">Arithmetic operations</a></li>
24        <li><a href="#Input%20and%20Output">Input and Output</a></li>
25        <li><a href="#In-place%20assignment">In-place assignment</a></li>
26        <li><a href="#Conversions">Conversions</a></li>
27        <li><a href="#Numerator%20and%20Denominator">Numerator and Denominator</a></li>
28    </ul></li>
29    <li><a href="#Performance">Performance</a></li>
30    <li><a href="#Exceptions">Exceptions</a></li>
31    <li><a href="#Internal%20representation">Internal representation</a></li>
32    <li><a href="#Design%20notes">Design notes</a>
33    <ul>
34        <li><a href="#Minimal%20Implementation">Minimal Implementation</a></li>
35        <li><a href="#Limited-range%20integer%20types">Limited-range integer types</a></li>
36        <li><a href="#Conversion%20from%20floating%20point">Conversion from floating point</a></li>
37        <li><a href="#Absolute%20Value">Absolute Value</a></li>
38    </ul></li>
39    <li><a href="#References">References</a></li>
40    <li><a href="#History%20and%20Acknowledgements">History and Acknowledgements</a></li>
41</ol>
42
43<h2><a name="Class rational synopsis">Class rational synopsis</a></h2>
44<pre>
45#include &lt;boost/rational.hpp&gt;
46
47namespace boost {
48
49template &lt;typename I&gt; I gcd(I n, I m);
50template &lt;typename I&gt; I lcm(I n, I m);
51
52class bad_rational;
53
54template&lt;typename I&gt; class rational {
55    typedef <em>implementation-defined</em> bool_type;
56
57public:
58    typedef I int_type;
59
60    // Constructors
61    rational();          // Zero
62    rational(I n);       // Equal to n/1
63    rational(I n, I d);  // General case (n/d)
64
65    // Normal copy constructors and assignment operators
66
67    // Assignment from I
68    rational&amp; operator=(I n);
69
70    // Assign in place
71    rational&amp; assign(I n, I d);
72
73    // Representation
74    I numerator() const;
75    I denominator() const;
76
77    // In addition to the following operators, all of the "obvious" derived
78    // operators are available - see <a href=../utility/operators.htm>operators.hpp</a>
79
80    // Arithmetic operators
81    rational&amp; operator+= (const rational&amp; r);
82    rational&amp; operator-= (const rational&amp; r);
83    rational&amp; operator*= (const rational&amp; r);
84    rational&amp; operator/= (const rational&amp; r);
85
86    // Arithmetic with integers
87    rational&amp; operator+= (I i);
88    rational&amp; operator-= (I i);
89    rational&amp; operator*= (I i);
90    rational&amp; operator/= (I i);
91
92    // Increment and decrement
93    const rational&amp; operator++();
94    const rational&amp; operator--();
95
96    // Operator not
97    bool operator!() const;
98
99    // Boolean conversion
100    operator bool_type() const;
101
102    // Comparison operators
103    bool operator&lt; (const rational&amp; r) const;
104    bool operator== (const rational&amp; r) const;
105
106    // Comparison with integers
107    bool operator&lt; (I i) const;
108    bool operator&gt; (I i) const;
109    bool operator== (I i) const;
110};
111
112// Unary operators
113template &lt;typename I&gt; rational&lt;I&gt; operator+ (const rational&lt;I&gt;&amp; r);
114template &lt;typename I&gt; rational&lt;I&gt; operator- (const rational&lt;I&gt;&amp; r);
115
116// Reversed order operators for - and / between (types convertible to) I and rational
117template &lt;typename I, typename II&gt; inline rational&lt;I&gt; operator- (II i, const rational&lt;I&gt;&amp; r);
118template &lt;typename I, typename II&gt; inline rational&lt;I&gt; operator/ (II i, const rational&lt;I&gt;&amp; r);
119
120// Absolute value
121template &lt;typename I&gt; rational&lt;I&gt; abs (const rational&lt;I&gt;&amp; r);
122
123// Input and output
124template &lt;typename I&gt; std::istream&amp; operator&gt;&gt; (std::istream&amp; is, rational&lt;I&gt;&amp; r);
125template &lt;typename I&gt; std::ostream&amp; operator&lt;&lt; (std::ostream&amp; os, const rational&lt;I&gt;&amp; r);
126
127// Type conversion
128template &lt;typename T, typename I&gt; T rational_cast (const rational&lt;I&gt;&amp; r);
129</pre>
130
131<h2><a name="Rationale">Rationale</a></h2>
132
133Numbers come in many different forms. The most basic forms are natural numbers
134(non-negative "whole" numbers), integers and real numbers.  These types are
135approximated by the C++ built-in types <b>unsigned int</b>, <b>int</b>, and
136<b>float</b> (and their various equivalents in different sizes).
137
138<p>The C++ Standard Library extends the range of numeric types available by
139providing the <b>complex</b> type.
140
141<p>This library provides a further numeric type, the <b>rational</b> numbers.
142
143<p>The <b>rational</b> class is actually a implemented as a template, in a
144similar manner to the standard <b>complex</b> class.
145
146<h2><a name="Background">Background</a></h2>
147
148The mathematical concept of a rational number is what is commonly thought of
149as a fraction - that is, a number which can be represented as the ratio of two
150integers. This concept is distinct from that of a real number, which can take
151on many more values (for example, the square root of 2, which cannot be
152represented as a fraction).
153
154<p>
155Computers cannot represent mathematical concepts exactly - there are always
156compromises to be made. Machine integers have a limited range of values (often
15732 bits), and machine approximations to reals are limited in precision. The
158compromises have differing motivations - machine integers allow exact
159calculation, but with a limited range, whereas machine reals allow a much
160greater range, but at the expense of exactness.
161
162<p>
163The rational number class provides an alternative compromise. Calculations
164with rationals are exact, but there are limitations on the available range. To
165be precise, rational numbers are exact as long as the numerator and
166denominator (which are always held in normalized form, with no common factors)
167are within the range of the underlying integer type. When values go outside
168these bounds, overflow occurs and the results are undefined.
169
170<p>
171The rational number class is a template to allow the programmer to control the
172overflow behaviour somewhat. If an unlimited precision integer type is
173available, rational numbers based on it will never overflow and will provide
174exact calculations in all circumstances.
175
176<h2><a name="Integer Type Requirements">Integer Type Requirements</a></h2>
177
178<p> The rational type takes a single template type parameter I. This is the
179<em>underlying integer type</em> for the rational type. Any of the built-in
180integer types provided by the C++ implementation are supported as values for
181I. User-defined types may also be used, but users should be aware that the
182performance characteristics of the rational class are highly dependent upon
183the performance characteristics of the underlying integer type (often in
184complex ways - for specific notes, see the <a href="#Performance">Performance</a>
185section below). Note: Should the boost library support an unlimited-precision
186integer type in the future, this type will be fully supported as the underlying
187integer type for the rational class.
188</p>
189
190<p>
191A user-defined integer type which is to be used as the underlying integer type
192for the rational type must be a model of the following concepts.
193</p>
194
195<ul>
196<li>Assignable
197<li>Default Constructible
198<li>Equality Comparable
199<li>LessThan Comparable
200</ul>
201
202<p>
203Furthermore, I must be an <em>integer-like</em> type, that is the following
204expressions must be valid for any two values n and m of type I, with the
205"expected" semantics.
206
207<ul>
208<li><code>n + m</code>
209<li><code>n - m</code>
210<li><code>n * m</code>
211<li><code>n / m</code> (must truncate; must be nonnegative if <var>n</var> and
212    <var>m</var> are positive)
213<li><code>n % m</code> (must be nonnegative if <var>n</var> and <var>m</var>
214    are positive)
215<li>Assignment versions of the above
216<li><code>+n</code>, <code>-n</code>
217<li><code>!n</code> (must be <code>true</code> iff <var>n</var> is zero)
218</ul>
219
220<p>
221There must be <em>zero</em> and <em>one</em> values available for I. It should
222be possible to generate these as <tt>I(0)</tt> and <tt>I(1)</tt>,
223respectively. <em>Note:</em> This does not imply that I needs to have an
224implicit conversion from integer - an <tt>explicit</tt> constructor is
225adequate.
226
227<p>
228It is valid for I to be an unsigned type. In that case, the derived rational
229class will also be unsigned. Underflow behaviour of subtraction, where results
230would otherwise be negative, is unpredictable in this case.
231
232<ul>
233<li>
234The implementation of rational_cast&lt;T&gt;(rational&lt;I&gt;) relies on the
235ability to static_cast from type I to type T, and on the expression x/y being
236valid for any two values of type T.
237<li>
238The input and output operators rely on the existence of corresponding input
239and output operators for type I.
240</ul>
241
242<h2><a name="Interface">Interface</a></h2>
243
244<h3><a name="Utility functions">Utility functions</a></h3>
245Two utility functions are provided, which work on any type I for which the
246following operations are defined: <tt>=, +=, *=, /=, %, &lt;</tt>, and a zero
247value accessible as I(0)
248<br><br>
249<table summary="Common-factor utility functions">
250<tr>
251<td width=5%></td>
252<td><tt>gcd(n, m)</tt></td>
253<td width=5%></td>
254<td>The greatest common divisor of n and m</td>
255</tr>
256<tr>
257<td width=5%></td>
258<td><tt>lcm(n, m)</tt></td>
259<td width=5%></td>
260<td>The least common multiple of n and m</td>
261</tr>
262</table>
263
264<p><em>Note:</em> In the future, these functions may be moved into a separate
265boost utility library.
266
267<h3><a name="Constructors">Constructors</a></h3>
268<p>Rationals can be constructed from zero, one, or two integer arguments;
269representing default construction as zero, conversion from an integer posing as
270the numerator with an implicit denominator of one, or a numerator and
271denominator pair in that order, respectively.  An integer argument should be of
272the rational's integer type, or implicitly convertible to that type.  (For the
273two-argument constructor, any needed conversions are evaluated independently,
274of course.)  The components are stored in normalized form.
275
276<p>This implies that the following statements are valid:
277
278<pre>
279    I n, d;
280    rational&lt;I&gt; zero;
281    rational&lt;I&gt; r1(n);
282    rational&lt;I&gt; r2(n, d);
283</pre>
284
285<p>The single-argument constructor is <em>not</em> declared as explicit, so
286there is an implicit conversion from the underlying integer type to the
287rational type.
288
289<h3><a name="Arithmetic operations">Arithmetic operations</a></h3>
290All of the standard numeric operators are defined for the <b>rational</b>
291class. These include:
292<br>
293
294<pre>
295    +    +=
296    -    -=
297    *    *=
298    /    /=
299    ++   --    (both prefix and postfix)
300    ==   !=
301    &lt;    &gt;
302    &lt;=   &gt;=
303</pre>
304
305<h3><a name="Input and Output">Input and Output</a></h3>
306Input and output operators <tt>&lt;&lt;</tt> and <tt>&gt;&gt;</tt>
307are provided. The external representation of a rational is
308two integers, separated by a slash (<tt>/</tt>). On input, the format must be
309exactly an integer, followed with no intervening whitespace by a slash,
310followed (again with no intervening whitespace) by a second integer. The
311external representation of an integer is defined by the undelying integer
312type.
313
314<h3><a name="In-place assignment">In-place assignment</a></h3>
315For any <tt>rational&lt;I&gt; r</tt>, <tt>r.assign(n, m)</tt> provides a
316fast equivalent of <tt>r = rational&lt;I&gt;(n, m);</tt>, without the
317construction of a temporary. While this is probably unnecessary for rationals
318based on machine integer types, it could offer a saving for rationals based on
319unlimited-precision integers, for example.
320
321<h3><a name="Conversions">Conversions</a></h3>
322<p>There is a conversion operator to an unspecified Boolean type (most likely a
323member pointer).  This operator converts a rational to <code>false</code> if it
324represents zero, and <code>true</code> otherwise.  This conversion allows a
325rational for use as the first argument of operator <code>?:</code>; as either
326argument of operators <code>&amp;&amp;</code> or <code>||</code> without
327forfeiting short-circuit evaluation; as a condition for a <code>do</code>,
328<code>if</code>, <code>while</code>, or <code>for</code> statement; and as a
329conditional declaration for <code>if</code>, <code>while</code>, or
330<code>for</code> statements.  The nature of the type used, and that any names
331for that nature are kept private, should prevent any inappropriate non-Boolean
332use like numeric or pointer operations or as a <code>switch</code> condition.
333
334<p>There are <em>no other</em> implicit conversions from a rational
335type. However, there is an explicit type-conversion function,
336<tt>rational_cast&lt;T&gt;(r)</tt>. This can be used as follows:
337
338<pre>
339    rational r(22,7);
340    double nearly_pi = boost::rational_cast&lt;double&gt;(r);
341</pre>
342
343<p>The <tt>rational_cast&lt;T&gt;</tt> function's behaviour is undefined if the
344source rational's numerator or denominator cannot be safely cast to the
345appropriate floating point type, or if the division of the numerator and
346denominator (in the target floating point type) does not evaluate correctly.
347
348<p>In essence, all required conversions should be value-preserving, and all
349operations should behave "sensibly". If these constraints cannot be met, a
350separate user-defined conversion will be more appropriate.
351
352<p><em>Implementation note:</em>
353
354<p>The actual implementation of the rational_cast function is
355
356<pre>
357    template &lt;typename Float, typename Int&gt;
358    Float rational_cast(const rational&lt;Int&gt;&amp; src)
359    {
360        return static_cast&lt;Float&gt;(src.numerator()) / src.denominator();
361    }
362</pre>
363
364Programs should not be written to depend upon this implementation, however.
365
366<h3><a name="Numerator and Denominator">Numerator and Denominator</a></h3>
367Finally, access to the internal representation of rationals is provided by
368the two member functions <tt>numerator()</tt> and <tt>denominator()</tt>.
369
370<p>These functions allow user code to implement any additional required
371functionality. In particular, it should be noted that there may be cases where
372the above rational_cast operation is inappropriate - particularly in cases
373where the rational type is based on an unlimited-precision integer type. In
374this case, a specially-written user-defined conversion to floating point will
375be more appropriate.
376
377<h2><a name="Performance">Performance</a></h2>
378The rational class has been designed with the implicit assumption that the
379underlying integer type will act "like" the built in integer types. The
380behavioural aspects of this assumption have been explicitly described above,
381in the <a href="#Integer%20Type%20Requirements">Integer Type Requirements</a>
382section. However, in addition to behavioural assumptions, there are implicit
383performance assumptions.
384
385<p> No attempt will be made to provide detailed performance guarantees for the
386operations available on the rational class. While it is possible for such
387guarantees to be provided (in a similar manner to the performance
388specifications of many of the standard library classes) it is by no means
389clear that such guarantees will be of significant value to users of the
390rational class. Instead, this section will provide a general discussion of the
391performance characteristics of the rational class.
392
393<p>There now follows a list of the fundamental operations defined in the
394<a href="../../boost/rational.hpp"> &lt;boost/rational.hpp&gt;</a> header
395and an informal description of their performance characteristics. Note that
396these descriptions are based on the current implementation, and as such should
397be considered subject to change.
398
399<ul>
400<li>Construction of a rational is essentially just two constructions of the
401underlying integer type, plus a normalization.
402
403<li>Increment and decrement operations are essentially as cheap as addition and
404subtraction on the underlying integer type.
405
406<li>(In)equality comparison is essentially as cheap as the same operation on
407the underlying integer type.
408
409<li>I/O operations are not cheap, but their performance is essentially
410dominated by the I/O time itself.
411
412<li>The gcd operation is essentially a repeated modulus operation. The only
413other significant operations are construction, assignment, and comparison
414against zero of IntType values. These latter operations are assumed to be
415trivial in comparison with the modulus operation.
416
417<li>The lcm operation is essentially a gcd, plus a couple of multiplications
418and divisions.
419
420<li>The addition and subtraction operations are complex. They will require
421approximately two gcd operations, 3 divisions, 3 multiplications and an
422addition on the underlying integer type.
423
424<li>The multiplication and division operations require two gcd operations, two
425multiplications, and four divisions.
426
427<li>The comparison operations require two gcd operations, two multiplications,
428four divisions and a comparison in the worst case. On the assumption that
429IntType comparisons are the cheapest of these operations (and that comparisons
430agains zero may be cheaper still), these operations have a number of special
431case optimisations to reduce the overhead where possible. In particular,
432equality and inequality tests are only as expensive as two of the equivalent
433tests on the underlying integer type.
434
435<li>The final fundamental operation is normalizing a rational. This operation
436is performed whenever a rational is constructed (and assigned in place). All
437other operations are careful to maintain rationals in a normalized state.
438Normalization costs the equivalent of one gcd and two divisions.
439</ul>
440
441<p>Note that it is implicitly assumed that operations on IntType have the
442"usual" performance characteristics - specifically, that the expensive
443operations are multiplication, division, and modulo, with addition and
444subtraction being significantly cheaper. It is assumed that construction (from
445integer literals 0 and 1, and copy construction) and assignment are relatively
446cheap, although some effort is taken to reduce unnecessary construction and
447copying. It is also assumed that comparison (particularly against zero) is
448cheap.
449
450<p>Integer types which do not conform to these assumptions will not be
451particularly effective as the underlying integer type for the rational class.
452Specifically, it is likely that performance will be severely sub-optimal.
453
454<h2><a name="Exceptions">Exceptions</a></h2>
455Rationals can never have a denominator of zero. (This library does not support
456representations for infinity or NaN). Should a rational result ever generate a
457denominator of zero, the exception <tt>boost::bad_rational</tt> (a subclass of
458<tt>std::domain_error</tt>) is thrown. This should only occur if the user
459attempts to explicitly construct a rational with a denominator of zero, or to
460divide a rational by a zero value.
461
462<p>In addition, if operations on the underlying integer type can generate
463exceptions, these will be propogated out of the operations on the rational
464class. No particular assumptions should be made - it is only safe to assume
465that any exceptions which can be thrown by the integer class could be thrown
466by any rational operation. In particular, the rational constructor may throw
467exceptions from the underlying integer type as a result of the normalization
468step.  The only exception to this rule is that the rational destructor will
469only throw exceptions which can be thrown by the destructor of the underlying
470integer type (usually none).
471
472<h2><a name="Internal representation">Internal representation</a></h2>
473<em>Note:</em> This information is for information only. Programs should not
474be written in such a way as to rely on these implementation details.
475
476<p>Internally, rational numbers are stored as a pair (numerator, denominator)
477of integers (whose type is specified as the template parameter for the
478rational type). Rationals are always stored in fully normalized form (ie,
479gcd(numerator,denominator) = 1, and the denominator is always positive).
480
481<h2><a name="Design notes">Design notes</a></h2>
482<h3><a name="Minimal Implementation">Minimal Implementation</a></h3>
483The rational number class is designed to keep to the basics. The minimal
484operations required of a numeric class are provided, along with access to the
485underlying representation in the form of the numerator() and denominator()
486member functions. With these building-blocks, it is possible to implement any
487additional functionality required.
488
489<p>Areas where this minimality consideration has been relaxed are in providing
490input/output operators, and rational_cast. The former is generally
491uncontroversial. However, there are a number of cases where rational_cast is
492not the best possible method for converting a rational to a floating point
493value (notably where user-defined types are involved). In those cases, a
494user-defined conversion can and should be implemented. There is no need
495for such an operation to be named rational_cast, and so the rational_cast
496function does <em>not</em> provide the necessary infrastructure to allow for
497specialisation/overloading.
498
499<h3><a name="Limited-range integer types">Limited-range integer types</a></h3>
500The rational number class is designed for use in conjunction with an
501unlimited precision integer class. With such a class, rationals are always
502exact, and no problems arise with precision loss, overflow or underflow.
503
504<p>Unfortunately, the C++ standard does not offer such a class (and neither
505does boost, at the present time). It is therefore likely that the rational
506number class will in many cases be used with limited-precision integer types,
507such as the built-in <tt>int</tt> type.
508
509<p>When used with a limited precision integer type, the rational class suffers
510from many of the precision issues which cause difficulty with floating point
511types. While it is likely that precision issues will not affect simple uses of
512the rational class, users should be aware that such issues exist.
513
514<p>As a simple illustration of the issues associated with limited precision
515integers, consider a case where the C++ <tt>int</tt> type is a 32-bit signed
516representation. In this case, the smallest possible positive
517rational&lt;int&gt; is <tt>1/0x7FFFFFFF</tt>. In other words, the
518"granularity" of the rational&lt;int&gt; representation around zero is
519approximately 4.66e-10. At the other end of the representable range, the
520largest representable rational&lt;int&gt; is <tt>0x7FFFFFFF/1</tt>, and the
521next lower representable rational&lt;int&gt; is <tt>0x7FFFFFFE/1</tt>. Thus,
522at this end of the representable range, the granularity ia 1. This type of
523magnitude-dependent granularity is typical of floating point representations.
524However, it does not "feel" natural when using a rational number class.
525
526<p>It is up to the user of a rational type based on a limited-precision integer
527type to be aware of, and code in anticipation of, such issues.
528
529<h3><a name="Conversion from floating point">Conversion from floating point</a></h3>
530The library does not offer a conversion function from floating point to
531rational. A number of requests were received for such a conversion, but
532extensive discussions on the boost list reached the conclusion that there was
533no "best solution" to the problem. As there is no reason why a user of the
534library cannot write their own conversion function which suits their
535particular requirements, the decision was taken not to pick any one algorithm
536as "standard".
537
538<p>The key issue with any conversion function from a floating point value is
539how to handle the loss of precision which is involved in floating point
540operations. To provide a concrete example, consider the following code:
541
542<pre>
543    // These two values could in practice be obtained from user input,
544    // or from some form of measuring instrument.
545    double x = 1.0;
546    double y = 3.0;
547
548    double z = x/y;
549
550    rational&lt;I&gt; r = rational_from_double(z);
551</pre>
552
553<p>The fundamental question is, precisely what rational should r be? A naive
554answer is that r should be equal to 1/3. However, this ignores a multitude of
555issues.
556
557<p>In the first instance, z is not exactly 1/3. Because of the limitations of
558floating point representation, 1/3 is not exactly representable in any of the
559common representations for the double type. Should r therefore not contain an
560(exact) representation of the actual value represented by z? But will the user
561be happy with a value of 33333333333333331/100000000000000000 for r?
562
563<p>Before even considering the above issue, we have to consider the accuracy
564of the original values, x and y. If they came from an analog measuring
565instrument, for example, they are not infinitely accurate in any case. In such
566a case, a rational representation like the above promises far more accuracy
567than there is any justification for.
568
569<p>All of this implies that we should be looking for some form of "nearest
570simple fraction". Algorithms to determine this sort of value do exist.
571However, not all applications want to work like this. In other cases, the
572whole point of converting to rational is to obtain an exact representation, in
573order to prevent accuracy loss during a series of calculations. In this case,
574a completely precise representation is required, regardless of how "unnatural"
575the fractions look.
576
577<p>With these conflicting requirements, there is clearly no single solution
578which will satisfy all users. Furthermore, the algorithms involved are
579relatively complex and specialised, and are best implemented with a good
580understanding of the application requirements. All of these factors make such
581a function unsuitable for a general-purpose library such as this.
582
583<h3><a name="Absolute Value">Absolute Value</a></h3>
584In the first instance, it seems logical to implement
585abs(rational&lt;IntType&gt;) in terms of abs(IntType).
586However, there are a number of issues which arise with doing so.
587
588<p>The first issue is that, in order to locate the appropriate implementation
589of abs(IntType) in the case where IntType is a user-defined type in a user
590namespace, Koenig lookup is required. Not all compilers support Koenig lookup
591for functions at the current time. For such compilers, clumsy workarounds,
592which require cooperation from the user of the rational class, are required to
593make things work.
594
595<p>The second, and potentially more serious, issue is that for non-standard
596built-in integer types (for example, 64-bit integer types such as
597<em>long long</em> or <em>__int64</em>), there is no guarantee that the vendor
598has supplied a built in abs() function operating on such types. This is a
599quality-of-implementation issue, but in practical terms, vendor support for
600types such as <em>long long</em> is still very patchy.
601
602<p>As a consequence of these issues, it does not seem worth implementing
603abs(rational&lt;IntType&gt;) in terms of abs(IntType). Instead, a simple
604implementation with an inline implementation of abs() is used:
605
606<pre>
607    template &lt;typename IntType&gt;
608    inline rational&lt;IntType&gt; abs(const rational&lt;IntType&gt;&amp; r)
609    {
610        if (r.numerator() &gt;= IntType(0))
611            return r;
612
613            return rational&lt;IntType&gt;(-r.numerator(), r.denominator());
614    }
615</pre>
616
617<p>The same arguments imply that where the absolute value of an IntType is
618required elsewhere, the calculation is performed inline.
619
620<h2><a name="References">References</a></h2>
621<ul>
622<li>The rational number header itself: <a href="../../boost/rational.hpp">rational.hpp</a>
623<li>Some example code: <a href="rational_example.cpp">rational_example.cpp</a>
624<li>The regression test: <a href="rational_test.cpp">rational_test.cpp</a>
625</ul>
626
627<h2><a name="History and Acknowledgements">History and Acknowledgements</a></h2>
628
629In December, 1999, I implemented the initial version of the rational number
630class, and submitted it to the <A HREF="http://www.boost.org/">boost.org</A>
631mailing list. Some discussion of the implementation took place on the mailing
632list. In particular, Andrew D. Jewell pointed out the importance of ensuring
633that the risk of overflow was minimised, and provided overflow-free
634implementations of most of the basic operations. The name rational_cast was
635suggested by Kevlin Henney. Ed Brey provided invaluable comments - not least
636in pointing out some fairly stupid typing errors in the original code!
637
638<p>David Abrahams contributed helpful feedback on the documentation.
639
640<p>A long discussion of the merits of providing a conversion from floating
641point to rational took place on the boost list in November 2000. Key
642contributors included Reggie Seagraves, Lutz Kettner and Daniel Frey (although
643most of the boost list seemed to get involved at one point or another!). Even
644though the end result was a decision <em>not</em> to implement anything, the
645discussion was very valuable in understanding the issues.
646
647<p>Stephen Silver contributed useful experience on using the rational class
648with a user-defined integer type.
649
650<p>Nickolay Mladenov provided the current implementation of operator+= and
651operator-=.
652
653<p>Discussion of the issues surrounding Koenig lookup and std::swap took place
654on the boost list in January 2001.
655
656<p>Daryle Walker provided a Boolean conversion operator, so that a rational can
657be used in the same Boolean contexts as the built-in numeric types, in December
6582005.
659
660<p>Revised December 27, 2005</p>
661
662<p>© Copyright Paul Moore 1999-2001; &copy; Daryle Walker 2005. Permission to
663copy, use, modify, sell and distribute this document is granted provided this
664copyright notice appears in all copies. This document is provided &quot;as
665is&quot; without express or implied warranty, and with no claim as to its
666suitability for any purpose.</p>
667</body>
668</html>
Note: See TracBrowser for help on using the repository browser.