fraction.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 262 行

C
262
字号
/* Fraction.c -- implementation of fractions

        THIS SOFTWARE FITS THE DESCRIPTION IN THE U.S. COPYRIGHT ACT OF A
        "UNITED STATES GOVERNMENT WORK".  IT WAS WRITTEN AS A PART OF THE
        AUTHOR'S OFFICIAL DUTIES AS A GOVERNMENT EMPLOYEE.  THIS MEANS IT
        CANNOT BE COPYRIGHTED.  THIS SOFTWARE IS FREELY AVAILABLE TO THE
        PUBLIC FOR USE WITHOUT A COPYRIGHT NOTICE, AND THERE ARE NO
        RESTRICTIONS ON ITS USE, NOW OR SUBSEQUENTLY.

Author:
        K. E. Gorlen
        Bg. 12A, Rm. 2033
        Computer Systems Laboratory
        Division of Computer Research and Technology
        National Institutes of Health
        Bethesda, Maryland 20892
        Phone: (301) 496-1111
        uucp: uunet!nih-csl!kgorlen
        Internet: kgorlen@alw.nih.gov
        December, 1985

Function:
        
Implements a fraction as two integers, the numerator and the
denominator.  WARNING -- this implementation is not suitable for serious
numeric applications.  Reference: Knuth, "The Art of Computer
Programming", Vol. 2, Section 4.5.

log:    FRACTION.C $
Revision 1.1  90/05/20  04:19:40  Anthony_Scian
.

 * Revision 3.0  90/05/20  00:19:38  kgorlen
 * Release for 1st edition.
 * 
*/

#include "Fraction.h"
#include <libc.h>
#include <math.h>
#include "nihclIO.h"

#define THIS    Fraction
#define BASE    Object
#define BASE_CLASSES BASE::desc()
#define MEMBER_CLASSES
#define VIRTUAL_BASE_CLASSES Object::desc()

DEFINE_CLASS(Fraction,1,"header: D:\PLUSTEST\regress\nih\x:\groupdir\cproj\plustest\regress\nih\rcs\FRACTION.C 1.1 90/05/20 04:19:40 Anthony_Scian Exp Locker: NT_Test_Machine $",NULL,NULL);

extern const int NIHCL_ZERODEN,NIHCL_FCTNOV,NIHCL_FCTNUN;

int Fraction::gcd(int uu, int vv)
/* gcd -- binary greatest common divisor algorithm

Algorithm B, p. 321.

*/
{
        register int u=ABS(uu), v=ABS(vv);
        register int k=0;
        register int t;
        if (u == 0) return v;
        if (v == 0) return u;
        while ((u&1) == 0 && (v&1) == 0) { u>>=1; v>>=1; k++; }
        if (u&1) { t = -v; goto B4; }
        else t = u;
        do {
B3:             t/=2;
B4:             if ((t&1) == 0) goto B3;
                if (t>0) u = t;
                else v = -t;
                t = u-v;
        } while (t != 0);
        return u<<k;
}

Fraction::Fraction(int num, int den)
/*
        Construct a Fraction from the specified numerator and denominator.
*/
{
        n = num; d = den;
        if (d == 0) setError(NIHCL_ZERODEN,DEFAULT,this,num,den);
        if (n == 0) { d = 1; return; }
        if (d < 0) { n = -n; d = -d; }
        reduce();
}

inline char* gcvt(double val, int dig, char* buf)
{
        sprintf(buf,"%*.lg",dig,val);
        return buf;
}

Fraction::Fraction(double x)
/*
        Construct a Fraction from a double.
*/
{
        char buf[20];
        int exp;
        double m = frexp(x,&exp);
        register int k;
        if (exp>=0) {
                if (exp > (sizeof(int)*8-2)) setError(NIHCL_FCTNOV,DEFAULT,this,gcvt(x,20,buf));
                k = (sizeof(int)*8-2);
        }
        else {
                k = exp+(sizeof(int)*8-2);
                if (k < 0) setError(NIHCL_FCTNUN,DEFAULT,this,gcvt(x,20,buf));
        }
        n = (int)(m*(1<<k));
        d = 1 << (k-exp);
        reduce();
}

