【ONE·R || R与C++混合编程简单介绍 】

news2024/11/24 10:59:13

总言

  课堂演讲:R语言与CPP混合编程课后学习汇报。
  

  

文章目录

  • 总言
  • 1、汇报目的
  • 2、RCPP
    • 2.1、简单介绍:
    • 2.2、简单使用演示:
      • 2.1.1、Rcpp包与RTools
      • 2.2.2、上手尝试1.0:一个hello world小程序。
      • 2.2.3、上手尝试2.0:求斐波那契数第N个数·递归实现。
      • 2.2.4、一些说明
    • 2.3、初探RCPP

  
  

1、汇报目的

  1)、关于本次主题汇报的想法诞生?

从自身经历角度:

  1、个人对C、C++、Linux操作系统有简单的了解,R虽然为解释型语言,但同属于计算机编程语言。
  2、已知存在混合编程的情景,最常见的属于C/C++混合编程,比如Linux操作系统主要是通过C和C++编写的。这个例子相对缺陷在于:C++是基于C的改进,能使用C的基本语法。但是,多语言混合编程也存在于python、Java等各种语言间。
  3、既然正在了解R语言,那么正好可以探索一下其与C/C++的混合编程,也是熟悉对这些语言的使用。
  

从R语言自身来看:

  1、在《R语言实战》中有这样一段描述:
在这里插入图片描述

  关于虚拟内存: 属于计算机操作系统相关的知识,我们的程序可存储于各种外储中,比如磁盘,程序运行需要加载到内存,而加载到内存中的程序称之为进程。CPU对进程有一套完整的调度模式,虚拟空间是操作系统为了更好的管理物理内存而为进程设置的一套体系。
  
在这里插入图片描述

  关于RCPP: 这是接下来探讨的内容。
  
  

2、RCPP

2.1、简单介绍:

  1)、是什么
  1、Rcpp包是一个打通R语言和C++语言的通信组件包,可以把C++代码与R程序连接在一起,且不用关心C++中那套繁琐的编译、链接、接口问题。
  2、R语言和C++语言的数据类型是不经相同,通过Rcpp包能够对它们进行完整的映射转换。
  3、Rcpp支持把C++代码写在R源程序文件内, 执行时自动编译连接调用; 也支持把C++代码保存在单独的源文件中, 执行R程序时自动编译连接调用。

  
  2)、有什么用
  1、其最大的用途之一在于提高运行效率,可以把R代码中遇到运行速度瓶颈部分改写成C++代码。
  2、C++或C提供了各种方便使用的函数库,Rcpp可支持这些外来函数库的调用
  

  

2.2、简单使用演示:

2.1.1、Rcpp包与RTools

  1)、如何安装Rcpp

> install.packages("Rcpp");
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.2/Rcpp_1.0.9.zip'
Content type 'application/zip' length 2842384 bytes (2.7 MB)
downloaded 2.7 MB

程序包‘Rcpp’打开成功,MD5和检查也通过

下载的二进制程序包在
	C:\Users\无咎\AppData\Local\Temp\RtmpMnQcFB\downloaded_packages里
> 

在这里插入图片描述
  
  

  2)、如何安装RTools

  原因说明: 由于涉及到编译, 所以Rcpp比一般的扩展包有更多的安装要求: 除了要安装Rcpp包之外, 还需要安装RTools包。
  RTools包: 用于C, C++, Fortran程序编译链接的开发工具包。

在这里插入图片描述

trying URL 'https://cran.rstudio.com/bin/windows/Rtools/rtools42/files/rtools42-5355-5357.exe'
Content type 'application/x-msdownload' length 482123824 bytes (459.8 MB)
downloaded 459.8 MB

  
  相关问题: RStudio自己的自动安装RTools的功能可能有问题, 安装后不能正常编译含有Rcpp的Rmd文件。 按照RTools 4.0的要求, 还要在自己的“我的文档”文件夹中生成名为.Renviron的如下文本文件:
  这里采用非手动配置方式:进入R Studio里,运行以下代码即可。

