封装Fraction-分数类(C++)
Fraction 分数类
默认假分数,可自行修改
由于concept的原因
template <typename T>
concept is_float_v = std::is_floating_point<T>::value;
template <typename T>
concept arithmetic = std::is_arithmetic<T>::value;
需要c++20,若要c++17可用enable来替代
前两个define是是否总是约分和是否检查上溢的开关
Code
// C++20
#include <cassert>
#include <cmath>
#include <concepts>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
//#define Always_Reduce
//#define Check_Overflow
#ifdef Check_Overflow
#define Check_Add_Overflow(a, b) assert(((a) + (b) - (b)) == (a))
#define Check_Mul_Overflow(a, b) assert(((a) * (b) / (b)) == (a))
#else
#define Check_Add_Overflow(a, b) 114514
#define Check_Mul_Overflow(a, b) 114514
#endif
template <std::integral T>
inline T gcd(T a, T b) {
assert((a >= 0) && (b >= 0));
if (a == 0) return b;
if (b == 0) return a;
T r;
while (r = a % b) a = b, b = r;
return b;
}
template <typename T>
concept is_float_v = std::is_floating_point<T>::value;
template <typename T>
concept arithmetic = std::is_arithmetic<T>::value;
class Fraction {
private:
bool m_minus;
long long m_numerator;
long long m_denominator;
public:
Fraction() : m_minus(false), m_numerator(0), m_denominator(1) {}
Fraction(long long numerator, long long denominator)
: m_numerator(std::abs(numerator)), m_denominator(std::abs(denominator)), m_minus((numerator < 0) ^ (denominator < 0)) {
assert(m_denominator != 0);
reduce();
}
explicit Fraction(std::string x) {
try {
std::stold(x);
} catch (std::exception e) {
std::stringstream msg;
msg << "The argument \"std::string x\"(" << x << ") is invalid";
throw std::runtime_error(msg.str());
}
std::stringstream number;
int digits = 0;
bool flag = false;
int len = x.size();
for (int i = 0; i < len; ++i) {
const auto& c = x[i];
if (i == 0) {
m_minus = (c == '-');
if (c == '-') continue;
}
if (c == '.') {
flag = true;
continue;
}
number << c;
if (flag) ++digits;
}
m_numerator = std::stoll(number.str());
m_denominator = 1;
long long base = 10;
for (; digits; digits >>= 1, base *= base)
if (digits & 1) m_denominator *= base;
reduce();
}
Fraction(const Fraction& frac) : m_numerator(frac.m_numerator), m_denominator(frac.m_denominator), m_minus(frac.m_minus) {}
template <is_float_v T>
Fraction(T x) : Fraction(std::to_string(x)) {}
template <std::integral T>
Fraction(T x) : m_minus(x < 0), m_numerator(std::abs(x)), m_denominator(1) {}
~Fraction() {}
void set(long long numerator, long long denominator) {
m_minus = (numerator < 0) ^ (denominator < 0);
m_numerator = std::abs(numerator), m_denominator = std::abs(denominator);
reduce();
}
void set_numerator(long long numerator) {
m_minus = m_minus ^ (numerator < 0);
m_numerator = std::abs(numerator);
reduce();
}
void set_Denominator(long long denominator) {
assert(denominator != 0);
m_minus = m_minus ^ (denominator < 0);
m_denominator = std::abs(denominator);
reduce();
}
void set_sign(bool flag) { m_minus = m_minus ^ (flag == 0); }
Fraction operator-() const { return Fraction((m_minus ? 1 : -1) * m_numerator, m_denominator); }
Fraction operator~() const { return Fraction((m_minus ? -1 : 1) * m_denominator, m_numerator); }
Fraction operator+(const Fraction& frac) const {
long long mu = m_denominator * frac.DenominatorPart();
long long t1 = m_numerator * frac.DenominatorPart(), t2 = frac.NumeratorPart() * m_denominator;
Check_Add_Overflow(t1, t2);
Check_Mul_Overflow(m_numerator, frac.DenominatorPart());
Check_Mul_Overflow(m_denominator, frac.NumeratorPart());
Check_Mul_Overflow(m_denominator, frac.DenominatorPart());
long long t = t1 + t2;
#ifdef Always_Reduce
long long g = std::abs(gcd(t, mu));
return Fraction(t / g, mu / g);
#endif
return Fraction(t, mu);
}
Fraction operator-(const Fraction& frac) { return (*this) + (-frac); }
Fraction operator*(const Fraction& frac) {
long long z = m_numerator * frac.NumeratorPart(), m = m_denominator * frac.DenominatorPart();
Check_Mul_Overflow(m_numerator, frac.NumeratorPart());
Check_Mul_Overflow(m_denominator, frac.DenominatorPart());
#ifdef Always_Reduce
long long g = gcd(z, m);
return Fraction((m_minus ^ (frac.SignPart() == 0) ? -1ll : 1ll) * z / g, m / g);
#endif
return Fraction((m_minus ^ (frac.SignPart() == 0) ? -1ll : 1ll) * z, m);
}
Fraction operator/(const Fraction& frac) { return (*this) * (~frac); }
Fraction& operator*=(const Fraction& frac) { return (*this) = (*this) * frac; }
Fraction& operator/=(const Fraction& frac) { return (*this) = (*this) / frac; }
Fraction& operator+=(const Fraction& frac) { return (*this) = (*this) + frac; }
Fraction& operator-=(const Fraction& frac) { return (*this) = (*this) - frac; }
template <arithmetic T>
friend Fraction& operator+(T x, const Fraction& frac) { return frac + x; }
template <arithmetic T>
friend Fraction& operator-(T x, const Fraction& frac) { return -(frac - x); }
template <arithmetic T>
friend Fraction& operator*(T x, const Fraction& frac) { return frac * x; }
template <arithmetic T>
friend Fraction& operator/(T x, const Fraction& frac) { return ~(frac / x); }
friend long long compare(const Fraction& a, const Fraction& b) {
long long t1 = a.SignPart() * a.NumeratorPart() * b.DenominatorPart();
long long t2 = b.SignPart() * b.NumeratorPart() * a.DenominatorPart();
Check_Add_Overflow(t1, t2);
Check_Mul_Overflow(a.NumeratorPart(), b.DenominatorPart());
Check_Mul_Overflow(b.NumeratorPart(), a.DenominatorPart());
return t1 - t2;
}
friend bool operator==(const Fraction& left, const Fraction& right) { return compare(left, right) == 0; }
friend bool operator!=(const Fraction& left, const Fraction& right) { return compare(left, right) != 0; }
friend bool operator>(const Fraction& left, const Fraction& right) { return compare(left, right) > 0; }
friend bool operator<(const Fraction& left, const Fraction& right) { return compare(left, right) < 0; }
friend bool operator>=(const Fraction& left, const Fraction& right) { return compare(left, right) >= 0; }
friend bool operator<=(const Fraction& left, const Fraction& right) { return compare(left, right) <= 0; }
[[nodiscard]] inline long long NumeratorPart() const { return m_numerator; }
[[nodiscard]] inline long long DenominatorPart() const { return m_denominator; }
[[nodiscard]] inline bool SignPart() const { return !m_minus; }
[[nodiscard]] long long IntegerPart() const { return m_numerator / m_denominator; }
[[nodiscard]] std::pair<long long, long long> FractionPart() const { return {m_numerator % m_denominator, m_denominator}; }
[[nodiscard]] float toFloat() const { return static_cast<float>(toLDouble()); }
[[nodiscard]] double toDouble() const { return static_cast<double>(toLDouble()); }
[[nodiscard]] long double toLDouble() const { return static_cast<long double>(m_minus ? -1.0 : 1.0) * m_numerator / m_denominator; }
friend std::ostream& operator<<(std::ostream& os, const Fraction& frac) {
if (frac.m_minus) os << '-';
os << frac.m_numerator << "/" << frac.m_denominator;
return os;
}
inline void reduce() {
#ifdef Always_Reduce
auto tmp = std::abs(gcd(m_numerator, m_denominator));
m_numerator /= tmp, m_denominator /= tmp;
#endif
}
};
Fraction pow(Fraction f, long long b) {
Fraction ret(1ll);
for (; b; b >>= 1, f = f * f)
if (b & 1) ret = f * ret;
return ret;
}
封装Fraction-分数类(C++)的更多相关文章
- Problem F: 分数类的类型转换
Description 封装一个分数类Fract,用来处理分数功能和运算,支持以下操作: 1. 构造:传入两个参数n和m,表示n/m:分数在构造时立即转化成最简分数. 2. show()函数:分数 ...
- Problem E: 分数类的输出
Problem E: 分数类的输出 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 2699 Solved: 1227[Submit][Status][ ...
- UVA 10288 Coupons---概率 && 分数类模板
题目链接: https://cn.vjudge.net/problem/UVA-10288 题目大意: 一种刮刮卡一共有n种图案,每张可刮出一个图案,收集n种就有奖,问平均情况下买多少张才能中奖?用最 ...
- 【作品】超实用C++分数类
引言 我们说,编程语言的精髓在于封装,而面向对象语言完胜面向过程语言的原因就是具有更好的可封装性,而C++就是这样的一种多范型语言,常用而复杂的工作完全不必在每一份源文件中重敲,就好像我们不需要自己手 ...
- OC2_分数类
// // Fraction.h // OC2_分数类 // // Created by zhangxueming on 15/6/10. // Copyright (c) 2015年 zhangxu ...
- 第十七周oj刷题——Problem B: 分数类的四则运算【C++】
Description 编写分数类Fraction,实现两个分数的加.减.乘和除四则运算.主函数已给定. Input 每行四个数,分别表示两个分数的分子和分母,以0 0 0 0 表示结束. Outpu ...
- java的分数类
概述 分数类在算法中非常重要, 而在java中不那么重要,java基础类库提供 了biginteger了,提供类似方式, package 组合数学; public class Fraction { p ...
- .NET3.5中JSON用法以及封装JsonUtils工具类
.NET3.5中JSON用法以及封装JsonUtils工具类 我们讲到JSON的简单使用,现在我们来研究如何进行封装微软提供的JSON基类,达到更加方便.简单.强大且重用性高的效果. 首先创建一个类 ...
- MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
随机推荐
- python之loggin模块与第三方模块
目录 logging模块详解 第三方模块 openpyxl模块 logging模块详解 主要组成部分 logger对象,用于产生日志 # 第一步,创建logger对象 logger = logging ...
- windows和linux系统下测试端口连通性的命令
0. ping 1. telnet 2. ssh 3. curl 4. wget 5. tcping 6. 总结 本文地址: https://www.cnblogs.com/hchengmx/p/12 ...
- iPhone x 的区别
最近入手两台iPhone x, 均从官网购买,两台分别是2017年和2018年生产,对比了一下,两台还有是一些差别: 首先苹果X使用起来还是非常爽的,没有HOME键,明显比按HOME键方便,因为按HO ...
- generatorConfig.xml自动生成实体类,dao和xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration ...
- 高级web网页人脸识别tracking.js
what?你没有看错,强大的JavaScript也可以实现人脸识别功能.小编精心整理了一个人脸识别的JavaScript库(tracking.js),通过这篇文章,你可以了解到如何在网页中实现一个人脸 ...
- Vue.js与Node.js一起打造一款属于自己的音乐App(收藏)
更多内容请见原文,原文转载自:https://blog.csdn.net/weixin_44519496/article/details/118755888
- idea显示 RunDashboard ,多个启动项时列表显示
在.idea(项目所在文件夹中)下的workspace.xml文件中找到 <component name="RunDashboard"> 标签,然后添加如下节点 < ...
- 11.4 Android Studio如何设置代理
有些网络环境下,Android Studio下载无法下载依赖,这个时候就要配置代理,至于代理的问题,大家要自己解决. 获取代理信息 一般要获取如下信息: 地址:可以是域名和IP 端口: 代理类型:常用 ...
- Vite+TS带你搭建一个属于自己的Vue3组件库
theme: nico 前言 随着前端技术的发展,业界涌现出了许多的UI组件库.例如我们熟知的ElementUI,Vant,AntDesign等等.但是作为一个前端开发者,你知道一个UI组件库是如何被 ...
- CTCLoss如何使用
CTCLoss如何使用 目录 CTCLoss如何使用 什么是CTC 架构介绍 一个简单的例子 CTC计算的推导 总概率\(p(z|x)\) 路径的含义 路径概率\(p(\pi|x)\) 什么是\(\m ...