C++11标准模板(STL)- 算法(std::inner_product)

news/2025/2/22 3:34:01/
定义于头文件 <algorithm>

算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first, last) ,其中 last 指代要查询或修改的最后元素的后一个元素。

计算两个范围的元素的内积

std::inner_product
template< class InputIt1, class InputIt2, class T >

T inner_product( InputIt1 first1, InputIt1 last1,

                 InputIt2 first2, T init );
(1)
template<class InputIt1, class InputIt2, class T,

         class BinaryOperation1, class BinaryOperation2>
T inner_product( InputIt1 first1, InputIt1 last1,
                 InputIt2 first2, T init,
                 BinaryOperation1 op1,

                 BinaryOperation2 op2 );
(2)

 

计算内积(即积之和)或在范围 [first1, last1) 和始于 first2 的范围上进行有序映射/规约操作。

1) 以初值 init 初始化积累器 acc ,然后

以表达式 acc = acc + *first1 * *first2 修改它,再以表达式 acc = acc + *(first1+1) * *(first2+1) 修改它,以此类推

(C++20 前)

以表达式 acc = std::move(acc) + *first1 * *first2 修改它,再以表达式 acc = std::move(acc) + *(first1+1) * *(first2+1) 修改它,以此类推

(C++20 起)

直至抵达 last1 。对于 + 与 * 的内建含义,此算法计算二个范围的内积。2) 以初值 init 初始化积累器 acc ,然后

以表达式 acc = op1(acc, op2(*first1, *first2)) 修改它,再以表达式 acc = op1(acc, op2(*(first1+1), *(first2+1))) 修改它,以此类推

(C++20 前)

以表达式 acc = op1(std::move(acc), op2(*first1, *first2)) 修改它,再以表达式 acc = op1(std::move(acc), op2(*(first1+1), *(first2+1))) 修改它,以此类推

(C++20 起)

直至抵达 last1

op1op2 必须无副效应。

(C++11 前)

op1op2 必须不非法化所涉及范围的任何迭代器,含尾迭代器或修改该范围的任何元素。

(C++11 起)

参数

first1, last1-元素范围
first2-第二个元素范围的起始
init-积的和的初值
op1-被使用的二元函数对象。此“和”函数接收 op2 所返回的值和当前积累器的值,并产生存储于积累器的新值。

该函数的签名应当等价于:

 Ret fun(const Type1 &a, const Type2 &b);

签名中并不需要有 const &。
类型 Type1 与 Type2 必须使得 T 与 Type3 类型的对象各能隐式转换成 Type1 与 Type2 。 类型 Ret 必须使得 T 类型对象能被赋 Ret 类型值。 ​

op2-被使用的二元函数对象。此“积”函数从每个范围接收一个值并产生新值。

该函数的签名应当等价于:

 Ret fun(const Type1 &a, const Type2 &b);

签名中并不需要有 const &。
类型 Type1 与 Type2 必须使得 InputIt1 与 InputIt2 类型的对象在解引用后分别能隐式转换到 Type1 与 Type2 。 类型 Ret 必须使得 Type3 类型对象能被赋 Ret 类型值。 ​

类型要求
- InputIt1, InputIt2 必须满足遗留输入迭代器 (LegacyInputIterator) 的要求。
- ForwardIt1, ForwardIt2 必须满足遗留向前迭代器 (LegacyForwardIterator) 的要求。
- T 必须满足可复制赋值 (CopyAssignable) 和 可复制构造 (CopyConstructible) 的要求。

返回值

上述 acc 的最终值。

可能的实现

版本一

