分数类 frac

报喜,分数类研制成功!

正式完结散花!简单测试了下,基本没有 bug。

本代码遵循 CC-BY-NC-ND (署名-非商业使用-禁止演绎)协议。

代码:frac.h

#pragma once

#include <iostream>
#include <utility>
#include <cmath>

#if __cplusplus >= 202002L

#include <format> 

#endif

constexpr long long gcd(long long a, long long b) {
  return !b ? a : gcd(b, a % b);
}

constexpr long long lcm(long long a, long long b) {
  return a * b / gcd(a, b);
}

template<typename _Ty1 = int, typename _Ty2 = int>
class frac {
private:
  _Ty1 numerator;
  _Ty2 denominator;

public:
  static constexpr auto cannot{ static_cast<unsigned long long>(-1) };

  frac() {
    numerator = denominator = 0;
  }

  frac(long long _num, long long _den) {
    numerator = _num;
    denominator = _den;
  }

  frac(long long _number) {
    numerator = _number;
    denominator = 1;
  }

  frac &operator=(frac _Right) {
    numerator = _Right.numerator;
    denominator = _Right.denominator;
    return *this;
  }

  frac &operator=(long long _number) {
    numerator = _number;
    denominator = 1;
    return *this;
  }

  friend void reduction(frac &_Left, frac &_Right) {
    long long lcmValue = lcm(_Left.denominator, _Right.denominator);
    _Left.numerator *= lcmValue / _Left.denominator, _Left.denominator = lcmValue;
    _Right.numerator *= lcmValue / _Right.denominator, _Right.denominator = lcmValue;
  }

  bool check() {
    long long gcdValue = gcd(numerator, denominator);
    if (gcdValue == 1) {
      return 1;
    }
    numerator /= gcdValue, denominator /= gcdValue;
    return 0;
  }

  friend frac operator+(frac _Left, frac _Right) {
    reduction(_Left, _Right);
    frac _Answer(_Left.numerator + _Right.numerator, _Left.denominator);
    _Answer.check();
    return _Answer;
  }

  friend frac operator-(frac _Left, frac _Right) {
    reduction(_Left, _Right);
    frac _Answer(_Left.numerator - _Right.numerator, _Left.denominator);
    _Answer.check();
    return _Answer;
  }

  friend frac operator*(frac _Left, frac _Right) {
    frac _Answer(_Left.numerator * _Right.numerator, _Left.denominator * _Right.denominator);
    _Answer.check();
    return _Answer;
  }

  friend frac operator/(frac _Left, frac _Right) {
    return _Left * frac(_Right.denominator, _Right.numerator);
  }


  frac &operator+=(frac _Right) {
    *this = *this + _Right;
    return *this;
  }

  frac &operator-=(frac _Right) {
    *this = *this - _Right;
    return *this;
  }

  frac &operator*=(frac _Right) {
    *this = *this * _Right;
    return *this;
  }

  frac &operator/=(frac _Right) {
    *this = *this / _Right;
    return *this;
  }

  constexpr long long toInt() {
    return numerator % denominator == 0 ? numerator / denominator : cannot;
  }

  constexpr float toFloat() {
    return 1.0f * numerator / denominator;
  }

  constexpr double toDouble() {
    return 1.0 * numerator / denominator;
  }

  constexpr long double toLongDouble() {
    if (sizeof(long double) == sizeof(double)) {
      return this->toDouble();
    }
    return 1.0L * numerator / denominator;
  }

  constexpr long long getNum() {
    return numerator;
  }

  constexpr long long getDen() {
    return denominator;
  }
};

bool _none = 0, _mixed = 0;

struct _NoLine {
  void operator()(std::ostream &out) {
    _none = 1;
  }
} none;

struct _Mixed {
  void operator()(std::ostream &out) {
    _mixed = 1;
  }
} mixed;

template<typename _Ty1 = int, typename _Ty2 = int>
std::istream &operator>>(std::istream &in, frac<_Ty1, _Ty2> &__x) {
  long long _num, _den;
  in >> _num >> _den;
  __x = frac<_Ty1, _Ty2>(_num, _den);
  __x.check();
  return in;
}

std::ostream &operator<<(std::ostream &out, _NoLine __n) {
  _none = 1;
  return out;
}

std::ostream &operator<<(std::ostream &out, _Mixed __n) {
  _mixed = 1;
  return out;
}

template<typename _Ty1 = long long, typename _Ty2 = long long>
std::ostream &operator<<(std::ostream &out, frac<_Ty1, _Ty2> __x) {
  __x.check();
#if __cplusplus >= 202002L
  if (_mixed) {
    if (__x.getNum() % __x.getDen() == 0) {
      out << __x.getNum() / __x.getDen();
    } else {
      long long s = 0;
      for (; __x.getNum() > __x.getDen(); __x -= frac(__x.getDen(), __x.getDen())) {
        ++s;
      }
      if (s == 0) {
        out << std::format("{}/{}", __x.getNum(), __x.getDen());
      } else {
        out << std::format("{} {}/{}", s, __x.getNum(), __x.getDen());
      }
    }
    _mixed = 0;
  } else if (_none) {
    out << std::format("{} {}", __x.getNum(), __x.getDen());
    _none = 0;
  } else {
    out << std::format("{}/{}", __x.getNum(), __x.getDen());
  }
#else
  if (_mixed) {
    if (__x.getNum() % __x.getDen() == 0) {
      out << __x.getNum() / __x.getDen();
    } else {
      long long s = 0;
      for (; __x.getNum() > __x.getDen(); __x -= frac<_Ty1, _Ty2>(__x.getDen(), __x.getDen())) {
        ++s;
      }
      if (s == 0) {
        out << __x.getNum() << '/' << __x.getDen();
      } else {
        out << s << ' ' << __x.getNum() << '/' << __x.getDen();
      }
    }
    _mixed = 0;
  } else if (_none) {
    out << __x.getNum() << ' ' << __x.getDen();
    _none = 0;
  } else {
    if (__x.toInt() != frac<_Ty1, _Ty2>::cannot) {
      out << __x.toInt();
    } else {
      out << __x.getNum() << '/' <<  __x.getDen();
    }
  }
#endif
  return out;
}

主函数代码

#include "frac.h"
#include <iostream>

using namespace std;

int main() {
  frac<int, int> a(7, 9);
  cout << a + frac<int, int>(4, 18) << '\n';
  return 0;
}

输出

1
posted @ 2023-10-15 17:18  haokee  阅读(36)  评论(0)    收藏  举报