valarray 除元素
valarray divide its element
当我将 valarray 除以它的第一个元素时,只有第一个元素变为 1,其他元素保持原来的值。
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
arr=arr/arr[0]; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
实际输出为:
1 10 15 20 25
预期输出为:
1 2 3 4 5
为什么实际输出不符合预期?
我使用 g++(4.8.1) 和 -std=c++11
这个有效:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
auto v = arr[0];
arr=arr/v; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
问题是您正在尝试使用您正在同时修改的数组 (arr
) 中的值 (arr[0]
)。
直观地说,一旦您通过 arr[0]/arr[0]
更新了 arr[0]
,它包含什么值?
好吧,这就是从现在开始除以其他值的值...
请注意,这同样适用于 arr/=arr[0]
(首先,arr[0]/arr[0]
比其他所有发生在 for 循环或类似的循环中)。
还要注意从documentation一个std::valarray
一个returns一个T&
那个operator[]
。这证实了上面的假设:它转向1
作为你迭代的第一步,那么其他所有操作都没有用。
只需复制它即可解决问题,如示例代码所示。
发生这种情况的详细信息是由于 valarray
中为提高性能而使用的实施技巧。 libstdc++ 和 libc++ 都使用 expression templates 作为 valarray
操作的结果,而不是立即执行操作。这是 C++ 标准中的 [valarray.syn] p3 明确允许的:
Any function returning a valarray<T>
is permitted to return an object of another type, provided all the
const member functions of valarray<T>
are also applicable to this type.
在您的示例中发生的情况是 arr/arr[0]
没有立即执行除法,而是 returns 一个像 _Expr<__divide, _Valarray, _Constant, valarray<double>, double>
这样的对象引用了 arr
和对 arr[0]
的引用。当该对象被分配给另一个 valarray
时,执行除法运算并将结果直接存储到分配的 left-hand 端(这避免了创建一个临时的 valarray
来存储结果然后将其复制到 left-hand 侧)。
因为在您的示例中,left-hand 端是同一个对象,arr
,这意味着一旦arr
中的第一个元素已用结果更新。
换句话说,最终结果是这样的:
valarray<double> arr{5, 10, 15, 20, 25};
struct DivisionExpr {
const std::valarray<double>& lhs;
const double& rhs;
};
DivisionExpr divexpr = { arr, arr[0] };
for (int i = 0; i < size(); ++i)
arr[i] = divexpr.lhs[i] / divexpr.rhs;
for-loop 的第一次迭代会将 arr[0]
设置为 arr[0] / arr[0]
,即 arr[0] = 1
,然后所有后续迭代都会设置 arr[i] = arr[i] / 1
,这意味着值不变。
我正在考虑更改 libstdc++ 实现,以便表达式模板将直接存储 double
而不是保存引用。这意味着 arr[i] / divexpr.rhs
将始终评估 arr[i] / 5
而不是使用 arr[i]
.
的更新值
当我将 valarray 除以它的第一个元素时,只有第一个元素变为 1,其他元素保持原来的值。
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
arr=arr/arr[0]; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
实际输出为:
1 10 15 20 25
预期输出为:
1 2 3 4 5
为什么实际输出不符合预期?
我使用 g++(4.8.1) 和 -std=c++11
这个有效:
#include <iostream>
#include <valarray>
using namespace std;
int main() {
valarray<double> arr({5,10,15,20,25});
auto v = arr[0];
arr=arr/v; // or arr/=arr[0];
for(int value:arr)cout << value << ' ';
return 0;
}
问题是您正在尝试使用您正在同时修改的数组 (arr
) 中的值 (arr[0]
)。
直观地说,一旦您通过 arr[0]/arr[0]
更新了 arr[0]
,它包含什么值?
好吧,这就是从现在开始除以其他值的值...
请注意,这同样适用于 arr/=arr[0]
(首先,arr[0]/arr[0]
比其他所有发生在 for 循环或类似的循环中)。
还要注意从documentation一个std::valarray
一个returns一个T&
那个operator[]
。这证实了上面的假设:它转向1
作为你迭代的第一步,那么其他所有操作都没有用。
只需复制它即可解决问题,如示例代码所示。
发生这种情况的详细信息是由于 valarray
中为提高性能而使用的实施技巧。 libstdc++ 和 libc++ 都使用 expression templates 作为 valarray
操作的结果,而不是立即执行操作。这是 C++ 标准中的 [valarray.syn] p3 明确允许的:
Any function returning a
valarray<T>
is permitted to return an object of another type, provided all the const member functions ofvalarray<T>
are also applicable to this type.
在您的示例中发生的情况是 arr/arr[0]
没有立即执行除法,而是 returns 一个像 _Expr<__divide, _Valarray, _Constant, valarray<double>, double>
这样的对象引用了 arr
和对 arr[0]
的引用。当该对象被分配给另一个 valarray
时,执行除法运算并将结果直接存储到分配的 left-hand 端(这避免了创建一个临时的 valarray
来存储结果然后将其复制到 left-hand 侧)。
因为在您的示例中,left-hand 端是同一个对象,arr
,这意味着一旦arr
中的第一个元素已用结果更新。
换句话说,最终结果是这样的:
valarray<double> arr{5, 10, 15, 20, 25};
struct DivisionExpr {
const std::valarray<double>& lhs;
const double& rhs;
};
DivisionExpr divexpr = { arr, arr[0] };
for (int i = 0; i < size(); ++i)
arr[i] = divexpr.lhs[i] / divexpr.rhs;
for-loop 的第一次迭代会将 arr[0]
设置为 arr[0] / arr[0]
,即 arr[0] = 1
,然后所有后续迭代都会设置 arr[i] = arr[i] / 1
,这意味着值不变。
我正在考虑更改 libstdc++ 实现,以便表达式模板将直接存储 double
而不是保存引用。这意味着 arr[i] / divexpr.rhs
将始终评估 arr[i] / 5
而不是使用 arr[i]
.