void Fraction::parseFraction(istream& strm)
/*
        Read a Fraction from an istream.
*/
{
        n = 0; d = 1;
        strm >> n;
        char slash;
        strm >> slash;
        if (slash == '/') {
                strm >> d;
                reduce();
        }
        else strm.putback(slash);
}

Fraction::Fraction(istream& strm)       { parseFraction(strm); }

void Fraction::reduce()
/*
        Reduce a Fraction to lowest terms by dividing the numerator and
        denominator by their gcd.
*/
{
        register int d1 = gcd(n,d);
        if (d1 == 1) return;
        n /= d1; d /= d1;
}

Fraction operator+(const Fraction& u, const Fraction& v)
{
        register int d1 = Fraction::gcd(u.d,v.d);
        if (d1 == 1) return Fraction(u.n*v.d+u.d*v.n, u.d*v.d, 0);
        register int t = u.n*(v.d/d1) + v.n*(u.d/d1);
        register int d2 = Fraction::gcd(t,d1);
        return Fraction(t/d2, (u.d/d1)*(v.d/d2), 0);
}

Fraction operator-(const Fraction& u, const Fraction& v)
{
        register int d1 = Fraction::gcd(u.d,v.d);
        if (d1 == 1) return Fraction(u.n*v.d-u.d*v.n, u.d*v.d, 0);
        register int t = u.n*(v.d/d1) - v.n*(u.d/d1);
        register int d2 = Fraction::gcd(t,d1);
        return Fraction(t/d2, (u.d/d1)*(v.d/d2), 0);
}

bool operator<(const Fraction& u, const Fraction& v)
{
        register int d1 = Fraction::gcd(u.d,v.d);
        if (d1 == 1) return u.n*v.d < u.d*v.n;
        return u.n*(v.d/d1) < v.n*(u.d/d1);
}

bool operator<=(const Fraction& u, const Fraction& v)
{
        if (u==v) return YES;
        return u<v;
}

Fraction operator*(const Fraction& u, const Fraction& v)
{
        register int d1 = Fraction::gcd(u.n, v.d);
        register int d2 = Fraction::gcd(u.d, v.n);
        return Fraction((u.n/d1)*(v.n/d2), (u.d/d2)*(v.d/d1), 0);
}

Fraction operator/(const Fraction& u, const Fraction& v)
{
        if (v.n < 0) return u*Fraction(-v.d,-v.n, 0);
        return u*Fraction(v.d,v.n,0);
}

bool Fraction::between(const Fraction& min, const Fraction& max) const
/*
        Return YES if this Fraction is <= to max and >= to min.
*/
{
        return *this >= min && *this <= max;
}

Fraction Fraction::max(const Fraction& f) const
{
        if (f < *this) return *this;
        else return f;
}

Fraction Fraction::min(const Fraction& f) const
{
        if (f > *this) return *this;
        else return f;
}

unsigned Fraction::hash() const { return n^d; }

bool Fraction::isEqual(const Object& ob) const
{
        return ob.isSpecies(classDesc) && *this==castdown(ob);
}

const Class* Fraction::species() const { return &classDesc; }

int Fraction::compare(const Object& ob) const
{
        assertArgSpecies(ob,classDesc,"compare");
        const Fraction& f = castdown(ob);
        if (*this == f) return 0;
        if (*this < f) return -1;
        return 1;
}

void Fraction::deepenShallowCopy()      {}

void Fraction::printOn(ostream& strm) const
{
        if (n == 0 || d == 1) strm << n;
        else strm << n << '/' << d;
}

void Fraction::scanFrom(istream& strm)  { parseFraction(strm); }

Fraction::Fraction(OIOin& strm)
        : BASE(strm)
{
        strm >> n >> d;
}

void Fraction::storer(OIOout& strm) const
{
        BASE::storer(strm);
        strm << n << d;
}

Fraction::Fraction(OIOifd& fd)
        : BASE(fd)
{
        fd >> n >> d;
}

void Fraction::storer(OIOofd& fd) const
{
        BASE::storer(fd);
        fd << n << d;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?