Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Why pass doubles as const references?

Reply
Thread Tools

Why pass doubles as const references?

 
 
army1987
Guest
Posts: n/a
 
      02-10-2013
Is there any good reason to declare a function parameter as `const double
&foo` rather than just `double foo`? I can see the point of that when
passing a very large object, but with a double I'd expect any improvement
in performance to be negligible. I've seen code using the former, but I
guess that's because it was translated from Fortran, where all function
arguments are passed by reference -- or am I missing something?

--
[ T H I S S P A C E I S F O R R E N T ]
Troppo poca cultura ci rende ignoranti, troppa ci rende folli.
-- fathermckenzie di it.cultura.linguistica.italiano
<http://xkcd.com/397/>
 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      02-10-2013
army1987 wrote:
> Is there any good reason to declare a function parameter as `const double
> &foo` rather than just `double foo`? I can see the point of that when
> passing a very large object, but with a double I'd expect any improvement
> in performance to be negligible. I've seen code using the former, but I
> guess that's because it was translated from Fortran, where all function
> arguments are passed by reference -- or am I missing something?


On most current systems, I would expect the performance to decrease
(building the reference) rather than increase passing a double by const
reference.

--
Ian Collins
 
Reply With Quote
 
 
 
 
Rui Maciel
Guest
Posts: n/a
 
      02-10-2013
army1987 wrote:

> Is there any good reason to declare a function parameter as `const double
> &foo` rather than just `double foo`? I can see the point of that when
> passing a very large object, but with a double I'd expect any improvement
> in performance to be negligible. I've seen code using the former, but I
> guess that's because it was translated from Fortran, where all function
> arguments are passed by reference -- or am I missing something?


In architectures where pointers are 64-bit wide there is no point in passing
primitives as const references. Doing so even introduces a performance
penalty, because it is just as expensive to pass a double as is a pointer,
and a reference implies a redirection.

If I'm not mistaken, this point is covered in one of Scott Meyer's effective
C++ books.


Rui Maciel
 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      02-11-2013
On 2/10/2013 3:52 PM, army1987 wrote:
> Is there any good reason to declare a function parameter as `const double
> &foo` rather than just `double foo`? I can see the point of that when
> passing a very large object, but with a double I'd expect any improvement
> in performance to be negligible. I've seen code using the former, but I
> guess that's because it was translated from Fortran, where all function
> arguments are passed by reference -- or am I missing something?


Perhaps you're missing the age of the code in question. Fifteen years
ago passing a double by a const reference would have a noticeable
difference to passing by value. Not anymore, most likely.

V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      02-11-2013
On Sunday, 10 February 2013 22:52:26 UTC+2, army1987 wrote:
> Is there any good reason to declare a function parameter as `const double
> &foo` rather than just `double foo`?


There can be good reasons. For example if it is one of overloads and
overloads accept const& for several class types plus double. Making it
different from other overloads may (or may not) cause subtle difficulties
of usage (say picking pointer to that overload) from template.

> I can see the point of that when passing a very large object, but with a
> double I'd expect any improvement in performance to be negligible.


Most likely it does not affect performance at all either way. Both
ways you can pass billions of parameters per second. If it is complex
algorithm then performance of parameter passing does not affect overall
performance by any percentage. If it is trivial algorithm then it is
often inlined and so parameter's won't be passed.

> I've seen code using the former, but I guess that's because it was
> translated from Fortran, where all function arguments are passed by
> reference -- or am I missing something?


That can be other good reason. Most code generators/translators
produce such code (in circumstances) that contains some overhead.
For example I have seen a switch with default only in generated code.
It looks nonsensical and feels waste, but in practice a compiler
later optimizes it out and so the perceptional "inefficiency" does
not manifest itself.
 
Reply With Quote
 
Rui Maciel
Guest
Posts: n/a
 
      02-11-2013
Öö Tiib wrote:

> Most likely it does not affect performance at all either way. Both
> ways you can pass billions of parameters per second. If it is complex
> algorithm then performance of parameter passing does not affect overall
> performance by any percentage. If it is trivial algorithm then it is
> often inlined and so parameter's won't be passed.


<example>
rui@kubuntu:tmp$ cat main.c++
#include <ctime>
#include <iostream>

double count = 0;

void value(double foo)
{
count += foo;
}


void reference(double const &foo)
{
count += foo;
}


int main(void)
{
const int max = 100000000;
clock_t t = clock();

count = 0;
for(int i = 0; i < max; ++i)
{
value(1.0f);
}

std::cout << "time pass by value: " << clock() - t << std::endl;

t = clock();
count = 0;
for(int i = 0; i < max; ++i)
{
reference(1.0f);
}

std::cout << "time pass by reference: " << clock() - t << std::endl;

return 0;
}

rui@kubuntu:tmp$ g++ main.c++ && ./a.out
time pass by value: 640000
time pass by reference: 1670000
</example>


Rui Maciel
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      02-11-2013
Rui Maciel wrote:
> Öö Tiib wrote:
>
>> Most likely it does not affect performance at all either way. Both
>> ways you can pass billions of parameters per second. If it is complex
>> algorithm then performance of parameter passing does not affect overall
>> performance by any percentage. If it is trivial algorithm then it is
>> often inlined and so parameter's won't be passed.

