为什么这个函数产生不正确的值? [英] Why is this function producing incorrect values?
问题描述
我有一个简单的函数模板来计算一个容器的平均值:
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
的结果).
(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 modifyvalues
. - If you call the function with a
T
which is not valid forstd::accumulate
(e.g. not arithmetic), you will get a compile-time error. The topmostif
would have to beif constexpr
to work the way you want it to.
这篇关于为什么这个函数产生不正确的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!