writeLines('PATH="${RTOOLS40_HOME}\\usr\\bin;${PATH}"', con = "~/.Renviron")

  运行后关闭RStudio,重新打开并运行下述代码Sys.which("make"),检测是否配置成功:

> Sys.which("make")
                                   make 
"C:\\RBUILD~1\\4.2\\usr\\bin\\make.exe" 

  如上述可看到成功配置。
  
  

2.2.2、上手尝试1.0:一个hello world小程序。

  1)、如何在Rstudio中建立一个C++文件:

  文件打开:

在这里插入图片描述

  这里的英文做了详细解释:可以阅读并演示。

在这里插入图片描述
  
  
  2)、实例演示:

  下面我们来演示自己的函数,在CPP文件中编写如下代码:

#include <iostream>
#include <Rcpp.h>
#include <string> //头文件:里面包含各种函数实现的声明、定义
using namespace Rcpp; //命名空间:起限制作用,能解决名称冲突问题。
using namespace std;//这两句的含义是展开Rcpp、std这两个空间中所包含的内容。


// [[Rcpp::export]]
string HelloByCpp(string s)
{
  cout << "hello " << s << endl; //cout、endl存在于std中的对象
  return s;
}


/*** R
HelloByCpp("world")
*/

  在控制台运行下述代码sourceCpp(file = "HelloByCpp.cpp")表示对相关cpp文件进行编译,转换成R可以调用的同名R函数。
  演示结果如下:

> sourceCpp(file = "HelloByCpp.cpp");

> HelloByCpp("world")
hello world
[1] "world"

> HelloByCpp("R");
hello R
[1] "R"

> HelloByCpp("string!");
hello string!
[1] "string!"

在这里插入图片描述
  解释说明:
  1、编译、链接、导入等过程在后台由Rcpp控制自动进行的, 不需要用户去设置编译环境, 也不需要用户执行编译、链接、导入R的工作。

  2、同样的,如果上述的代码指令在R中频繁使用,我们可以将其保存为.R的文件。

  
  
  

2.2.3、上手尝试2.0:求斐波那契数第N个数·递归实现。

  1)、斐波那契数:
  
在这里插入图片描述

  
  2)、递归函数:
  简单理解就是俄罗斯套娃。
在这里插入图片描述

  
  3)、R中调用CPP实现:
  下述R代码,其中有一部分C++代码, 用cppFunction转换成了R可以调用的同名R函数。

> cppFunction(code = '
+     int fib(const int n)
+     {
+         if(n <= 2) 
+            return 1;
+         return fib(n-1)+fib(n-2) ;
+     }
+ ');
> fibonacci(2);
[1] 1
> fibonacci(4);
[1] 3
> fibonacci(5);
[1] 5

  
  
  

2.2.4、一些说明

  1)、一些说明:
  需要说明的是,上述演示是为了学习了解RCPP包的基础使用方式,像hello world这样的程序与其大费周章去调用CPP,不如直接在R中编写一个简单的函数,也能达到相同效果。

  R中直接编写函数实现hello word打印:

> hello <-function(s){
+     print(s);
+ }

> hello ("hello world");
[1] "hello world"
> hello ("hello R");
[1] "hello R"
> hello ("hello vim");
[1] "hello vim"

  R中直接编写函数实现斐波那契数递归:

> Fib <- function(n){
+     if(1 == n | 2 == n)
+     {
+         return (1);
+     }else{
+         return (Fib(n-1)+Fib(n-2));
+     }
+ };

+ > Fib(1);
[1] 1
> Fib(2);
[1] 1
> Fib(3);
[1] 2
> Fib(5);
[1] 5

  
  
  2)、运行速度测试:
  就如前文所言,在R中使用C++是为了提高运行速度以及相关库函数使用。在编写函数时我们,有时我们需要遍历数据,或多次循环、递归等。这些是占据进程运行时间的缘由之一。这里我们简单的做个关于运行速度测试例子:

  关于演示实例:
  这里我们就以输出第40个斐波那契数为例。因为递归是这种嵌套式写法很方便进行检测。

  Fib:用R语言编写的斐波那契数递归函数。

