封装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 ...
随机推荐
- mysqldump还原备份数据时遇到一个问题
问题描述 ERROR 1839 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_MODE = O ...
- python之装饰器补充与递归函数与二分查找
目录 多层装饰器 有参装饰器 递归函数 基本演示 斐波那契数列 总结 小拓展 算法之二分法 简介 举例 总结 多层装饰器 我们已经知道了语法糖的作用是将装饰对象自动装饰到装饰器中,一个语法糖的应用我们 ...
- 关于我学git这档子事
创建本地分支并切换到该分支 git checkout -b *** 相当于如下2个命令: git branch *** git checkout *** 推送本地开发分支到远程开发分支 git pus ...
- Hadoop入门学习笔记(一)
Week2 学习笔记 Hadoop核心组件 Hadoop HDFS(分布式文件存储系统):解决海量数据存储 Hadoop YARN(集群资源管理和任务调度框架):解决资源任务调度 Hadoop Map ...
- 贝塞尔曲线在Unity中的应用
前言:国庆放假后基本整个人的散掉了.加之种种原因,没时间没心情写博客.最近研究了一下3d的一些效果.其中有类似翻书撕纸的操作,可是一个panel怎么由平整的变成弯曲的呢? 两点可以确定一条直线,三点可 ...
- Java ES 实现or查询
es mapping里有三个字段: A:Integer B:Integer C:TEXT 现在想实现一个查询,来检索 ( (A =1 and B=2) or (c like "test ...
- CabloyJS一站式助力微信、企业微信、钉钉开发 - 微信篇
前言 现在软件开发不仅要面对前端碎片化,还要面对后端碎片化.针对前端碎片化,CabloyJS提供了pc=mobile+pad的跨端自适应方案,参见:自适应布局:pc = mobile + pad 在这 ...
- BUUCTF-假如给我三天光明
假如给我三天光明 打开压缩包可以看到一个海报,下方有盲文显示,通过对照表得知 盲文翻译为kmdonowg 通过盲文翻译得到的字符串解压压缩包得到一个音频文件 使用Audacity打开,看样子应该是摩斯 ...
- SAP Web Dynpro - 应用程序中的服务调用
您可以使用服务调用来调用Web Dynpro组件中的现有功能模块. 要创建服务呼叫,您可以使用Web Dynpro工具中易于使用的向导. 您可以在ABAP工作台中启动该向导以创建服务调用. 步骤1-选 ...
- HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴
2022年6月28日,HDD·HMS Core.Sparkle影音娱乐沙龙在线上与开发者们见面.HMS Core音频编辑服务(Audio Editor Kit)专家为大家详细分享了基于分离的3D音乐创 ...