std::ratio 简单使用举例


author: hjjdebug
date: 2025年 06月 09日 星期一 14:28:40 CST
descrip: std::ratio 简单使用举例


文章目录

  • 1. 先看一个简单的例子 1/2+/1/3=5/6
  • 2 std::ratio 的手册页
  • 3. std::ratio_add 到底是什么呢?
  • 4. 代码注释
  • 5. 加深理解.
  • 6. 自定义的std::ratio 与 std::ratio_add

std::ratio 代表一个比值,代表一个分数, 是一种类型, 这容易理解, 因为它有自己的类成员num,den
std::ratio 还能参与运算,例如进行加,减,乘,除, 而且是编译期预算,这下就感觉有点意思了.

c++ 的编译期的分数运算.

1. 先看一个简单的例子 1/2+/1/3=5/6

$ cat main.cpp
// ratio example
#include <ratio>
#include <stdio.h>int main (void)
{using one_third= std::ratio<1,3> ;  //类型using one_second = std::ratio<1,2> ; //类型using sum = std::ratio_add<one_third,one_second> ; //类型,由一种类型可以转变成另一种类型printf("one_third=%ld/%ld\n",one_third::num,one_third::den);printf("one_second=%ld/%ld\n",one_second::num,one_second::den);double r=(double)sum::num/sum::den;printf("sum=%ld/%ld (which is:%f)\n",sum::num,sum::den,r);sum obj1;r=(double)obj1.num/obj1.den;printf("sum=%ld/%ld (which is:%f)\n",obj1.num,obj1.den,r);return 0;
}

执行结果:
$ ./tt
one_third=1/3
one_second=1/2
sum=5/6 (which is:0.833333)
sum=5/6 (which is:0.833333)

初见这个例子,还是觉得非常的奇怪的, 这种写法是什么意思?怎么工作的?
std::ratio<1,3> 是一种类型.
std::ratio<1,2> 是另一种类型
它们都是模板std::ratio 的实例化类型. std::ratio 叫类模板. 这2个实例可以叫模板类,是具体的类型.

2 std::ratio 的手册页

$ man std::ratio
有如下描述:
template<intmax_t _Num, intmax_t _Den = 1>
struct std::ratio< _Num, _Den >" Provides compile-time rational arithmetic. //提供编译期有理数算术
它的两个输入参数是非类型参数.
非类型参数不是类型,而是具体的值,通常是整数值或整数常量

std::ratio_add 是另一个类模板,它接受2种类型做输入参数.
当我们查询它的手册页时, 竟然没有条目.
$ man std::ratio_add
没有 std::ratio_add 的手册页条目

好吧,顺便看看std::ratio 相关的有几个条目?
$ man -w std::ratio
/usr/share/man/man3/std::ratio.3cxx.gz

找到std::rario手册页位置后, 例如相关帮助. 由此看出是 3条,另2条是equal, not_equal
$ ls -l /usr/share/man/man3/std::ratio*
-rw-r–r-- 1 root root 546 10月 24 2022 /usr/share/man/man3/std::ratio.3cxx.gz
-rw-r–r-- 1 root root 493 10月 24 2022 /usr/share/man/man3/std::ratio_equal.3cxx.gz
-rw-r–r-- 1 root root 484 10月 24 2022 /usr/share/man/man3/std::ratio_not_equal.3cxx.gz

3. std::ratio_add 到底是什么呢?

可以对编译进行一下预处理, 然后找到std::ratio_add, 为:
template<typename _R1, typename _R2>
using ratio_add = typename __ratio_add<_R1, _R2>::type;

从这里,我们知道ratio_add 是一种类型别名就可以了.
至于这个类型到底是什么?包含了什么成员,
那要继续追查 __ratio_add 重点关注__ratio_add::type
template<typename _R1, typename _R2>
struct __ratio_add
{
typedef typename __ratio_add_impl<_R1, _R2>::type type;
static constexpr intmax_t num = type::num;
static constexpr intmax_t den = type::den;
};

__ratio_add 有两个常量num,den, 这就是我们用printf 打印的内容,
这两个值的计算依赖于__ratio_add_impl<_R1, _R2>::type
这里是说, __ratio_add::type 是 __radio_add_imple::type的别名

其中 __radio_add_imple<_R1,_R2> 的type 是如下定义的, 看其中的一种形式定义
private:
typedef typename __ratio_add_impl<
ratio<_R1::num, _R1::den>,
ratio<_R2::num, _R2::den> >::type __t;
public:
typedef ratio<-__t::num, __t::den> type;

从这个定义中看出,将类型R1,类型R2共同构建一个复合类型,__ratio_add_impl<…> ,
复合类型里边的type类型,把它叫别名 __t, 剧透一下,实际上这个__t也是std::ratio 类型.
我这里没有继续追下去到此为止了.
我们把__t的num,den做为参数创建 std::ratio类型,把它叫__ratio_add_impl的type 类型
其下面具体的运算过程 __ratio_add_impl 比较复杂,需要考虑分子,分母符号问题, 分母通分,分子相加等.
就不copy代码也不再分析了.
绕了一大圈,实际上 template std::ratio_add ==>bla bla bla… ==> ratio<_num,_den>

