commit af8e30a7fbdc355b618c8eebbbdc11c7e013ccd9 Author: Beman Dawes Date: Fri Jul 7 16:04:40 2000 +0000 This commit was generated by cvs2svn to compensate for changes in r4, which included commits to RCS files with non-trunk default branches. [SVN r7621] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/include/boost/rational.hpp b/include/boost/rational.hpp new file mode 100644 index 0000000..ece5b36 --- /dev/null +++ b/include/boost/rational.hpp @@ -0,0 +1,321 @@ +// Boost rational.hpp header file ------------------------------------------// + +// (C) Copyright Paul Moore 1999. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or +// implied warranty, and with no claim as to its suitability for any purpose. + +// See http://www.boost.org for most recent version including documentation. + +// Credits: +// Thanks to the boost mailing list in general for useful comments. +// Particular contributions included: +// Andrew D Jewell, for reminding me to take care to avoid overflow +// Ed Brey, for many comments, including picking up on some dreadful typos + +// Revision History +// 23 Jun 00 Incorporate changes from Mark Rodgers for Borland C++ +// 22 Jun 00 Change _MSC_VER to BOOST_MSVC so other compilers are not +// affected (Beman Dawes) +// 6 Mar 00 Fix operator-= normalization, #include (Jens Maurer) +// 14 Dec 99 Modifications based on comments from the boost list +// 09 Dec 99 Initial Version (Paul Moore) + +#ifndef BOOST_RATIONAL_HPP +#define BOOST_RATIONAL_HPP + +#include // for std::istream and std::ostream +#include // for std::domain_error +#include // for std::string implicit constructor +#include // for boost::addable etc +#include // for std::abs +#include // for BOOST_NO_STDC_NAMESPACE, BOOST_MSVC + +namespace boost { + +template +IntType gcd(IntType n, IntType m) +{ + while (m) { + IntType r = n % m; + if (r < 0) + r += m; + + n = m; + m = r; + } + + return n; +} + +template +IntType lcm(IntType n, IntType m) +{ + n /= gcd(n, m); + n *= m; + return n; +} + +class bad_rational : public std::domain_error +{ +public: + explicit bad_rational() : std::domain_error("bad rational: zero denominator") {} +}; + +// The following is an awful lot of code to implement a 1-line abs() function. + +#ifdef BOOST_MSVC +// This is a gross hack. MS Visual C++ has utterly broken namespace reslution +// rules. Basically, the call to abs(int) in abs(rational) below will not find +// ::abs(). So the only way we have of fixing this is to reimplement std::abs +// in the boost:: namespace! In practice, this is a relatively minor bit of +// pollution, so we should be OK. + +inline int abs(int n) { return ::abs(n); } +inline long abs(long n) { return ::labs(n); } + +#endif + +template +class rational; + +template +rational abs(const rational& r); + +template +class rational : + less_than_comparable < rational >, + equality_comparable < rational >, + addable < rational >, + subtractable < rational >, + multipliable < rational >, + dividable < rational >, + incrementable < rational >, + decrementable < rational > +{ + typedef IntType int_type; + +public: + rational(IntType n = 0) : num(n), den(1) {} + rational(IntType n, IntType d) : num(n), den(d) { normalize(); } + + // Default copy constructor and assignment are fine + + // Assign in place + rational& assign(IntType n, IntType d); + + // Access to representation + IntType numerator() const { return num; } + IntType denominator() const { return den; } + + // Arithmetic assignment operators + rational& operator+= (const rational& r); + rational& operator-= (const rational& r); + rational& operator*= (const rational& r); + rational& operator/= (const rational& r); + + // Increment and decrement + const rational& operator++(); + const rational& operator--(); + + // Comparison operators + bool operator< (const rational& r) const; + bool operator== (const rational& r) const; + +private: + // Implementation - numerator and denominator (normalized). + // Other possibilities - separate whole-part, or sign, fields? + IntType num; + IntType den; + + // Representation note: Fractions are kept in normalized form at all + // times. normalized form is defined as gcd(num,den) == 1 and den > 0. + // In particular, note that the implementation of abs() below relies + // on den always being positive. + void normalize(); +}; + +// Assign in place +template +inline rational& rational::assign(IntType n, IntType d) +{ + num = n; + den = d; + normalize(); + return *this; +} + +// Unary plus and minus +template +inline rational operator+ (const rational& r) +{ + return r; +} + +template +inline rational operator- (const rational& r) +{ + return rational(-r.numerator(), r.denominator()); +} + +// Arithmetic assignment operators +template +rational& rational::operator+= (const rational& r) +{ + // This calculation avoids overflow + IntType new_den = lcm(den, r.den); + num = num * (new_den / den) + r.num * (new_den / r.den); + den = new_den; + normalize(); // Example where this is needed: 1/2 + 1/2 + return *this; +} + +template +rational& rational::operator-= (const rational& r) +{ + // This calculation avoids overflow + IntType new_den = lcm(den, r.den); + num = num * (new_den / den) - r.num * (new_den / r.den); + den = new_den; + normalize(); // Example where this is needed: 1/2 + 1/2 + return *this; +} + +template +rational& rational::operator*= (const rational& r) +{ + // Avoid overflow and preserve normalization + IntType gcd1 = gcd(num, r.den); + IntType gcd2 = gcd(r.num, den); + num = (num/gcd1) * (r.num/gcd2); + den = (den/gcd2) * (r.den/gcd1); + return *this; +} + +template +rational& rational::operator/= (const rational& r) +{ + // Avoid overflow and preserve normalization + IntType gcd1 = gcd(num, r.num); + IntType gcd2 = gcd(r.den, den); + num = (num/gcd1) * (r.den/gcd2); + den = (den/gcd2) * (r.num/gcd1); + return *this; +} + +// Increment and decrement +template +inline const rational& rational::operator++() +{ + // This can never denormalise the fraction + num += den; + return *this; +} + +template +inline const rational& rational::operator--() +{ + // This can never denormalise the fraction + num -= den; + return *this; +} + +// Comparison operators +template +bool rational::operator< (const rational& r) const +{ + // Avoid overflow + IntType gcd1 = gcd(num, r.num); + IntType gcd2 = gcd(r.den, den); + return (num/gcd1) * (r.den/gcd2) < (den/gcd2) * (r.num/gcd1); +} + +template +inline bool rational::operator== (const rational& r) const +{ + return ((num == r.num) && (den == r.den)); +} + +// Normalisation +template +void rational::normalize() +{ + if (den == 0) + throw bad_rational(); + + IntType g = gcd(num, den); + + num /= g; + den /= g; + + if (den < 0) { + num = -num; + den = -den; + } +} + +// Input and output +template +std::istream& operator>> (std::istream& is, rational& r) +{ + IntType n = 0, d = 1; + char c = 0; + + is >> n; + c = is.get(); + + if (c == '/') + is >> d; + else + is.putback(c); + + if (is) + r.assign(n, d); + + return is; +} + +// Add manipulators for output format? +template +std::ostream& operator<< (std::ostream& os, const rational& r) +{ + os << r.numerator() << '/' << r.denominator(); + return os; +} + +// Type conversion +template +inline T rational_cast(const rational& src) +{ + return static_cast(src.numerator())/src.denominator(); +} + +#ifdef __GNUC__ +// Workaround for a bug in gcc 2.95.2 - using statements at function scope are +// silently ignored - to get around this, we need to include std::abs at +// namespace scope. + +using std::abs; +#endif + +template +inline rational abs(const rational& r) +{ +#ifndef BOOST_NO_STDC_NAMESPACE + // We want to use abs() unadorned below, so that if IntType is a + // user-defined type, the name lookup rules will work to find an + // appropriate abs() defined for IntType. + // + // We protect this with BOOST_NO_STDC_NAMESPACE, as some compilers + // don't put abs into std:: (notably MS Visual C++) and so we can't + // "use" it from there. + using std::abs; +#endif + // Note that with normalized fractions, the denominator is always positive. + return rational(abs(r.numerator()), r.denominator()); +} + +} // namespace boost + +#endif // BOOST_RATIONAL_HPP + diff --git a/rational_example.cpp b/rational_example.cpp new file mode 100644 index 0000000..b7c99e3 --- /dev/null +++ b/rational_example.cpp @@ -0,0 +1,103 @@ +// smart pointer test program ----------------------------------------------// + +// (C) Copyright Paul Moore 1999. Permission to copy, use, modify, sell +// and distribute this software is granted provided this copyright notice +// appears in all copies. This software is provided "as is" without express or +// implied warranty, and with no claim as to its suitability for any purpose. + +// Revision History +// 14 Dec 99 Initial version + +#include +#include +#include +#ifndef __MINGW32__ +#include +#else +#include +#endif +#include +#include + +using std::cout; +using std::endl; +using boost::rational; + +#ifdef _MSC_VER +// This is a nasty hack, required because MSVC does not implement "Koenig +// Lookup". Basically, if I call abs(r), the C++ standard says that the +// compiler should look for a definition of abs in the namespace which +// contains r's class (in this case boost) - among other places. + +// Koenig Lookup is a relatively recent feature, and other compilers may not +// implement it yet. If so, try including this line. + +using boost::abs; +#endif + +int main () +{ + rational half(1,2); + rational one(1); + rational two(2); + + // Some basic checks + assert(half.numerator() == 1); + assert(half.denominator() == 2); + assert(boost::rational_cast(half) == 0.5); + + // Arithmetic + assert(half + half == one); + assert(one - half == half); + assert(two * half == one); + assert(one / half == two); + + // With conversions to integer + assert(half+half == 1); + assert(2 * half == one); + assert(2 * half == 1); + assert(one / half == 2); + assert(1 / half == 2); + + // Sign handling + rational minus_half(-1,2); + assert(-half == minus_half); + assert(abs(minus_half) == half); + + // Do we avoid overflow? +#ifndef __MINGW32__ + int maxint = std::numeric_limits::max(); +#else + int maxint = INT_MAX; +#endif + rational big(maxint, 2); + assert(2 * big == maxint); + + // Print some of the above results + cout << half << "+" << half << "=" << one << endl; + cout << one << "-" << half << "=" << half << endl; + cout << two << "*" << half << "=" << one << endl; + cout << one << "/" << half << "=" << two << endl; + cout << "abs(" << minus_half << ")=" << half << endl; + cout << "2 * " << big << "=" << maxint + << " (rational: " << rational(maxint) << ")" << endl; + + // Some extras + rational pi(22,7); + cout << "pi = " << boost::rational_cast(pi) << " (nearly)" << endl; + + // Exception handling + try { + rational r; // Forgot to initialise - set to 0 + r = 1/r; // Boom! + } + catch (const boost::bad_rational &e) { + cout << "Bad rational, as expected: " << e.what() << endl; + } + catch (...) { + cout << "Wrong exception raised!" << endl; + } + + return 0; +} +