template<class InputIt1, class InputIt2, class T>
T inner_product(InputIt1 first1, InputIt1 last1,InputIt2 first2, T init)
{while (first1 != last1) {init = std::move(init) + *first1 * *first2; // C++20 起有 std::move++first1;++first2;}return init;
}

版本二

template<class InputIt1, class InputIt2,class T,class BinaryOperation1, class BinaryOperation2>
T inner_product(InputIt1 first1, InputIt1 last1,InputIt2 first2, T init,BinaryOperation1 op1,BinaryOperation2 op2)
{while (first1 != last1) {init = op1(std::move(init), op2(*first1, *first2)); // C++20 起有 std::move++first1;++first2;}return init;
}

注意

此算法的可并行版本 std::transform_reduce 要求 op1op2 可交换并可结合,但 std::inner_product 不作这种要求,且始终以给定顺序进行操作。

调用示例

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <list>
#include <iterator>
#include <time.h>using namespace std;struct Cell
{int x;int y;Cell &operator +=(const Cell &cell){x += cell.x;y += cell.y;return *this;}Cell &operator +(const Cell &cell){x += cell.x;y += cell.y;return *this;}Cell &operator *(const Cell &cell){x *= cell.x;y *= cell.y;return *this;}Cell &operator ++(){x += 1;y += 1;return *this;}bool operator <(const Cell &cell) const{if (x == cell.x){return y < cell.y;}else{return x < cell.x;}}bool operator ==(const Cell &cell) const{return x == cell.x && y == cell.y;}
};std::ostream &operator<<(std::ostream &os, const Cell &cell)
{os << "{" << cell.x << "," << cell.y << "}";return os;
}int main()
{std::mt19937 g{std::random_device{}()};srand((unsigned)time(NULL));;std::cout << std::boolalpha;std::function<Cell()> generate = [](){int n = std::rand() % 10;Cell cell{n, n};return cell;};// 初始化lCells1std::list<vector<Cell>> lCells1(3, vector<Cell>(5));//用从起始值开始连续递增的值填充一个范围for (vector<Cell> &vCells : lCells1){std::generate(vCells.begin(), vCells.end(), generate);}// 初始化lCells1std::list<vector<Cell>> lCells2(3, vector<Cell>(5));//用从起始值开始连续递增的值填充一个范围for (vector<Cell> &vCells : lCells2){std::generate(vCells.begin(), vCells.end(), generate);}size_t index = 0;std::list<vector<Cell>>::iterator it1 = lCells1.begin();std::list<vector<Cell>>::iterator it2 = lCells2.begin();for (; it1 != lCells1.end() && it2 != lCells2.end(); it1++, it2++){std::cout << "lCells1 " << index << " ";std::copy((*it1).begin(), (*it1).end(), std::ostream_iterator<Cell>(std::cout, " "));std::cout << std::endl;std::cout << "lCells1 " << index << " ";std::copy((*it2).begin(), (*it2).end(), std::ostream_iterator<Cell>(std::cout, " "));std::cout << std::endl;auto inner_product = std::inner_product((*it1).begin(), (*it1).end(), (*it2).begin(), Cell{0, 0});std::cout << "inner_product: " << inner_product << std::endl;std::cout << std::endl;index++;}std::cout << std::endl;std::cout << std::endl;std::cout << std::endl;auto opt1 = [](const Cell & a, const Cell & b){Cell cell{a.x + b.x, a.y + b.y};return cell;};auto opt2 = [](const Cell & a, const Cell & b){Cell cell{a.x * b.x, a.y * b.y};return cell;};// 初始化lCells3std::list<vector<Cell>> lCells3(3, vector<Cell>(5));//用从起始值开始连续递增的值填充一个范围for (vector<Cell> &vCells : lCells3){std::generate(vCells.begin(), vCells.end(), generate);}// 初始化lCells4std::list<vector<Cell>> lCells4(3, vector<Cell>(5));//用从起始值开始连续递增的值填充一个范围for (vector<Cell> &vCells : lCells4){std::generate(vCells.begin(), vCells.end(), generate);}index = 0;std::list<vector<Cell>>::iterator it3 = lCells3.begin();std::list<vector<Cell>>::iterator it4 = lCells4.begin();for (; it3 != lCells3.end() && it4 != lCells4.end(); it3++, it4++){std::cout << "lCells1 " << index << " ";std::copy((*it3).begin(), (*it3).end(), std::ostream_iterator<Cell>(std::cout, " "));std::cout << std::endl;std::cout << "lCells1 " << index << " ";std::copy((*it4).begin(), (*it4).end(), std::ostream_iterator<Cell>(std::cout, " "));std::cout << std::endl;auto inner_product = std::inner_product((*it3).begin(), (*it3).end(), (*it4).begin(),Cell{0, 0}, opt1, opt2);std::cout << "inner_product: " << inner_product << std::endl;std::cout << std::endl;index++;}return 0;
}

输出

 


http://www.ppmy.cn/news/6688.html

相关文章

DSP-离散时间系统

目录 概念&#xff1a; 累加器(Accumulator)&#xff1a; N点滑动滤波器&#xff1a; 离散时间系统的分类 &#xff1a; 线性系统 Linear System 移不变系统 Shift-Invariant Systems 因果系统 Causal System 稳定系统 Stable System 无源&#xff08;passive&#x…

C#语言实例源码系列-伪装文件

专栏分享点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册 &#x1f449;关于作者 众所周知&#xff0c;人生是一个漫长的流程&#xff0c;不断克服困难&#xff0c;不断反思前进的过程。在这个过程中…

双软认证”包含的具体内容

为贯彻落实《国务院关于印发新时期促进集成电路产业和软件产业高质量发展若干政策的通知》&#xff08;国发〔2020〕8号&#xff09;精神&#xff0c;根据《关于促进集成电路产业和软件产业高质量发展企业所得税的公告》&#xff08;财政部 税务总局 国家发展改革委 工业和信…

网络文件系统NFS

一、Linux文件系统概述 1、Linux文件系统 Linux下常见的有DOS文件系统类型msdos,windows下的FAT系列(fat16和FAT32)和NTFS文件系统,光盘文件系统ISO-9660,单一文件系统ext2和日志文件系统ext3、ext4、xfs,集群文件系统gfs(Red Hat Global File System)、ocfs2(oracl…

基于Xlinx的时序分析与约束(5)----衍生时钟约束

衍生时钟约束语法 衍生时钟&#xff08;Generated Clocks&#xff0c;又称为生成时钟&#xff09;是指由设计中已有的主时钟通过倍频、分频或者相移等操作后产生的新的时钟信号&#xff0c;如由MMCM或PLL或由组合逻辑生成的倍、分频时钟信号。 衍生时钟约束必须指定时钟源&…

NetSuite Decode函数

昨天是平安夜&#xff0c;小家伙仍然为圣诞老人的到来准备了礼物&#xff0c;这是他的传统。每年为了感谢圣诞老人和驯鹿的到来&#xff0c;他都会准备上点心、水果。今年&#xff0c;他认为驯鹿可能需要电力&#xff0c;所以准备了电池给它们享用。 真希望天真一直伴随他的成长…

docker入门以及常见的命令

目录 1. 什么是docker 2. docker的核心组件 3. docker的安装 3.1 安装的先决条件 3.2.1 ubuntu安装docker 3.2.2 CentOS安装docker 3.3 配置镜像加速器 4. 镜像常用操作 4.1 搜索镜像 4.2 镜像下载 4.3 查看宿主机中的镜像 4.3 删除镜像 5. 容器常用命令 5.1 运行…

RHI_图形API对比(Vulkan、DirectX 12/11、Metal、WebGPU、OpenGL)

本文我们将回顾一下现代图形 API在设计和数据结构上与传统图形 API&#xff08;如 OpenGL&#xff09;的对比情况。 图形处理单元 &#xff08;GPU&#xff09; 是异步计算单元&#xff0c;可以处理大量数据&#xff0c;例如复杂的网格几何体、图像纹理、输出帧缓冲区、转换矩…