封装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 ...
随机推荐
- SpringBoot实现基于token的登录验证
一.SpringBoot实现基于token的登录验证 基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字 ...
- Spring Authorization Server 0.3.0 发布,官方文档正式上线
基于OAuth2.1的授权服务器Spring Authorization Server 0.3.0今天正式发布,在本次更新中有几大亮点. 文档正式上线 Spring Authorization Ser ...
- CMU 15-445 数据库课程第四课文字版 - 存储2
熟肉视频地址: CMU数据库管理系统课程[熟肉]4.数据库存储结构2(上) CMU数据库管理系统课程[熟肉]4.数据库存储结构2(下) 1. 面向日志的存储 上节课我们讲完了面向元组的存储,这节课从面 ...
- Spring boot中最大连接数、最大线程数与最大等待数在生产中的异常场景
在上周三下午时,客户.业务和测试人员同时反溃生产环境登录进入不了系统,我亲自测试时,第一次登录进去了,待退出后再登录时,复现了客户的问题,场景像是请求连接被拒绝了,分析后判断是spring boot的 ...
- 如何用 UDP 实现可靠传输?
作者:小林coding 计算机八股文刷题网站:https://xiaolincoding.com 大家好,我是小林. 我记得之前在群里看到,有位读者字节一面的时候被问到:「如何基于 UDP 协议实现可 ...
- 1.数据结构《Pytorch神经网络高效入门教程》Deeplizard
当移动一个数组或向量时,我们需要一个索引:二维数组/矩阵需要两个索引, 比如说标量是零维张量,数组/向量/矢量是一维张量,矩阵是是二维张量,n维数组是n维张量. 如果我们被告知, 假设有一个张量t, ...
- 使用PowerShell安装MySQL
更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年7月10日. 2022年4月16日:更新MySQL下载链接. 一.说明与准备工作 根据MySQL官网提供的安装M ...
- Mybatisi和Spring整合源码分析
一.MybatisSpring的使用 1.创建 Maven 工程. 2.添加依赖,代码如下 <dependency> <groupId>org.mybatis</grou ...
- 老子云AMRT全新三维格式正式上线,其性能全面超越现有的三维数据格式
9月16日,老子云AMRT全新三维格式正式上线,其性能远超现有的三维数据格式.目前已有含国家超算长沙中心.中科院空间所.中车集团等上百家政企事业单位的项目中使用了AMRT格式,大大提升了可视化项目的开 ...
- js 生成的html class属性失效问题
var html = '<fieldset class="struct-info" id="SlopeZY"><legend>变坡点(Z ...