为什么这个函数产生不正确的值? [英] Why is this function producing incorrect values?

查看:21
本文介绍了为什么这个函数产生不正确的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的函数模板来计算一个容器的平均值:

I have a simple function template to calculate the average value of a container:

template<typename T>
T array_average( std::vector<T>& values ) {
    if( std::is_arithmetic<T>::value ) {
        if( !values.empty() ) {
            if( values.size() == 1 ) {
                return values[0];
            } else { 
                return (static_cast<T>( std::accumulate( values.begin(), values.end(), 0 )  ) / static_cast<T>( values.size() ) );
            }
        } else {
            throw std::runtime_error( "Can not take average of an empty container" ); 
        }
    } else {
        throw std::runtime_error( "T is not of an arithmetic type" );
    }
}

我在上面的 static_cast<> 中添加,以尝试强制计算为所需的类型 .

I added in the static_cast<>s above to try to force the calculation to the desired type <T>.

当我使用 uint64_t

std::vector<uint64_t> values{ 1,2,3,4,5,6,7,8,9,10,11,12 };
std::cout << array_average( values ) << '\n';

这段代码确实产生了 MSVC 的编译器警告 C4244 由于转换可能会丢失数据,但它运行正常,这给了我预期的结果,它打印出 6 到控制台.这是正确的,因为实际值为 6.5 但由于整数除法中的截断 6 是正确的.

This codes does produce MSVC's compiler warning C4244 possible loss of data due to conversion, but it runs properly and this gives me the expected result and it prints out 6 to the console. This is correct as the actual value is 6.5 but due to the truncation in integer division 6 is correct.

现在如果我用上面的函数代替:

Now If I use the function above with this instead:

std::vector<double> values { 2.0, 3.5, 4.5, 6.7, 8.9 };
std::cout << array_average( values2 ) << '\n';

这应该给我 5.12 的结果,但它显示的是 4.6.这也给了我与上面相同的编译器警告,但它运行时没有运行时错误(执行中断)但给了我不正确的结果.

This should give me a result of 5.12 however it is displaying 4.6 instead. This also gives me the same compiler warning as above, but it runs without a runtime error (break in execution) but is giving me incorrect results.

我不确定我的函数中的错误在哪里.我不知道这是不是由于编译器警告,还是我自己设计函数的方式.

I'm not sure where the bug is in my function. I don't know if this is due to that compiler warning or not, or if it's the way I designed the function itself.

-编辑-

有用户建议这可能是此Q/A 我无法反驳它回答或不回答我的问题的事实.在问这个问题的时候;我不知道该错误来自对 std::accumulate 本身的不当使用.我不确定它是否来自编译器警告,该警告与由于转换可能导致数据丢失有关,或者我是否错误地转换了它,或者它是否来自我通常如何实现此功能.在提供链接之前,我已经接受了在此页面上找到的答案.我将保留此 Q/A 以供将来参考和读者!除此之外,我非常感谢提供的链接,因为它确实有助于了解错误在我的代码中的位置、错误是什么以及导致它的原因,以及除了此页面上接受的答案之外如何正确修复它.

A user has suggested that this may be a duplicate of this Q/A I can not argue against the fact that it does or does not answer my question. At the time of asking this question; I did not know that the bug was coming from the improper use of std::accumulate itself. I wasn't sure if it was coming from the compiler warning that pertained to possible loss of data due to conversion, or if I was casting it wrong, or if it was in how I implemented this function in general. I had already accepted the answer that is found on this page before the link was provided. I will leave this Q/A as is for future reference and readers! Other than that I do appreciate the provided link as it does help to understand where the error was located in my code, what the error was and what was causing it, and how to properly fix it in addition to the accepted answer on this page.

推荐答案

您的 static_cast 位置错误.您正在投射累积的 result,但让累积以初始项的类型运行(此处为 0,即 int).所以改为这样做:

Your static_cast is in the wrong place. You're casting the result of the accumulation, but letting the accumulation run in the type of the initial term (here 0, which is int). So do this instead:

return std::accumulate( values.begin(), values.end(), static_cast<T>(0) ) / static_cast<T>( values.size() );

(注意 4.6 确实是 static_cast(2 + 3 + 4 + 6 + 8)/5.0 的结果).

(Note that 4.6 is indeed the result of static_cast<double>(2 + 3 + 4 + 6 + 8) / 5.0).

与问题核心无关的评论:

Comments unrelated to the core of the question:

  • 该函数应该采用 const std::vector&,因为它不会修改 values.
  • 如果您使用对 std::accumulate 无效的 T 调用函数(例如,不是算术),您将收到编译时错误.最顶层的 if 必须是 if constexpr 才能按照您希望的方式工作.
  • The function should be taking const std::vector<T>&, because it doesn't modify values.
  • If you call the function with a T which is not valid for std::accumulate (e.g. not arithmetic), you will get a compile-time error. The topmost if would have to be if constexpr to work the way you want it to.

这篇关于为什么这个函数产生不正确的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