总之,它这里面引入了诸多的类型.
类型是可以有变量的, (有的变量属于类型而不属于对象)
类型可以以类型为输入参数,(模板参数有2种类型: 类型参数,非类型参数)
类型内可以重新构建其它类型 (例如上面由num,den构成的ratio<__t::num,__t::den>类型)
可以定义类型的小名. (例如将上面长的称谓std::ration<__t::num,__t::den>用type 来称谓.
这些关系构成面向类型的编程.
这里所说的面向类型强调的是编译期的数据类型, 并非是独立的编程范式.
这里的代码,是一种解释性语言,消费者是gcc, gcc负责解释并执行模板代码. gcc 能够记录和推导类型.

4. 代码注释

one_third 是std::ratio 的一种实例化类型
one_second 是std::ratio 的一种实例化类型
sum 也是 std::ratio 的一种实例化类型, 它的分子,分母是由2个输入参数one_third,one_second来决定的.
在编译期间进行计算和推导.
本博没有给出分子,分母的推导过程,只说明了ratio_add 是一种std::radio类型

5. 加深理解.

从代码上去推导sum 的类型还是比较费劲的, 所以我们不如直接去看最后的推导结果,
反正这对gcc 是一件小事. 为了看sum 的类型, 我们为sum类型声明一个变量obj1
就如同代码种所示的那样.
然后用gdb 来打印obj1的类型,如下:
(gdb) ptype obj1
type = struct std::ratio<5, 6> {
static const intmax_t num;
static const intmax_t den;
}

6. 自定义的std::ratio 与 std::ratio_add

鉴于标准库中的模板库 std::ratio_add 很难阅读,
不如实现一个简单的自定义的std::ratio 及 std::ratio_add模板
以进一步理解模板编程.
下面代码已经是很精简的了,慢慢体会其中之妙吧.
简单来说,求最大公约数是重点和难点,求最小公倍数.分数加法运算(通分母,分子相加)
测试代码:

$ cat main.cpp
#include <stdio.h>
#include <stdint.h>  // for intmax_t// 编译期计算最大公约数 (GCD) Greatest common divider, 辗转相除法
template <intmax_t A, intmax_t B>
struct gcd {static constexpr intmax_t value = gcd<B, A % B>::value;
};//特化gcd
template <intmax_t A>
struct gcd<A, 0> {static constexpr intmax_t value = A;
};// 自定义 ratio 结构
template <intmax_t Num, intmax_t Den = 1>
struct ratio {static_assert(Den != 0, "Denominator cannot be zero");static constexpr intmax_t num = Num / gcd<Num, Den>::value;static constexpr intmax_t den = Den / gcd<Num, Den>::value;
};// 编译期计算最小公倍数 (LCM) Least common multiple
template <intmax_t A, intmax_t B>
struct lcm {static constexpr intmax_t value = (A / gcd<A, B>::value) * B;
};// 自定义 ratio_add
template <typename R1, typename R2>
struct ratio_add {
private:static constexpr intmax_t lcm_val = lcm<R1::den, R2::den>::value;  //求公分母static constexpr intmax_t num_sum = R1::num * (lcm_val / R1::den) + R2::num * (lcm_val / R2::den); //求分子
public:using type = ratio<num_sum, lcm_val>;
};int main() {using R1 = ratio<1, 3>;  // 1/3using R2 = ratio<2, 5>;  // 2/5using Result = ratio_add<R1, R2>::type;printf("Result:%ld/%ld\n",Result::num, Result::den); // 输出 11/15
}

执行结果:
$ ./tt
Result:11/15

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 优势与缺点全面解析:容器技术的利与弊

在当今云计算、微服务、DevOps盛行的时代&#xff0c;Docker 几乎成了开发者、运维工程师的标配工具之一。自2013年诞生以来&#xff0c;Docker 以其轻量、快速、易移植的特点&#xff0c;彻底改变了应用的构建、交付与部署方式。 但任何技术都有两面性&#xff0c;Docker 也不…

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…

使用Redis作为缓存优化ElasticSearch读写性能

在现代数据密集型应用中,ElasticSearch凭借其强大的全文搜索能力成为许多系统的首选搜索引擎。然而,随着数据量和查询量的增长,ElasticSearch的读写性能可能会成为瓶颈。本文将详细介绍如何使用Redis作为缓存层来显著提升ElasticSearch的读写性能,包括完整的架构设计、详细…

获取wordpress某个栏目的内容数量

获取wordpress某个栏目的内容数量 <?php // 将以下 8 改成你的分类 ID 即可echo get_category(8)->count;?> 在制作wordpress模板时&#xff0c;有时会需要调用某个分类目录下的所有内容数量&#xff0c;通过这段简洁的代码就可以实现。 给WordPress自定义字段加…

uniapp 安卓 APP 后台持续运行(保活)的尝试办法

在移动应用开发领域&#xff0c;安卓系统的后台管理机制较为复杂&#xff0c;应用在后台容易被系统回收&#xff0c;导致无法持续运行。对于使用 Uniapp 开发的安卓 APP 来说&#xff0c;实现后台持续运行&#xff08;保活&#xff09;是很多开发者面临的重要需求&#xff0c;比…

深度学习——知识提炼

第一部分&#xff1a;引言与背景——为什么需要知识提炼&#xff1f; 一、模型压缩的背景 随着深度学习的发展&#xff0c;模型变得越来越大&#xff08;如 ResNet152、BERT、ViT、GPT 等&#xff09;&#xff0c;其参数量动辄数亿甚至上百亿。这些大模型虽然性能强大&#x…

开源之夏·西安电子科技大学站精彩回顾:OpenTiny开源技术下沉校园,点燃高校开发者技术热情

开源之夏2025编程活动正在如火如荼的进行中&#xff0c;当前也迎来了报名的倒计时阶段&#xff0c;开源之夏组织方也通过高校行系列活动进入各大高校&#xff0c;帮助高校开发者科普开源文化、开源活动、开源技术。 6月4日 开源之夏携手多位开源技术大咖、经验型选手走进西安电…

时间复杂度和算法选择

数据范围 时间复杂度 算法选择 n \leq 30 指数级别 O(2^n) 深度优先搜索&#xff08;DFS&#xff09; 剪枝、状态压缩动态规划 n \leq 100 O(n^3) Floyd 算法、动态规划、高斯消元 n \leq 1000 O(n^2) 、 O(n^2 \log n) 动态规划、二分…

数据分析实战2(Tableau)

1、Tableau功能 数据赋能&#xff08;让业务一线也可以轻松使用最新数据&#xff09; 分析师可以直接将数据看板发布到线上自动更新看板自由下载数据线上修改图表邮箱发送数据设置数据预警 数据探索&#xff08;通过统计分析和数据可视化&#xff0c;从数据发现问题&#xf…

CentOS7_Linux下安装Docker和docker-compose

目录 环境要求安装步骤1、修改镜像源配置文件2、卸载旧版本 Docker&#xff08;如有&#xff09;3、安装依赖工具4、添加 Docker 官方仓库5、安装 Docker 引擎6、启动 Docker 并设置开机自启7、验证安装8、配置镜像加速器创建配置文件重启 Docker 生效 9、允许非 root 用户操作…

ubuntu中使用docker

上一篇我已经下载了一个ubuntu:20.04的镜像&#xff1b; 1. 查看所有镜像 sudo docker images 2. 基于本地存在的ubuntu:20.04镜像创建一个容器&#xff0c;容器的名为cppubuntu-1。创建的时候就会启动容器。 sudo docker run -itd --name cppubuntu-1 ubuntu:20.04 结果出…

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…

idea中 maven 本地仓库有jar包,但还是找不到,解决打包失败和无法引用的问题

1、删除本地仓库中的文件 进入本地仓库对应jar包文件目录中删除_remote.repositories文件和结尾为.lastUpdated的文件 2、回到IDEA刷新Maven 3、查看之前引用不了的jar是否引入成功

ALOHA ACT算法与源码笔记

算法 一文通透动作分块算法ACT&#xff1a;斯坦福ALOHA团队推出的动作序列预测算法(Action Chunking with Transformers) 比较简单&#xff0c;算法题目里就写了&#xff1a;Action Chunking with Transformers&#xff0c;比较有特色的地方就是Action Chunking&#xff0c;核…

数字ic后端设计从入门到精通6(含fusion compiler, tcl教学)repeater详解

Repeaters RC延迟与导线长度的关系&#xff1a; 导线的电阻&#xff08;R&#xff09;和电容&#xff08;C&#xff09;都会随着导线长度&#xff08;l&#xff09;的增加而增大。RC延迟是电阻和电容共同作用导致的信号延迟。由于RC延迟与R和C的乘积有关&#xff0c;因此它会随…

Data Warebase 成功押注 PostgreSQL 生态,或成 AI 时代数据底座

本文内容整理自 ProtonBase CEO 王绍翾在 AICon 的主题演讲《Data Warebase: Instant Ingest-Transform-Explore-Retrieve for AI Applications》。作者的职业经历贯穿了 AI 1.0、2.0 和 3.0 的时代&#xff0c;从搜索推荐&#xff0c;到视觉 / 语音 / NLP 智能&#xff0c;再到…

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …

Kubernetes (k8s)版本发布情况

Kubernetes (k8s)版本发布情况 代码放在 GitHub - kubernetes/kubernetes: Production-Grade Container Scheduling and Management https://github.com/kubernetes/kubernetes/releases 文档放在 kubernetes.io各个版本变更等: https://github.com/kubernetes/kubernet…