Why is this function producing incorrect values?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite












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" );




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



When I call this function in main using an 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';


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';


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.










share|improve this question



















  • 3




    It should be returning 5.12, not 6.4.
    – jwimberley
    24 mins ago






  • 1




    @jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
    – Francis Cugler
    19 mins ago






  • 2




    Did you try the change that @Angew suggested.
    – drescherjm
    19 mins ago






  • 2




    Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
    – molbdnilo
    10 mins ago







  • 1




    @FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
    – molbdnilo
    3 mins ago















up vote
6
down vote

favorite












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" );




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



When I call this function in main using an 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';


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';


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.










share|improve this question



















  • 3




    It should be returning 5.12, not 6.4.
    – jwimberley
    24 mins ago






  • 1




    @jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
    – Francis Cugler
    19 mins ago






  • 2




    Did you try the change that @Angew suggested.
    – drescherjm
    19 mins ago






  • 2




    Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
    – molbdnilo
    10 mins ago







  • 1




    @FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
    – molbdnilo
    3 mins ago













up vote
6
down vote

favorite









up vote
6
down vote

favorite











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" );




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



When I call this function in main using an 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';


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';


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.










share|improve this question















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" );




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



When I call this function in main using an 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';


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';


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.







c++ templates stdvector






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 19 mins ago

























asked 30 mins ago









Francis Cugler

3,95811227




3,95811227







  • 3




    It should be returning 5.12, not 6.4.
    – jwimberley
    24 mins ago






  • 1




    @jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
    – Francis Cugler
    19 mins ago






  • 2




    Did you try the change that @Angew suggested.
    – drescherjm
    19 mins ago






  • 2




    Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
    – molbdnilo
    10 mins ago







  • 1




    @FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
    – molbdnilo
    3 mins ago













  • 3




    It should be returning 5.12, not 6.4.
    – jwimberley
    24 mins ago






  • 1




    @jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
    – Francis Cugler
    19 mins ago






  • 2




    Did you try the change that @Angew suggested.
    – drescherjm
    19 mins ago






  • 2




    Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
    – molbdnilo
    10 mins ago







  • 1




    @FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
    – molbdnilo
    3 mins ago








3




3




It should be returning 5.12, not 6.4.
– jwimberley
24 mins ago




It should be returning 5.12, not 6.4.
– jwimberley
24 mins ago




1




1




@jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
– Francis Cugler
19 mins ago




@jwimberley you are correct; I must of added the values into windows calc wrong... it is 5.12 and not 6.4. but the function was still producing incorrect values.
– Francis Cugler
19 mins ago




2




2




Did you try the change that @Angew suggested.
– drescherjm
19 mins ago




Did you try the change that @Angew suggested.
– drescherjm
19 mins ago




2




2




Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
– molbdnilo
10 mins ago





Use less arbitrary test cases – start with ones where it's easy to tell that they're wrong. 1.5, 1.5 is enough to expose the bug, and if you didn't have the unnecessary special case for a one-element input, 1.5 would suffice.
– molbdnilo
10 mins ago





1




1




@FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
– molbdnilo
3 mins ago





@FrancisCugler I know what it's for. Unless you know that the vast majority of averaging will be of single-element containers and you've measured the performance and determined that it matters, it's a pointless premature optimisation that only adds complexity.
– molbdnilo
3 mins ago













1 Answer
1






active

oldest

votes

















up vote
11
down vote



accepted










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() );


(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:



  • 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.





share|improve this answer




















  • Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
    – Francis Cugler
    9 mins ago











  • @FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
    – Angew
    8 mins ago






  • 1




    @FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
    – Algirdas Preidžius
    7 mins ago










  • Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
    – YSC
    2 mins ago










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53189928%2fwhy-is-this-function-producing-incorrect-values%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
11
down vote



accepted










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() );


(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:



  • 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.





share|improve this answer




















  • Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
    – Francis Cugler
    9 mins ago











  • @FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
    – Angew
    8 mins ago






  • 1




    @FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
    – Algirdas Preidžius
    7 mins ago










  • Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
    – YSC
    2 mins ago














up vote
11
down vote



accepted










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() );


(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:



  • 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.





share|improve this answer




















  • Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
    – Francis Cugler
    9 mins ago











  • @FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
    – Angew
    8 mins ago






  • 1




    @FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
    – Algirdas Preidžius
    7 mins ago










  • Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
    – YSC
    2 mins ago












up vote
11
down vote



accepted







up vote
11
down vote



accepted






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() );


(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:



  • 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.





share|improve this answer












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() );


(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:



  • 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.






share|improve this answer












share|improve this answer



share|improve this answer










answered 26 mins ago









Angew

130k11244336




130k11244336











  • Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
    – Francis Cugler
    9 mins ago











  • @FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
    – Angew
    8 mins ago






  • 1




    @FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
    – Algirdas Preidžius
    7 mins ago










  • Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
    – YSC
    2 mins ago
















  • Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
    – Francis Cugler
    9 mins ago











  • @FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
    – Angew
    8 mins ago






  • 1




    @FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
    – Algirdas Preidžius
    7 mins ago










  • Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
    – YSC
    2 mins ago















Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
– Francis Cugler
9 mins ago





Sounds good, now with the if constexpr on the failed case: should I be throwing std::runtime_error(...) like I am or should I use: static_assert(dependent_false<T>::value, "Must be arithmetic"); instead? What's the major differences between the two...
– Francis Cugler
9 mins ago













@FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
– Angew
8 mins ago




@FrancisCugler It depends on what you want to achieve. If you want a compile-time error, do the static_assert (and you can get rid of that if altogether). If you actually want a runtime error, throw one.
– Angew
8 mins ago




1




1




@FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
– Algirdas Preidžius
7 mins ago




@FrancisCugler static_assert is evaluated at compile time, while throw is evaluated at runtime. Presumably you would want to check as many things as possible, at compile time.
– Algirdas Preidžius
7 mins ago












Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
– YSC
2 mins ago




Another comment unrelated to the core of the question: Better than using the std::is_arithmetic trait, you should write a custom trait (or a concept) to check than T provides a + and a /. This way, a type mimicking an arithmetic type (e.g. std::complex) could be used.
– YSC
2 mins ago

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53189928%2fwhy-is-this-function-producing-incorrect-values%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

List of Gilmore Girls characters

Confectionery