> Fib <- function(n){
+     if(1 == n | 2 == n)
+     {
+         return (1);
+     }else{
+         return (Fib(n-1)+Fib(n-2));
+     }
+ };

  fib用C++编写的斐波那契数递归函数。

+     int fib(const int n)
+     {
+         if(n <= 2) 
+            return 1;
+         return fib(n-1)+fib(n-2) ;
+     }

  

  关于测试结果:
  这里使用的是system.time()函数,用于查看系统运行时间,它的时间由三个成分组成。
  “用户”:是消耗在应用程序(非操作系统部分)执行的时间。
  “系统”:是底层操作系统执行(例如磁盘读写等)部分的时间,
  “流逝”:是经过的总时间(可以认为是前两者的总和)。

> system.time(fib(40));
用户 系统 流逝 
0.14 0.00 0.14 
> system.time(Fib(40));
  用户   系统   流逝 
110.67   0.04 111.61 

  上述结果以秒为单位,可看到我们使用C++来处理相关数据,它几乎立马就能得到运行结果。但如果使用R来处理数据,计算40个斐波那契数大约需要2min。

  
  有关运行速度的问题,这里我们再来演示一下,这次换一个相对较大的数据,考虑到R运行速度问题,这里以C++演示:
在这里插入图片描述
在这里插入图片描述

  可以看到使用C++相关编译器,其输入数字,大约到40左右程序差不多就运行不出来了,原因就和上述R中提及的问题一样,涉及存储空间问题,以及递归的深度嵌套效率。
  

#include<iostream>
#include<time.h>
using namespace std;

unsigned int fib(const unsigned int n)
 {
	if (n <= 2)
		return 1;
	
	return fib(n - 1) + fib(n - 2);
}

int main()
{
	
	size_t begin1 = clock();
	unsigned int result1 = fib(10);
	size_t end1 = clock();
	cout << "result1:" << result1 << endl;
	cout << "fib(10)-time:" << end1 - begin1 << endl << endl << endl;


	size_t begin2 = clock();
	unsigned int result2 = fib(20);
	size_t end2 = clock();
	cout << "result2:" << result2 << endl;
	cout << "fib(20)-time:" << end2 - begin2 << endl << endl << endl;


	size_t begin3 = clock();
	unsigned int result3 = fib(30);
	size_t end3 = clock();
	cout << "result3:" << result3 << endl;
	cout << "fib(30)-time:" << end3 - begin3 << endl << endl << endl;



	size_t begin4 = clock();
	unsigned int result4 = fib(40);
	size_t end4 = clock();
	cout << "result4:" << result4 << endl;
	cout << "fib(40)-time:" << end4 - begin4 << endl << endl << endl;


	size_t begin5 = clock();
	unsigned int result5 = fib(50);
	size_t end5 = clock();
	cout << "result5:" << result5 << endl;
	cout << "fib(50)-time:" << end5 - begin5 << endl << endl << endl;


	size_t begin6 = clock();
	unsigned int result6 = fib(100);
	size_t end6 = clock();
	cout << "result6:" << result6 << endl;
	cout << "fib(100)-time:" << end6 - begin6 << endl << endl << endl;

	size_t begin7 = clock();
	unsigned int result7 = fib(500);
	size_t end7 = clock();
	cout << "result7:" << result7 << endl;
	cout << "fib(500)-time:" << end7 - begin7 << endl << endl << endl;

	size_t begin8 = clock();
	unsigned int result8 = fib(1000);
	size_t end8 = clock();
	cout << "result8:" << result8 << endl;
	cout << "fib(1000)-time:" << end8 - begin8 << endl << endl << endl;

	return 0;
}

  
  
  
  
  

