【问题标题】:Ignore zero in std::min and calculate minimum of other numbers忽略 std::min 中的零并计算其他数字的最小值
【发布时间】:2021-11-07 16:18:13
【问题描述】:

非零数的最小值:

#include <iostream>
#include <algorithm>

int main() {
    
        double s1 = 1000;
        double s2 = 400;
        double s3 = 300;
        double s4 = 10;     
            
        double minimum = std::min({s1, s2, s3, s4});
        
        std::cout<<minimum<<"\n";
        
        double var = 1/minimum;
        
        std::cout<<var;
}

这工作正常并返回:

10
0.1

问题是当其中一个数字为零时:

#include <iostream>
#include <algorithm>

int main() {
    
        double s1 = 1000;
        double s2 = 400;
        double s3 = 300;
        double s4 = 0;      
            
        double minimum = std::min({s1, s2, s3, s4});
        
        std::cout<<minimum<<"\n";
        
        double var = 1/minimum;
        
        std::cout<<var;
}

返回:

0
inf

预期结果:

300
0.00333333

如何在计算中忽略零?

【问题讨论】:

  • std::min 函数按预期工作,它返回最小值。如果您想忽略零,则需要将其从传递给std::min 的值列表中删除。一种简单的方法是将值放入容器中,使用 std::remove_if 删除零,然后使用例如std::min_element 在容器上。
  • 你可以传递一个 lambda 作为第二个参数来比较运算符并忽略你想忽略的数字。

标签: c++ minimum divide-by-zero


【解决方案1】:

或者像这样

#include <algorithm>
#include <limits>
#include <vector>

template<std::size_t N>
constexpr double min_no_zero(const double (&values)[N])
{
    static_assert(N>0,"There must be at least one number");
    double min = std::numeric_limits<double>::max();
    for (const auto value : values)
    {
        if ( value != 0.0 )
        {
            min = std::min(min, value);
        }
    }
    return min;
}

int main()
{
    constexpr double s1 = 1000.0;
    constexpr double s2 = 400.0;
    constexpr double s3 = 0.0;
    constexpr double s4 = 10.0;

    static_assert( min_no_zero({ s1, s2, s3, s4 }) == 10.0);
}

【讨论】:

  • 如果所有值都为零或N 为零,则返回std::numeric_limits&lt;double&gt;::max()
  • @G.Sliepen 好点,但唯一的要求是它不应该返回 0.0。不过,我将添加对 0 元素的检查;)也许要求应该是用 std::numeric_limits::epsilon() 替换 0.0。我将把它留给提出问题的人。
【解决方案2】:

std::min 工作正常,如果您有特殊要求,您可以传递具有以下签名的比较函数:

bool cmp(const Type1 &a, const Type2 &b);

作为第二个std::min 函数参数(Compare 模板参数):

#include <iostream>
#include <algorithm>

int main()
{
    double s1 = 1000;
    double s2 = 400;
    double s3 = 300;
    double s4 = 0;

    auto const ignore_zero = [](auto const& a, auto const& b) -> bool {
        if(0 == a)
        {
            return false;
        }
        else if(0 == b)
        {
            return true;
        }
        return a < b;
    };

    double minimum = std::min({s1, s2, s3, s4}, ignore_zero);
    std::cout << minimum << "\n";
}

但是很奇怪,如果你对你的代码有这样的特殊要求,我建议你:

  1. 尝试重新设计您的程序。
  2. 使用函数/函子助手:
#include <algorithm>
#include <iostream>
#include <vector>

namespace core::helper
{
template<typename T>
struct special_find final
{
    std::vector<T> nums;
    explicit special_find(std::initializer_list<T> nums_)
        : nums(std::move(nums_))
    {
    }

    auto min() const
    {
        return *std::min_element(nums.cbegin(), nums.cend());
    }
    special_find& ignore(T const& value)
    {
        nums.erase(std::remove_if(nums.begin(), nums.end(), [&value](auto const & item)
        {
            return item == value;
        }), nums.end());
        return *this;
    }
};
} // namespace core::helper

int main()
{
    double s1 = 1000;
    double s2 = 400;
    double s3 = 300;
    double s4 = 0;

    auto const min = core::helper::special_find({s1, s2, s3, s4}).ignore(0).min();
    std::cout << min << "\n";
}

【讨论】:

  • 您的ignore_zero lambda 不满足Compare 的要求,我认为这会导致行为未定义。我运行了一个测试,在其中复制了您的代码,然后交换了s1s4 的初始化(所以s1 是0,而s4 是1000),编译并得到0 作为结果。问题是!ignore_zero(a,b) &amp;&amp; !(ignore_zero(b,a) 没有建立等价关系。更具体地说,只要 a 不为零,ignore_zero(a,0) 的计算结果就应该为 true
  • 另一个问题是,如果所有参数都为零,这仍然可以返回零。
【解决方案3】:

确保不要将 0 传递给 min。我想这是不知道您的输入是什么样子的唯一通用答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    相关资源
    最近更新 更多