4 ms·
I think it's mostly a fad issue. Normal loops and if statements are just as possible to hit with a static analyzer. But the very fact that they look easy makes
by knome 2y ago
I think it's mostly a fad issue. Normal loops and if statements are just as possible to hit with a static analyzer. But the very fact that they look easy makes a certain kind of programmer see them as beneath them. They want the complex looking code, even if it's functionally equivalent and semantically no more sound. They like the visual noise and complexity of it. It rubs their egos the right way.
- nine_k 2y agoLoops are more complex. They expose more implementation details, worse, they "expose" irrelevant details. Unless your CPU is very simple, like a Cortex M0, the C compiler will likely rewrite your loop using vector instructions (think MMX / SSE / Neon), leaving an unrecognizable mess where a neat loop with an index used to be. C was invented to match PDP-9 and PDP-11, and it matches them beautifully. Constructs like *a++ = *b++ directly compile to instructions like MOV (R1)+, (R2)+, etc. But however much I may like the beauty and simplicity of the PDP-11 architecture, it belongs to the past, or maybe to simplest MCUs. C no longer matches hardware all that well, and especially the idioms of C from classic books written 30-40 years ago don't match modern hardware woefully, if you care about the last bit of performance. (If you don't, take C#, Java, Go, even V8; they are plenty fast with JIT compilers.)
- knome 2y ago00106 template<typename _InputIterator, typename _Tp, typename _BinaryOperation> 00107 _Tp 00108 accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, 00109 _BinaryOperation __binary_op) 00110 { 00111 // concept requirements 00112 __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) 00113 __glibcxx_requires_valid_range(__first, __last); 00114 00115 for (; __first != __last; ++__first) 00116 __init = __binary_op(__init, *__first); 00117 return __init; 00118 } https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.0/stl__numeric_8h-source.html#l00108 It's just a loop. The compiler is doing all of the same transformations regardless of whether you use the higher order function or just write a loop yourself. -------------- _STD_BEGIN _EXPORT_STD template <class _InIt, class _Ty, class _Fn> _NODISCARD _CONSTEXPR20 _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val, _Fn _Reduce_op) { // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last), using _Reduce_op _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); for (; _UFirst != _ULast; ++_UFirst) { #if _HAS_CXX20 _Val = _Reduce_op(_STD move(_Val), *_UFirst); #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _Val = _Reduce_op(_Val, *_UFirst); #endif // ^^^ !_HAS_CXX20 ^^^ } return _Val; } https://github.com/microsoft/STL/blob/63354c3fa9c1fb2ab1fccb58c47d23c6af1c290f/stl/inc/numeric#L24 Also just a loop in MS' standard lib.
- nine_k 2y agoTry -O2 or -O3 like you would in a release build. See https://stackoverflow.com/a/50786881 https://stackoverflow.com/a/50786881
- knome 2y agoOptimization levels aren't going to care if you're using std::accumulate or not. They'll either analyze the loop directly, or they'll analyze it after munging it through the template function instantiation code and inlining the results of the template function. After that, both are doing what you originally said, lifting the C into an abstract form and analyzing it for whether parallel computation can be applied. Hell, the code to SSE enabled asm examples they give in the comment you link are just plain for loops.
- danlugo92 2y agoNice dissertation but loops is all you need.