C++标准库提供了一个class valarray用以进行数值数组的运算。
它声明于头文件<valarray>
namespace std{
template<class T> class valarray; //numeric array of type T
class slice;
template<class T> class slice_array; //slice out of a valarray
class gslice;
template<class T> class gslice_array; //a generalized slice
template<class T> calss mask_array; //a masked valarray
template<class T> class indirect_array; //an indirected valarray
}
- valarray是核心类别,管理一个数值数组
- slice和gslice用来为valarray提供切割(slice)和子集(subset)操作
- slice_array,gslice_array,mask_array,indirect_array是内部辅助类别,用来存放临时的数值或数据,你不能在应用程序中直接使用它们,它们由valarray的某些操作过程间接产生。
valarrays的构造
构造valarray时,通常应该将元素的数量当作参数传入:
std::valarray<int> val(10); //valarray of 10 ints with value 0
std::valarray<float> val(5.7,10); //valarray of ten floats with value 5.7
如果你只传入一个参数,它将被视为valarray的大小,各元素则以其型别的缺省构造函数加以初始化。如果元素是基本型别,初值就是0。如果你传入第二个参数,那么第一个参数就是元素初值,第二个参数就是元素个数。注意这里的行为和C++标准程序库的其他class的习惯不同,所有STL容器都是把第一参数视为元素个数,第二参数视为元素初值。
Valarray的各项操作
valarray可以通过下标操作符来存取某个元素,第一个元素的索引为0,此外还定义了所有的普通数值运算(加、减、乘、模数、反相、位操作、比较操作、逻辑操作、赋值操作),这些操作符会针对参与运算的每一个元素被调用起来,因此valarray的运算结果也是一个valarray,例如
va1 = va2 * va3;
等同于:
va1[0] = va2[0] * va3[0];
va1[1] = va2[1] * va3[1];
va1[2] = va2[2] * va3[2];
...
如果是二元操作符,操作数之一可以是元素型别的某个单值,这种情况下,该值将与另一个操作数(某个valarray)中的每一个元素组合运算,例如
va1 = 4 * va2;
等同于:
va1[0] = 4 * va2[0];
va1[1] = 4 * va2[1];
va1[2] = 4 * va2[2];
...
注意这个单值的型别必须和valarray的元素的型别完全一致,因此假如
std::valarray<double> va(20);
...
va=4 * va;// ERROR type mistach
这个程序语句就无法运行。
下面这个示例展示valarray的简单用法:
#include<iostream>
#include<valarray>
using namespace std;
template <class T>
void printValarray(const valarray<T>& va)
{
for (int i = 0; i < va.size(); ++i)
{
cout << va[i] << " ";
}
cout << endl;
}
int main()
{
//define two valrray with ten elements
valarray<double> va1(10), va2(10);
//assign values to the first valarray
for (int i = 0; i < 10; ++i)
{
va1[i] = i * 1.1;
}
//assign all -1 to second valarray
va2 = -1;
printValarray(va1);
printValarray(va2);
//print minimum,maximum and sum of the first valarray
cout << "min(): " << va1.min() << endl;
cout << "max(): " << va1.max() << endl;
cout << "sum(): " << va1.sum() << endl;
//assign values of the first to the second valarray
va2 = va1;
//remove all elements of the first valarray
va1.resize(0);
printValarray(va1);
printValarray(va2);
}
超越函数
超越计算(三角运算和指数运算)的定义如同一般数值运算:运算目标是valarray中的所有元素,对于二元运算,操作数之一可以是隶属元素型别之下的某个单值——这种情况下此一单值将和另一操作数(某valarray)的每一个元素组合运算。
下面展示超越函数的用法:
#include<iostream>
#include<valarray>
using namespace std;
template<class T>
void printValarray(const valarray<T> & va)
{
for (int i = 0; i < va.size(); ++i)
{
cout << va[i] << " ";
}
cout << endl;
}
int main()
{
//create and initialize valarray with nine elements
valarray<double> va(9);
for (int i = 0; i < va.size(); ++i)
{
va[i] = i * 1.1;
}
//print valarray
cout << "va: ";
printValarray(va);
//double values in the valarray
va *= 2.0;
//print valarray
cout << "va: ";
printValarray(va);
//create second valarray initialized by the values of the first plus 10
valarray<double> vb;
vb = va + 10.0;
//print valarray
cout << "vb: ";
printValarray(vb);
//create thirs valarray as a result of processing both existing valarrays
valarray<double>vc;
vc = sqrt(va) + vb / 2.0 - 1.0;
//print valarray
cout << "vc: ";
printValarray(vc);
}
valarray的子集
定义valarray子集的方法有四种:
- slices(切割)
- general slice(一般化切割)
- Masked subsets(屏蔽式子集)
- Indirect subsets(间接式子集)
Slices(切割)
一次切割动作(一个slice)定义出一个索引集,其具备三个属性
①起始索引②元素数量(size,大小)③元素间距(stride,步幅)
可以将这三个属性以上述次序作为参数,传给class slice的构造函数,例如以下表达式指定4个元素,从索引2开始,间距为3
slice(2,4,3)
其实也就是指定了2,5,8,11这四个索引所对应的元素
当然也可以设定间距为负数,但是必须保证这些索引都是合法的。
#include<iostream>
#include<valarray>
using namespace std;
template<class T>
void printValarray(const valarray<T> va, int num)
{
for (int i = 0; i < va.size()/num; ++i)
{
for (int j = 0; j < num; ++j)
{
cout << va[i * num + j] << " ";
}
cout << endl;
}
cout << endl;
}
int main()
{
valarray<double> va(12);
//fill valarray with values
for (int i = 0; i < 12; ++i)
{
va[i] = i;
}
printValarray(va, 3);
va[slice(0, 4, 3)] = pow(valarray<double>(va[slice(1, 4, 3)]), valarray<double>(va[slice(2, 4, 3)]));
printValarray(va, 3);
//create valarray with three times the thrid element of va
valarray<double> vb(va[slice(2, 4, 0)]);
//multiply the thrid column by the elements of vb
va[slice(2, 4, 3)] *= vb;
printValarray(va, 3);
//print the square root of the elements in the second row
printValarray(sqrt(valarray<double>(va[slice(3, 3, 1)])), 3);
//double the elements in the third row
va[slice(2, 4, 3)] = valarray<double>(va[slice(2, 4, 3)]) * 2.0;
printValarray(va, 3);
}
General Slices(一般化切割)
Gerenal slices 或称gslices,是slices的一般形式,与slices相似。大体上gslices跟slices有以下相同属性
①起始索引②元素数量(size,大小)③元素间距(stride,步幅)
和slices不同之处在于,gslices的元素数量和间距也是一个数组,其中的元素个数和其维度相同,假设有下列gslices:
start:2
size:[4]
stride:[3]
则这个gslices和一般的slices相同,然而如果gslices如下:
start:2
size:[2 4]
stride:[10 3]
那么这个gslices处理的是二维,所以这个gslices从索引2开始,以间距10取元素2次,以间距3取元素4次
2 5 8 11
12 15 18 21
下面是一个三维gslices
start:2
size:[3 2 4]
stride:[30 10 3]
从索引2开始,以间距30取3个值,以间距10取2个值,以间距3取4个值
2 5 8 11
12 15 18 21
32 35 38 41
42 45 48 51
62 65 68 71
72 75 78 81
能够运用数组来定义大小和间距,是gslices和slices之间的唯一区别。
全局性的数值函数
pow() | 求幂函数 |
exp() | 指数函数 |
sqrt() | 平方根 |
log() | 自然对数 |
log10() | 以10为底的对数 |
sin() | 正弦函数 |
cos() | 余弦函数 |
tan() | 正切函数 |
asin() | 反正弦函数 |
acos() | 反余弦函数 |
atan() | 反正切函数 |
atan2() | 商的反正切函数 |
ceil() | 大于某个浮点数的最小整数 |
floor() | 小于某个浮点数的最大整数 |
fabs() | 浮点数的绝对值 |
fmod() | 浮点数相除的余数 |
frexp() | 将一个浮点数转换成小数部分和整数部分 |
ldexp() | 将某个浮点数乘以2的某个整数次幂 |
modf() | 将浮点数分离为一个带正负号的整数和一个分数 |
abs() | 求某个int的绝对值 |
labs() | 求某个long的绝对值 |
div() | 求int相除的商和余数 |
ldiv() | 求long 相除的商和余数 |
srand() | 随机数产生器(种下新的随机数种子) |
rand() | 随机数产生器(取得一个随机数) |