2.3、初探RCPP

  1)、Rcpp属性:
  Rcpp属性(attributes):用来简化把C++函数变成R函数的过程。 做法是在C++源程序中加入一些特殊注释, 利用其指示自动生成C++与R的接口程序。 属性是C++11标准的内容。
  
  一些解释说明:
  1、在C++中,提供Rcpp::export标注要输出到R中的C++函数。
  
  2、在R中,提供sourceCpp(), 用来自动编译连接保存在文件或R字符串中的C++代码, 并自动生成界面程序把C++函数转换为R函数。
  
  3、在R中,提供cppFunction()函数, 用来把保存在R字符串中的C++函数自动编译连接并转换成R函数。 提供evalCpp()函数, 用来把保存在R字符串中的C++代码片段自动编译连接并执行。
  
  4、用特殊注释//[[Rcpp::export]] ,说明某C++函数需要在编译成动态链接库时, 把这个函数导出到链接库的对外可见部分。通俗来讲就是,在sourceCpp读取代码解析的过程中,被这条语句注释的函数能够在R里面调用。
  
  5、/*** R */:里面可以放R代码,会c++代码编译结束后运行,常用于代码测试。

  
  
  相关参考:
  1、R语言教程
  2、R的极客理想系列文章
  3、《R语言实战》

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

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

相关文章

STC 51单片机57——矩阵键盘 基本原理演示

51单片机 矩阵键盘 基本原理演示 #include "reg51.h" sbit P11P1^1; sbit P14P1^4; sbit P20P2^0; sbit P21P2^1; void main(void) { P111;// Hight P140; //Low if(P111) P200; else P210; while(1); }

刷爆力扣之较大分组的位置

刷爆力扣之较大分组的位置 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 工作原因拖更些时日&#xff0c;今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照…

Java项目:SSM农业信息管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 管理员角色包含以下功能&#xff1a; 管理员登陆,用户管理,新闻管理,留言列表查看等功能。 用户角色包含以下功能&#xff1a; 查看所有新闻,市…

免费分享20套微信小程序源码 源码免费下载【强烈推荐】

淘源码&#xff1a;国内知名的源码免费下载平台 微信小程序源码包括&#xff1a;商城系统、点餐外卖、垃圾分类、预约洗车、物业管理、校园跑腿、驾考学习、会议预约、图书管理、智能停车、在线答题等小程序源码。 源码分享&#xff0c;文末获取源码&#xff01; 1、JAVA微信…

微信API接口、微信二次开发API调用