>
> <example>
> rui@kubuntu:tmp$ cat main.c++
> #include <ctime>
> #include <iostream>
>
> double count = 0;
>
> void value(double foo)
> {
> count += foo;
> }
>
>
> void reference(double const &foo)
> {
> count += foo;
> }
>
>
> int main(void)
> {
> const int max = 100000000;
> clock_t t = clock();
>
> count = 0;
> for(int i = 0; i < max; ++i)
> {
> value(1.0f);
> }
>
> std::cout << "time pass by value: " << clock() - t << std::endl;
>
> t = clock();
> count = 0;
> for(int i = 0; i < max; ++i)
> {
> reference(1.0f);
> }
>
> std::cout << "time pass by reference: " << clock() - t << std::endl;
>
> return 0;
> }
>
> rui@kubuntu:tmp$ g++ main.c++ && ./a.out
> time pass by value: 640000
> time pass by reference: 1670000


That's what I would have expected, however on a reasonable quick i7
(with an extra 0 in max):

32 bit:

g++ x.cc && ./a.out
time pass by value: 7510000
time pass by reference: 2700000

64 bit:

g++ x.cc -m64 && ./a.out
time pass by value: 2440000
time pass by reference: 2760000

With a little optimisation:

g++ x.cc -m64 -O1 && ./a.out
time pass by value: 2410000
time pass by reference: 2410000

--
Ian Collins
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      02-11-2013
On Monday, 11 February 2013 21:27:49 UTC+2, Scott Lurndal wrote:
> Ian Collins <(E-Mail Removed)> writes:
> >With a little optimisation:
> >
> >g++ x.cc -m64 -O1 && ./a.out
> >time pass by value: 2410000
> >time pass by reference: 2410000

>
> Which completely optimizes out (eliminates) both function calls
> (reference and value).


Nope, it inlines those. It can not optimize out summing into global with
external linkage so easily. What you think where those 2.4
seconds went? Inlining was what I predicted. Billion cycles took less
than 3 seconds unoptimized as well. That on only one core from quad of
i7. It is unlikely that any of it matters for performance of practical
application. Just acquiring meaningful billion doubles from any media
(including RAM) is far more expensive.

 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      02-11-2013
Scott Lurndal wrote:
> Ian Collins <(E-Mail Removed)> writes:
>
>> With a little optimisation:
>>
>> g++ x.cc -m64 -O1 && ./a.out
>> time pass by value: 2410000
>> time pass by reference: 2410000
>>

>
> Which completely optimizes out (eliminates) both function calls (reference and value).


So nothing takes 4.8 seconds to execute? The calls are still made, the
function bodies are optimised.

This is what happens when the function calls are optimised away:

CC x.cc -fast -m64 && ./a.out
time pass by value: 0
time pass by reference: 0



--
Ian Collins
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      02-11-2013
Scott Lurndal wrote:
> =?ISO-8859-1?Q?=D6=F6_Tiib?= <(E-Mail Removed)> writes:
>> On Monday, 11 February 2013 21:27:49 UTC+2, Scott Lurndal wrote:
>>> Ian Collins <(E-Mail Removed)> writes:
>>>> With a little optimisation:
>>>>
>>>> g++ x.cc -m64 -O1 && ./a.out
>>>> time pass by value: 2410000
>>>> time pass by reference: 2410000
>>>
>>> Which completely optimizes out (eliminates) both function calls
>>> (reference and value).

>>
>> Nope, it inlines those.

>
> It optimizes them out. There is no 'CALL' instruction.
>
> It does that by inlining the functions, so there is no function call.


I'm not so daft as to post something without checking first. The first
loop is:

call clock
movq $0, count(%rip)
movl $1000000000, %ebx
..L7:
movsd .LC1(%rip), %xmm0
call _Z5valued
subl $1, %ebx
jne .L7

The optimised value function is:

..globl _Z5valued
.type _Z5valued, @function
_Z5valued:
..LFB961:
addsd count(%rip), %xmm0
movsd %xmm0, count(%rip)
ret

Unoptimised:

..globl _Z5valued
.type _Z5valued, @function
_Z5valued:
..LFB961:
pushq %rbp
..LCFI3:
movq %rsp, %rbp
..LCFI4:
movsd %xmm0, -8(%rbp)
movsd count(%rip), %xmm0
addsd -8(%rbp), %xmm0
movsd %xmm0, count(%rip)
leave
..LCFI5:
ret

Which looks like a typical x64 stack frame optimisation.

--
Ian Collins
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
is const necessary in eg int compar(const void *, const void *) lovecreatesbeauty@gmail.c0m C Programming 26 11-10-2008 09:47 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM
Casting int'** to 'const int * const * const' dosn't work, why? Jonas.Holmsten@gmail.com C Programming 11 07-01-2007 06:16 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
floats doubles long doubles dan C++ 1 11-26-2003 05:12 AM



Advertisments