LoginSignup
5
1

More than 3 years have passed since last update.

C++で分数class

Last updated at Posted at 2019-07-25

競技プログラミング用にC++で分数を扱えるクラスを作りました
(処理速度は考えてません

参考
- http://blog.livedoor.jp/add20/archives/2285655.html
- http://www002.upp.so-net.ne.jp/ys_oota/effec/chapter4.htm

コードは下記(# コード)

  • 2019/07/25 var.1.0.0
  • 2019/07/27 var.1.1.0
    • swap()などをstdを使用するように変更
    • dight()を削除
    • Fraction operator+(long long b);などを削除
    • 四則演算の順序が逆でもできるように変更

内容

Fraction a(2, 5);

で、2/5という分数のクラスを作成することができます

また

Fraction a(3);

で、3( = 3/1)を作成できます

一応、四則演算等は使用できます

toString()でStringに、toLongDouble()でlong doubleに変換できます

メモ

  1. 四則演算の相手がint型であっても、コンパイラが自動的にintをFractionに変換してくれる
  2. 四則演算の順序について(aはFraction型)
Fraction operator*(const Fraction& b);

  だと、a * 2しかできないが、

friend const Fraction operator*(const Fraction& a, const Fraction& b);

  にして、色々すると、2 * aもできるようになる

コード

Fraction.h

Fraction.h
#include <string>

#pragma once
class Fraction
{
private:
    long long numer;    // 分子
    long long denom;    // 分母

    friend const bool operator==(const Fraction& a, const Fraction& b);
    friend const bool operator!=(const Fraction& a, const Fraction& b);
    friend const bool operator>=(const Fraction& a, const Fraction& b);
    friend const bool operator<=(const Fraction& a, const Fraction& b);
    friend const bool operator>(const Fraction& a, const Fraction& b);
    friend const bool operator<(const Fraction& a, const Fraction& b);

    friend const Fraction operator+(const Fraction& a, const Fraction& b);
    friend const Fraction operator-(const Fraction& a, const Fraction& b);
    friend const Fraction operator*(const Fraction& a, const Fraction& b);
    friend const Fraction operator/(const Fraction& a, const Fraction& b);

public:
    Fraction();
    Fraction(long long);
    Fraction(long long, long long);
    Fraction(const Fraction&);

    void set(long long, long long);
    void set(const Fraction&);
    void setNumer(long long);
    void setDenom(long long);

    long long getNumer();
    long long getDenom();

    static long long gcd(long long, long long); // 最大公約数
    static long long lcm(long long, long long); // 最小公倍数
    void normal();  // 約分

    std::string toString();
    long double toLongDouble();

    bool equals(const Fraction&) const;
    long long compare(const Fraction&) const;

    Fraction& operator=(const Fraction& b);

    Fraction& operator+=(const Fraction& b);
    Fraction& operator-=(const Fraction& b);
    Fraction& operator*=(const Fraction& b);
    Fraction& operator/=(const Fraction& b);

    Fraction operator+();
    Fraction operator-();

    Fraction& operator++();
    Fraction  operator++(int);

    Fraction& operator--();
    Fraction  operator--(int);
};

Fraction.cpp

Fraction.cpp
#include "Fraction.h"

#include <utility>

long long Fraction::gcd(long long a, long long b)
{
    a = abs(a);
    b = abs(b);
    if (a < b) std::swap(a, b);

    long long tmp;
    while (b != 0) {
        tmp = b;
        b = a % b;
        a = tmp;
    }

    return a;
}
long long Fraction::lcm(long long a, long long b)
{
    a = abs(a);
    b = abs(b);
    if (a > b) std::swap(a, b);

    if (a == 1) return b;

    long long i = a;
    while (i % b != 0)
    {
        i += a;
    }
    return i;
}

Fraction::Fraction()
{
    set(0, 1);
}
Fraction::Fraction(long long n)
{
    set(n, 1);
}
Fraction::Fraction(long long numer, long long denom)
{
    set(numer, denom);
}
Fraction::Fraction(const Fraction& b)
{
    set(b);
}

void Fraction::set(long long numer, long long denom)
{
    this->numer = numer;
    this->denom = denom;
    normal();
}
void Fraction::set(const Fraction& b)
{
    this->numer = b.numer;
    this->denom = b.denom;
}
void Fraction::setNumer(long long numer)
{
    this->numer = numer;
    normal();
}
void Fraction::setDenom(long long denom)
{
    this->denom = denom;
    normal();
}

inline long long Fraction::getNumer()
{
    return numer;
}
inline long long Fraction::getDenom()
{
    return denom;
}

void Fraction::normal()
{
    long long gcd = this->gcd(getNumer(), getDenom());

    if (gcd == 1)
    {
        // 分母は常に正
        if (denom < 0)
        {
            numer *= -1;
            denom *= -1;
        }

        return;
    }

    long long numer = getNumer() / gcd;
    long long denom = getDenom() / gcd;

    // 分母は常に正
    if (denom < 0)
    {
        numer *= -1;
        denom *= -1;
    }

    set(numer, denom);
}

std::string Fraction::toString()
{
    std::string str = "";

    if (getDenom() == 1)
        str = std::to_string(getNumer());
    else
        str = std::to_string(getNumer()) + "/" + std::to_string(getDenom());

    return str;
}
long double Fraction::toLongDouble()
{
    return (long double)getNumer() / getDenom();
}

bool Fraction::equals(const Fraction& b) const {
    return numer == b.numer && denom == b.denom;
}
long long Fraction::compare(const Fraction& b) const  {
    long long lcm = this->lcm(denom, b.denom);

    return (lcm / denom) * numer - (lcm / b.denom) * b.numer;
}

const bool operator==(const Fraction& a, const Fraction& b) { return  a.equals(b); }
const bool operator!=(const Fraction& a, const Fraction& b) { return !a.equals(b); }
const bool operator>=(const Fraction& a, const Fraction& b) { return a.compare(b) >= 0; }
const bool operator<=(const Fraction& a, const Fraction& b) { return a.compare(b) <= 0; }
const bool operator>(const Fraction& a, const Fraction& b) { return a.compare(b) > 0; }
const bool operator<(const Fraction& a, const Fraction& b) { return a.compare(b) < 0; }

Fraction& Fraction::operator=(const Fraction& b) {
    this->set(b);

    return *this;
}

const Fraction operator+(const Fraction& a, const Fraction& b) {
    long long lcm = Fraction::lcm(a.denom, b.denom);
    long long numer = a.numer * (lcm / a.denom) + b.numer * (lcm / b.denom);

    return Fraction(numer, lcm);
}
const Fraction operator-(const Fraction& a, const Fraction& b) {
    return operator+(a, Fraction(-b.numer, b.denom));
}
const Fraction operator*(const Fraction& a, const Fraction& b) {
    long long gcd = Fraction::gcd(a.numer, b.denom);
    long long numer = a.numer / gcd;
    long long denom = b.denom / gcd;

    gcd = Fraction::gcd(b.numer, a.denom);
    numer *= b.numer / gcd;
    denom *= a.denom / gcd;

    return Fraction(numer, denom);
}
const Fraction operator/(const Fraction& a, const Fraction& b) {
    return operator*(a, Fraction(b.denom, b.numer));
}

Fraction& Fraction::operator+=(const Fraction& b) { return *this = *this + b; }
Fraction& Fraction::operator-=(const Fraction& b) { return *this = *this - b; }
Fraction& Fraction::operator*=(const Fraction& b) { return *this = *this * b; }
Fraction& Fraction::operator/=(const Fraction& b) { return *this = *this / b; }

Fraction Fraction::operator+() { return Fraction(this->numer, this->denom); };
Fraction Fraction::operator-() { return Fraction(-(this->numer), this->denom); };

Fraction& Fraction::operator++() { return *this += 1; }
Fraction& Fraction::operator--() { return *this += -1; }
Fraction Fraction::operator++(int) {
    Fraction tmp = *this;
    *this += 1;
    return tmp;
}
Fraction Fraction::operator--(int) {
    Fraction tmp = *this;
    *this += -1;
    return tmp;
}
5
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1