std::max_element 跳过 NAN
std::max_element skip over NANs
我有一个 std::vector<double>
可能包含多个 NAN
值。我想找到向量中最大的元素。我怎样才能有效地跳过比较中的 NAN
s?我想避免在每个元素上调用 isnan
。有什么想法吗?
// std::max_element([NAN,NAN,NAN,-31,-89]) = NAN
// because NAN > -31 returns NAN.
// how can I skip all NANs in the comparison?
// test 2 below is my use case.
#include <vector>
#include <iostream>
#include <cmath>
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element(v.begin(),v.end());
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
int main(){
std::vector<double> v_vec;
std::vector<double>::iterator v_vec_iter;
int imax;
double val;
std::cout << "test 1. " << std::endl;
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 18.4 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << "test 2: my case. " << std::endl;
v_vec.clear();
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 31.0 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
};
这个returns:
test 1.
max(v_vec) = 18.4
indmax(v_vec) = 3
test 2.
max(v_vec) = nan
indmax(v_vec) = 0
您可以为 max_element
提供自定义比较:
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element(v.begin(),v.end(),
[] (auto x, auto y)
{
return x < y ? true : isnan(x);
});
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
我会尝试这样的事情:
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::size_type p=0;
imax = -1;
max = std::numeric_limits<double>::lowest();
for (auto &val : v)
{
if (!std::isnan(val) && val>max)
{
imax = p;
max = val;
}
p++;
}
}
问题是 std::max_element
默认使用 std::less
作为比较器。根据它处理向量元素的顺序,NAN
可能会出现在比较的右侧。由于 all 与 NAN
s return false
进行比较,这意味着 NAN
可以显示大于所有其他元素。
换句话说,当您在带有 NAN
的向量上将 std::max_element
与默认比较器一起使用时,结果实际上是未定义的,因为它取决于实现和元素的顺序。例如,在 GCC 上,如果我将所有 NAN
放在向量的 end 处,我(随机)得到所需的结果。
因此,您别无选择,只能提供自己的比较运算符:
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
template <typename T>
struct NaNAwareLess
{
bool operator () (T a, T b) const
{
if (std::isnan(b))
{
return false; // Assume NaN is less than *any* non-NaN value.
}
if (std::isnan(a))
{
return true; // Assume *any* non-NaN value is greater than NaN.
}
return (a < b);
}
};
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element<std::vector<double>::iterator, NaNAwareLess<double> >(v.begin(),v.end(),NaNAwareLess<double>());
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
int main(){
std::vector<double> v_vec;
std::vector<double>::iterator v_vec_iter;
int imax;
double val;
std::cout << "test 1. " << std::endl;
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 18.4 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << "test 2: my case. " << std::endl;
v_vec.clear();
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 31.0 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << std::boolalpha << std::less<double>()(NAN, -33.0) << std::endl;
std::cout << std::boolalpha << std::less<double>()(-33.0, NAN) << std::endl;
};
我认为您无法避免调用 isnan
。还有另一个重要的方面:根据个人经验,我发现对 NAN
值执行操作比对任何其他值执行操作要慢 lot(可能是因为 FPU 异常处理).因此,虽然使用 isnan
可能很烦人,但它也可以对性能产生相当大的积极影响。
我有一个 std::vector<double>
可能包含多个 NAN
值。我想找到向量中最大的元素。我怎样才能有效地跳过比较中的 NAN
s?我想避免在每个元素上调用 isnan
。有什么想法吗?
// std::max_element([NAN,NAN,NAN,-31,-89]) = NAN
// because NAN > -31 returns NAN.
// how can I skip all NANs in the comparison?
// test 2 below is my use case.
#include <vector>
#include <iostream>
#include <cmath>
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element(v.begin(),v.end());
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
int main(){
std::vector<double> v_vec;
std::vector<double>::iterator v_vec_iter;
int imax;
double val;
std::cout << "test 1. " << std::endl;
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 18.4 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << "test 2: my case. " << std::endl;
v_vec.clear();
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 31.0 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
};
这个returns:
test 1.
max(v_vec) = 18.4
indmax(v_vec) = 3
test 2.
max(v_vec) = nan
indmax(v_vec) = 0
您可以为 max_element
提供自定义比较:
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element(v.begin(),v.end(),
[] (auto x, auto y)
{
return x < y ? true : isnan(x);
});
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
我会尝试这样的事情:
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::size_type p=0;
imax = -1;
max = std::numeric_limits<double>::lowest();
for (auto &val : v)
{
if (!std::isnan(val) && val>max)
{
imax = p;
max = val;
}
p++;
}
}
问题是 std::max_element
默认使用 std::less
作为比较器。根据它处理向量元素的顺序,NAN
可能会出现在比较的右侧。由于 all 与 NAN
s return false
进行比较,这意味着 NAN
可以显示大于所有其他元素。
换句话说,当您在带有 NAN
的向量上将 std::max_element
与默认比较器一起使用时,结果实际上是未定义的,因为它取决于实现和元素的顺序。例如,在 GCC 上,如果我将所有 NAN
放在向量的 end 处,我(随机)得到所需的结果。
因此,您别无选择,只能提供自己的比较运算符:
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
template <typename T>
struct NaNAwareLess
{
bool operator () (T a, T b) const
{
if (std::isnan(b))
{
return false; // Assume NaN is less than *any* non-NaN value.
}
if (std::isnan(a))
{
return true; // Assume *any* non-NaN value is greater than NaN.
}
return (a < b);
}
};
void vector_max(std::vector<double> v, double &max, int &imax){
std::vector<double>::iterator v_iter;
v_iter = std::max_element<std::vector<double>::iterator, NaNAwareLess<double> >(v.begin(),v.end(),NaNAwareLess<double>());
imax = std::distance(v.begin(), v_iter);
max = *v_iter;
}
int main(){
std::vector<double> v_vec;
std::vector<double>::iterator v_vec_iter;
int imax;
double val;
std::cout << "test 1. " << std::endl;
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 18.4 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << "test 2: my case. " << std::endl;
v_vec.clear();
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( NAN );
v_vec.push_back( -33.0 );
v_vec.push_back( -124.0 );
v_vec.push_back( -31.0 );
v_vec.push_back( 31.0 );
vector_max(v_vec,val,imax);
std::cout << "max(v_vec) = " << val << std::endl;
std::cout << "indmax(v_vec) = " << imax << std::endl;
std::cout << std::boolalpha << std::less<double>()(NAN, -33.0) << std::endl;
std::cout << std::boolalpha << std::less<double>()(-33.0, NAN) << std::endl;
};
我认为您无法避免调用 isnan
。还有另一个重要的方面:根据个人经验,我发现对 NAN
值执行操作比对任何其他值执行操作要慢 lot(可能是因为 FPU 异常处理).因此,虽然使用 isnan
可能很烦人,但它也可以对性能产生相当大的积极影响。