微信API接口、微信二次开发API调用 微信协议接口调用-加微信好友及通过好友请求 加微信好友 /** * 微信自动添加好友 * author wechatno:tangjinjinwx * blog http://www.wlkankan.cn */ Async public void handleMsg(ChannelHandlerContext c…

代码随线录刷题|LeetCode 392.判断子序列 115.不同的子序列

目录 392.判断子序列 思路 1、确定dp数组 2、确定递推公式 3、初始化dp数组 4、遍历顺序 判断子序列 动态规划 双指针 115.不同的子序列 思路 1、确定dp数组 2、确定递推公式 3、初始化dp数组 4、遍历顺序 不同的子序列 392.判断子序列 题目链接&#xff1a;力扣 思路 比较简单…

【Exception】 Java Lambda List转换Map报错 触发异常 IllegalStateException: Duplicate key

【Exception】 Java Lambda List转换Map报错 触发异常 IllegalStateException: Duplicate key 一、问题描述 在使用Java8 lambda 将List转换为Map时&#xff0c;遇到报错&#xff1a;IllegalStateException- Duplicate key .... 具体报错信息如下&#xff1a; java.lang.Illega…

基于Dockerfile创建镜像

目录 一、Docker镜像的创建 1 基于现有镜像创建 2 基于本地模板创建 3 基于Dockerfile 创建 3.1 联合文件系统(UnionFS ) 3.2 镜像加载原理 二、Dockerfile 操作命令的指令 1 FROM 镜像 2 MAINTAINER 名字 3 RUN 命令 4 ENTRYPOINT 5 CMD ENTRYPOINT和CMD的区别&…

HTML网页设计【足球科普】学生DW静态网页设计

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

【openWrt】设置执行定时任务

遇到一个问题&#xff0c;使用openWrt软路由搭建服务器&#xff0c;在docker装了一个maccmsV10&#xff0c;需要每天执行cj信息定时任务&#xff0c;但是maccmsV10本身不支持执行定时任务的配置的。 看了下&#xff0c;openWrt是支持本身是linux系统&#xff0c;所以是可以设…

糟糕,数据库异常不可用怎么办?

摘要&#xff1a;糟糕&#xff0c;数据库异常不可用怎么办&#xff1f;挺着急的&#xff0c;在线等。本文分享自华为云社区《糟糕&#xff0c;数据库异常不可用怎么办&#xff1f;》&#xff0c;作者&#xff1a;GaussDB 数据库。 随着数字化转型的加速&#xff0c;数据量爆发…

获取鼠标在画布中的位置

获取鼠标在画布中的位置 效果展示 概述 本文讲解如何实现我们平时用的画布软件中&#xff0c;怎么获取的我们鼠标时刻在画布中的位置。 构建HTML框架 <body><div class"box"></div> </body>CSS样式 <style>.box {/* 设置盒子…

IDEA 2022.3 发布,终于支持 redis 了

IntelliJ IDEA 发布了最新2022.3版本&#xff0c;本次更新&#xff1a;可以通过设置切换到新 UI&#xff0c;即可预览焕然一新的 IDE 外观。引入了一个新的 Settings Sync&#xff08;设置同步&#xff09;解决方案&#xff0c;用于同步和备份自定义用户设置。此外&#xff0c;…

私域运营对于企业的重要性

企业进行私域流量的精细化运营&#xff0c;不仅可以打造属于企业自己的社群王国&#xff0c;还可以挖掘存量客户的价值&#xff0c;实现更智能的客户管理和个性化运营方案。 前言 相信每个人都对瑞幸咖啡略有耳闻&#xff0c;这个国产咖啡品牌曾一度被封神&#xff0c;但随着财…

【leetcode】2404. 出现最频繁的偶数元素(js实现)

1. 题目 2404. 出现最频繁的偶数元素 2. 思路 创建哈希表&#xff0c;统计偶数的出现次数将哈希表转换成数组&#xff0c;遍历哈希表&#xff0c;设置res的初始值为[-1&#xff0c;0]&#xff0c;第一个值为偶数值&#xff0c;第二个值为这个偶数出现的次数&#xff1b;如果…

探花交友_第3章_完善个人信息(新版)

探花交友_第3章_完善个人信息(新版) 文章目录探花交友_第3章_完善个人信息(新版)课程介绍1. 完善用户信息1.1 阿里云OSS1.1.1 概述1.1.2 账号申请购买服务创建Bucket1.1.3 抽取模板工具OssPropertiesOssTemplateTanhuaAutoConfiguration1.1.4 测试1.2 百度人脸识别1.2.1 概述1.…

PyCharm+PyQT5之四第二个QT程序

前面程序实现了逻辑分离&#xff0c;第二个QT程序将建立控件之间的关联&#xff0c;并自行撰写&#xff0c;事件。 首先&#xff0c;建立只有一个按钮的界面 点击工具栏编辑信号与槽&#xff0c;按钮带有红框并拖拽&#xff0c;这样间建立了按钮与dialog的槽信号。 按钮一般是…

【OpenCV学习】第7课:形态学操作-膨胀与腐蚀

仅自学做笔记用,后续有错误会更改 理论 图像形态学操作-基于形状的一系列图像处理操作的合集, 主要是基于集合论基础上的形态学数学形态学有4个基本操作:膨胀丶腐蚀丶开丶闭膨胀与腐蚀是图像处理中最常用的形态学操作手段 形态学操作(morphology operators)-膨胀 跟前边的卷…

行者AI解析内容审核平台中的图像检测技术原理

本文首发&#xff1a;行者AI谛听 近些年&#xff0c;监管部分对于平台的信息方面&#xff0c;越来越严格&#xff0c;继而有很多企业选择智能AI内容审核服务&#xff0c;帮助企业快速处理平台上一些违规内容。 很多人不懂这方面到底属于什么&#xff0c;今天行者AI就来为大家解…

【Python】python入门,这一篇就够了

快速入门/一文免挂Python程序元素变量python中的符号Python的程序结构分支结构异常处理循环结构Python函数python中的可变参数python中的全局变量和局部变量组合数据类型之序列类型序列通用操作字符串&#xff08;str&#xff09;字符串常用函数字符串类型的格式化列表&#xf…