comp.lang.ada
 help / color / mirror / Atom feed
* Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
@ 2010-02-15 10:58 Colin Paul Gloster
  2010-02-15 13:02 ` John B. Matthews
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-15 10:58 UTC (permalink / raw)


Hello,

I have been improving a program by suppressing C++ in it. After
speeding it up a lot by making changes, I have found one considerable
part which calls a library routine, which is unfortunately very slow
as provided as standard with a number of Ada compilers but which is
very fast with implementations of other languages. For some Ada
compilers perhaps I shall simply need to not rely on an implementation
of this routine by an Ada vendor. Perhaps this post will motivate Ada
vendors to speed up their implementations or for people to report
timings for efficient implementations which are used by default by
other Ada compilers.

At present the routine (which is still being called by a C++ part of
the code) takes up maybe approximately one per cent of the running
time. (I have profiled it but I do not have the timing profiles
available where I am typing this.) This might not sound as if it is
much and it is certainly much less than much of the C++ overhead which
I have removed, but it is trivial to speed it up and speeding up this
one per cent or so would reduce running time by hours.

To contrast different implementations, I have produced the C++ program
#include<iostream>
#include<cmath>
int main()
{
   double answer = 0.0;
   for(int I=1; I<=1000000; ++I)
   {
     #include"body_in_CPlusPlus.cc"
   }
   std::cout << answer;
}
where  body_in_CPlusPlus.cc  contained
answer += std::log10(0.10000000000000000000
);
/*Lines produced by
for((i=1; i<=500; ++i)) do echo -n 'answer += std::log10(0' ; echo  "$i/10" | bc -l ; echo ');'; done
*/
answer += std::log10(050.00000000000000000000
);
and the Ada program
with Ada.Numerics.Generic_Elementary_Functions;
with Interfaces.C;
with Ada.Text_IO;
procedure Logarithmic_Work_In_Ada is
    answer : Interfaces.C.double := 0.0;
    package double_library is new Ada.Numerics.Generic_Elementary_Functions(Interfaces.C.double);
    package double_output_library is new Ada.Text_IO.Float_IO(Interfaces.C.double);
begin

    for I in 1 .. 1_000_000 loop --I would not have this loop but one compiler crashed if
                                 --the source file was sized a few megabytes.

answer := Interfaces.C."+"(answer, double_library.log(0.10000000000000000000
, 10.0 ));
--Lines produced by
--for((i=1; i<=500; ++i)) do echo -n 'answer := Interfaces.C."+"(answer, double_library.log(0' ; echo  "$i/10" | bc -l ; echo ', 10.0 ));'; done
answer := Interfaces.C."+"(answer, double_library.log(050.00000000000000000000
, 10.0 ));


    end loop;

    double_output_library.Put(answer);
end;

The aforementioned code which I have been speeding up did not consist
of merely 500 million calls to std::log10() as consecutive calls, but
instead it consisted of hundreds of times as many calls to
std::log10() interspersed across maybe 200 other functions.

Of the two programs shown, the fastest C++ implementation on one test
platform took less than one millisecond and the fastest Ada
implementation took one minute and 31 seconds and 874 milliseconds on
the same platform. Both g++ and gnatmake were from the same
installation of GCC 4.1.2 20080704 (Red Hat 4.1.2-44).

  g++ -O3 -ffast-math logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_with_-ffast-math

time ./logarithmic_work_in_CPlusPlus_with_-ffast-math
6.34086e+08
real    0m0.005s
user    0m0.000s
sys     0m0.000s


  g++ -O3 logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus

time ./logarithmic_work_in_CPlusPlus
6.34086e+08
real    0m46.443s
user    0m46.435s
sys     0m0.000s


gnatmake -O3 -ffast-math logarithmic_work_in_Ada.adb -o logarithmic_work_in_Ada_compiled_by_GNAT_with_-ffast-math
(which did
gcc -c -O3 -ffast-math logarithmic_work_in_Ada.adb
logarithmic_work_in_Ada.adb:4:11: warning: file name does not match unit name, should be "logarithmic_work_in_ada.adb"
gnatbind -x logarithmic_work_in_Ada.ali
gnatlink logarithmic_work_in_Ada.ali -ffast-math -o logarithmic_work_in_Ada_compiled_by_GNAT_with_-ffast-mat
whereas trying  -cargs  resulted in no compilation)

time ./logarithmic_work_in_Ada_compiled_by_GNAT_with_-ffast-math
  6.34086408536266E+08

real    1m31.879s
user    1m31.874s
sys     0m0.000s



  gnatmake -O3 logarithmic_work_in_Ada.adb -o logarithmic_work_in_Ada_compiled_by_GNAT

time ./logarithmic_work_in_Ada_compiled_by_GNAT
  6.34086408536266E+08

real    1m33.338s
user    1m33.338s
sys     0m0.000s


proprietary_compiler -O -m logarithmic_work_in_Ada.adb -o logarithmic_work_in_Ada_compiled_by_a_proprietary_compiler

time ./logarithmic_work_in_Ada_compiled_by_a_proprietary_compiler
  6.34086408605593E+08
real    1m41.966s
user    1m41.954s
sys     0m0.000s



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
@ 2010-02-15 13:02 ` John B. Matthews
  2010-02-15 14:17   ` Colin Paul Gloster
  2010-02-15 14:54 ` jonathan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: John B. Matthews @ 2010-02-15 13:02 UTC (permalink / raw)


In article 
<alpine.LNX.2.00.1002151055530.17315@Bluewhite64.example.net>,
 Colin Paul Gloster <Colin_Paul_Gloster@ACM.org> wrote:

>   gnatmake -O3 logarithmic_work_in_Ada.adb -o 
>   logarithmic_work_in_Ada_compiled_by_GNAT
> 
> time ./logarithmic_work_in_Ada_compiled_by_GNAT
>   6.34086408536266E+08
> 
> real    1m33.338s
> user    1m33.338s
> sys     0m0.000s

I get a different answer: 698970 = 1000000 * (log10(50) - 1).

$ make clean logada ; time ./logada
rm -f *.o *.ali b~* core logada
gnatmake logada -cargs -O3 -gnatwa -bargs -shared -largs -dead_strip
gcc -c -O3 -gnatwa logada.adb
gnatbind -shared -x logada.ali
gnatlink logada.ali -shared-libgcc -dead_strip
 6.98970004334243E+05

real    0m0.138s
user    0m0.136s
sys 0m0.002s

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 13:02 ` John B. Matthews
@ 2010-02-15 14:17   ` Colin Paul Gloster
  2010-02-15 17:19     ` John B. Matthews
  0 siblings, 1 reply; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-15 14:17 UTC (permalink / raw)


On Mon, 15 Feb 2010, John B. Matthews wrote:

|--------------------------------------------------------------------|
|"In article                                                         |
|<alpine.LNX.2.00.1002151055530.17315@Bluewhite64.example.net>,      |
| Colin Paul Gloster <Colin_Paul_Gloster@ACM.org> wrote:             |
|                                                                    |
|>   gnatmake -O3 logarithmic_work_in_Ada.adb -o                     |
|>   logarithmic_work_in_Ada_compiled_by_GNAT                        |
|>                                                                   |
|> time ./logarithmic_work_in_Ada_compiled_by_GNAT                   |
|>   6.34086408536266E+08                                            |
|>                                                                   |
|> real    1m33.338s                                                 |
|> user    1m33.338s                                                 |
|> sys     0m0.000s                                                  |
|                                                                    |
|I get a different answer: 698970 = 1000000 * (log10(50) - 1).       |
|                                                                    |
|$ make clean logada ; time ./logada                                 |
|rm -f *.o *.ali b~* core logada                                     |
|gnatmake logada -cargs -O3 -gnatwa -bargs -shared -largs -dead_strip|
|gcc -c -O3 -gnatwa logada.adb                                       |
|gnatbind -shared -x logada.ali                                      |
|gnatlink logada.ali -shared-libgcc -dead_strip                      |
| 6.98970004334243E+05                                               |
|                                                                    |
|real    0m0.138s                                                    |
|user    0m0.136s                                                    |
|sys 0m0.002s                                                        |
|                                                                    |
|--                                                                  |
|John B. Matthews                                                    |
|trashgod at gmail dot com                                           |
|<http://sites.google.com/site/drjohnbmatthews> "                    |
|--------------------------------------------------------------------|

Hi,

Thanks for running it. The Ada program for timing had 500 statements
in the body of the loop. I reproduced only the first and last
verbatim: I showed a  bash  (Bourne Again SHell) line for producing
all 500 statements in a comment in-between the the first statement and
the last statement. You ran a program with 498 of the statements
missing.

Anyway, the answer produced by the program is not so much of concern
as the relative speeds of different implementations. Did  g++  produce
a faster result for you than GNAT? It did for me for many versions of
GCC today on a different platform than I used in the beginning of this
thread...


g++ -O3 -ffast-math logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.4.3_with_-ffast-math

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.4.3_with_-ffast-math
6.34086e+08
real    0m0.012s
user    0m0.008s
sys     0m0.004s



g++ -O3 -ffast-math logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.2_with_-ffast-math

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.2_with_-ffast-math
6.34086e+08
real    0m0.012s
user    0m0.012s
sys     0m0.000s



  g++ -O3 logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.2

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.2
6.34086e+08
real    0m0.567s
user    0m0.560s
sys     0m0.000s



  g++ -O3 logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.4.3

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.4.3
6.34086e+08
real    0m0.566s
user    0m0.564s
sys     0m0.004s



  g++ -O3 logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.3

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.3.3
6.34086e+08
real    0m0.583s
user    0m0.572s
sys     0m0.004s



gnatmake -O3 -ffast-math Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.4.3_with_-ffast-math

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.4.3_with_-ffast-math
  6.34086408536266E+08

real    0m31.618s
user    0m31.618s
sys     0m0.000s




  gnatmake -O3 Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.4.3

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.4.3
  6.34086408606382E+08

real    0m32.750s
user    0m32.746s
sys     0m0.004s


  gnatmake -O3 Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.2

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.2
  6.34086408606382E+08

real    0m33.537s
user    0m33.506s
sys     0m0.004s



  gnatmake -O3 Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.3

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.3
  6.34086408606382E+08

real    0m33.717s
user    0m33.718s
sys     0m0.000s



  g++ -O3 logarithmic_work_in_CPlusPlus.cc -o logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.2.4

  time ./logarithmic_work_in_CPlusPlus_compiled_by_64bit_GCC4.2.4
6.34086e+08
real    0m34.000s
user    0m33.982s
sys     0m0.000s



gnatmake -O3 Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.2.4

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.2.4
  6.34086408606382E+08

real    0m34.037s
user    0m34.034s
sys     0m0.004s



gnatmake -O3 -ffast-math Logarithmic_Work_In_Ada.adb -o Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.2_with_-ffast-math

  time ./Logarithmic_Work_In_Ada_compiled_by_64bit_GCC4.3.2_with_-ffast-math
  6.34086408536266E+08

real    0m35.093s
user    0m35.090s
sys     0m0.004s



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
  2010-02-15 13:02 ` John B. Matthews
@ 2010-02-15 14:54 ` jonathan
  2010-02-15 15:04   ` jonathan
  2010-02-15 18:26 ` (see below)
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: jonathan @ 2010-02-15 14:54 UTC (permalink / raw)


On Feb 15, 10:58 am, Colin Paul Gloster <Colin_Paul_Glos...@ACM.org>
wrote:
> Hello,
>
> I have been improving a program by suppressing C++ in it. After
> speeding it up a lot by making changes, I have found one considerable
> part which calls a library routine, which is unfortunately very slow
> as provided as standard with a number of Ada compilers but which is
> very fast with implementations of other languages....

Here is my own bench ... easier to play with:

with ada.numerics.generic_elementary_functions;
with text_io; use text_io;

procedure log_bench is

  type Real is digits 15;
  package Math is new ada.numerics.generic_elementary_functions
(Real);
  use Math;
  x, y : Real := 0.1;

  -- might (or might not!) be faster to use:
  --    log_base_10 (x) = log_base_10_of_e * log_base_e (x)

  Log_base_10_of_e : constant := 0.434_294_481_903_251_827_651_129;

begin

  for i in 1 .. 1_000_000 loop
    x := x + Log_base_10_of_e * Log (y);
    y := y + 0.0000000000001;
  end loop;
  put (Real'Image(x));

end log_bench;


gnatmake  gnatnp -O2 -march=native log_bench.adb



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 14:54 ` jonathan
@ 2010-02-15 15:04   ` jonathan
  2010-02-15 19:50     ` sjw
  0 siblings, 1 reply; 21+ messages in thread
From: jonathan @ 2010-02-15 15:04 UTC (permalink / raw)


On Feb 15, 2:54 pm, jonathan <johns...@googlemail.com> wrote:
> On Feb 15, 10:58 am, Colin Paul Gloster <Colin_Paul_Glos...@ACM.org>
> wrote:
>
> > Hello,
>
> > I have been improving a program by suppressing C++ in it. After
> > speeding it up a lot by making changes, I have found one considerable
> > part which calls a library routine, which is unfortunately very slow
> > as provided as standard with a number of Ada compilers but which is
> > very fast with implementations of other languages....
>
> Here is my own bench ... easier to play with:
>
> with ada.numerics.generic_elementary_functions;
> with text_io; use text_io;
>
> procedure log_bench is
>
>   type Real is digits 15;
>   package Math is new ada.numerics.generic_elementary_functions
> (Real);
>   use Math;
>   x, y : Real := 0.1;
>
>   -- might (or might not!) be faster to use:
>   --    log_base_10 (x) = log_base_10_of_e * log_base_e (x)
>
>   Log_base_10_of_e : constant := 0.434_294_481_903_251_827_651_129;
>
> begin
>
>   for i in 1 .. 1_000_000 loop
>     x := x + Log_base_10_of_e * Log (y);
>     y := y + 0.0000000000001;
>   end loop;
>   put (Real'Image(x));
>
>
>
> gnatmake  gnatnp -O2 -march=native log_bench.adb

Opps, accidently hit the send button!  Continuing discussion:

gnatmake  gnatnp -O2 -march=native log_bench.adb

-9.99999682845800E+05
real    0m0.024s
user    0m0.024s
sys     0m0.000s

NOW, comment out the y := y + ... so that the inner loop
is constant, and use the same compilation switches:

gnatmake  gnatnp -O2 -march=native log_bench.adb

-9.99999900000000E+05
real    0m0.002s
user    0m0.000s
sys     0m0.000s

You see now what's happening.  With the gnatn switch the
compiler is smart enough to call the Log just once, rather
than 10**6 times.

If you remove the -gnatn or -gnatN switches, then it runs in
 0m0.024s again.

Jonathan





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 14:17   ` Colin Paul Gloster
@ 2010-02-15 17:19     ` John B. Matthews
  0 siblings, 0 replies; 21+ messages in thread
From: John B. Matthews @ 2010-02-15 17:19 UTC (permalink / raw)


In article 
<alpine.LNX.2.00.1002151339400.17315@Bluewhite64.example.net>,
 Colin Paul Gloster <Colin_Paul_Gloster@ACM.org> wrote:

> Thanks for running it. The Ada program for timing had 500 statements 
> in the body of the loop. I reproduced only the first and last 
> verbatim: I showed a  bash  (Bourne Again SHell) line for producing 
> all 500 statements in a comment in-between the the first statement 
> and the last statement. You ran a program with 498 of the statements 
> missing.

Ah, source level compression!

> Anyway, the answer produced by the program is not so much of concern 
> as the relative speeds of different implementations. Did  g++  
> produce a faster result for you than GNAT? It did for me for many 
> versions of GCC today on a different platform than I used in the 
> beginning of this thread...

Retesting both 500+ line programs produces results similar to yours:

$ make test
Darwin: gcc 4.3.4
rm -f *.o *.ali b~* core
rm -f *.s temp.txt logada logcpp 
gnatmake logada -cargs -O3 -gnatnp -bargs -shared -largs -ffast-math 
-dead_strip
gcc -c -O3 -gnatnp logada.adb
gnatbind -shared -x logada.ali
gnatlink logada.ali -shared-libgcc -ffast-math -dead_strip
g++ -O3 logcpp.cc -o logcpp
time ./logcpp
6.35785e+08        0.57 real         0.56 user         0.00 sys
time ./logada
 6.35785378608776E+08
       28.15 real        28.10 user         0.02 sys

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
  2010-02-15 13:02 ` John B. Matthews
  2010-02-15 14:54 ` jonathan
@ 2010-02-15 18:26 ` (see below)
  2010-02-15 18:51   ` jonathan
                     ` (2 more replies)
  2010-02-15 23:04 ` Jeffrey R. Carter
  2010-02-15 23:20 ` Randy Brukardt
  4 siblings, 3 replies; 21+ messages in thread
From: (see below) @ 2010-02-15 18:26 UTC (permalink / raw)


On 15/02/2010 10:58, in article
alpine.LNX.2.00.1002151055530.17315@Bluewhite64.example.net, "Colin Paul
Gloster" <Colin_Paul_Gloster@ACM.org> wrote:

> Of the two programs shown, the fastest C++ implementation on one test
> platform took less than one millisecond and the fastest Ada
> implementation took one minute and 31 seconds and 874 milliseconds on
> the same platform. Both g++ and gnatmake were from the same
> installation of GCC 4.1.2 20080704 (Red Hat 4.1.2-44).

Is that 1 millisecond for 1e6 calls? This implies 1ns per call in C++.
I find it incredible that a log function could be so fast.
I think the loop body must be evaluated at compile-time in C++.

On my system your Ada code gives:

6.34086408536266E+08

real    0m33.918s
user    0m33.864s
sys     0m0.025s

And your original C++ code gives:

6.34086e+08
real    0m0.110s
user    0m0.003s
sys     0m0.003s

But if I replace the C++ loop body by:

      for(int j=1; j<=500; ++j)
         answer += std::log10(j*0.100000000000000000000);
It now gives:

6.34086e+08
real    0m18.112s
user    0m18.082s
sys    0m0.015s

This less than twice as fast as the more generalized Ada code.

The simpler inner loop:
      for(int j=1; j<=500; ++j)
         answer += j;
gives:

1.2525e+11
real    0m0.677s
user    0m0.614s
sys    0m0.003s

So the difference cannot be due to loop overhead.
-- 
Bill Findlay
<surname><forename> chez blueyonder.co.uk




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 18:26 ` (see below)
@ 2010-02-15 18:51   ` jonathan
  2010-02-15 20:00   ` sjw
  2010-02-16 17:33   ` Colin Paul Gloster
  2 siblings, 0 replies; 21+ messages in thread
From: jonathan @ 2010-02-15 18:51 UTC (permalink / raw)


On Feb 15, 6:26 pm, "(see below)" <yaldni...@blueyonder.co.uk> wrote:
> On 15/02/2010 10:58, in article
> alpine.LNX.2.00.1002151055530.17...@Bluewhite64.example.net, "Colin Paul
>
> Gloster" <Colin_Paul_Glos...@ACM.org> wrote:
> > Of the two programs shown, the fastest C++ implementation on one test
> > platform took less than one millisecond and the fastest Ada
> > implementation took one minute and 31 seconds and 874 milliseconds on
> > the same platform. Both g++ and gnatmake were from the same
> > installation of GCC 4.1.2 20080704 (Red Hat 4.1.2-44).
>
> Is that 1 millisecond for 1e6 calls? This implies 1ns per call in C++.
> I find it incredible that a log function could be so fast.
> I think the loop body must be evaluated at compile-time in C++.
>
> On my system your Ada code gives:
>
> 6.34086408536266E+08
>
> real    0m33.918s
> user    0m33.864s
> sys     0m0.025s
>
>... if I replace the C++ loop body by:
>
>       for(int j=1; j<=500; ++j)
>          answer += std::log10(j*0.100000000000000000000);
> It now gives:
>
> 6.34086e+08
> real    0m18.112s
> user    0m18.082s
> sys    0m0.015s
>

> Bill Findlay
> <surname><forename> chez blueyonder.co.uk

On my computer,
   Log_base_10_of_e * Log (y)
is twice as fast as
   Log (y, Base => 10.0).


Jonathan



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 15:04   ` jonathan
@ 2010-02-15 19:50     ` sjw
  2010-02-16 16:50       ` Colin Paul Gloster
  0 siblings, 1 reply; 21+ messages in thread
From: sjw @ 2010-02-15 19:50 UTC (permalink / raw)


On Feb 15, 3:04 pm, jonathan <johns...@googlemail.com> wrote:
> On Feb 15, 2:54 pm, jonathan <johns...@googlemail.com> wrote:
> > On Feb 15, 10:58 am, Colin Paul Gloster <Colin_Paul_Glos...@ACM.org>
> > wrote:
>
> > > Hello,
>
> > > I have been improving a program by suppressing C++ in it. After
> > > speeding it up a lot by making changes, I have found one considerable
> > > part which calls a library routine, which is unfortunately very slow
> > > as provided as standard with a number of Ada compilers but which is
> > > very fast with implementations of other languages....
>
> > Here is my own bench ... easier to play with:
>
> > with ada.numerics.generic_elementary_functions;
> > with text_io; use text_io;
>
> > procedure log_bench is
>
> >   type Real is digits 15;
> >   package Math is new ada.numerics.generic_elementary_functions
> > (Real);
> >   use Math;
> >   x, y : Real := 0.1;
>
> >   -- might (or might not!) be faster to use:
> >   --    log_base_10 (x) = log_base_10_of_e * log_base_e (x)
>
> >   Log_base_10_of_e : constant := 0.434_294_481_903_251_827_651_129;
>
> > begin
>
> >   for i in 1 .. 1_000_000 loop
> >     x := x + Log_base_10_of_e * Log (y);
> >     y := y + 0.0000000000001;
> >   end loop;
> >   put (Real'Image(x));
>
> > gnatmake  gnatnp -O2 -march=native log_bench.adb
>
> Opps, accidently hit the send button!  Continuing discussion:
>
> gnatmake  gnatnp -O2 -march=native log_bench.adb
>
> -9.99999682845800E+05
> real    0m0.024s
> user    0m0.024s
> sys     0m0.000s
>
> NOW, comment out the y := y + ... so that the inner loop
> is constant, and use the same compilation switches:
>
> gnatmake  gnatnp -O2 -march=native log_bench.adb
>
> -9.99999900000000E+05
> real    0m0.002s
> user    0m0.000s
> sys     0m0.000s
>
> You see now what's happening.  With the gnatn switch the
> compiler is smart enough to call the Log just once, rather
> than 10**6 times.
>
> If you remove the -gnatn or -gnatN switches, then it runs in
>  0m0.024s again.

The trouble is that that benchmark does something other than Colin's!
This might be a more accurate translation:

with Ada.Numerics.Generic_Elementary_Functions;
with Text_IO; use Text_IO;
procedure Log_Bench_0 is
   type Real is digits 15;
   package Math is new Ada.Numerics.Generic_Elementary_Functions
(Real);
   use Math;
   Answer : Real := 0.0;
   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;
begin
   for I in 1 .. 1_000_000 loop
      declare
         X : Real := 0.1;
      begin
         for J in 1 .. 500 loop
            Answer := Answer + Log_Base_10_Of_E * Log (X);
            X := X + 0.1;
         end loop;
      end;
   end loop;
   Put (Real'Image(Answer));
end Log_Bench_0;

I've tried inlining GNAT's implementation (GCC 4.5.0, x86_64-aqpple-
darwin10.2.0) and even just calling up the C log10 routine using an
inline. None was very impressive compared to the g++ result.

Colin's time: 37s
Jonathan's time (-O3 -ffast-math -gnatp): 16s
Jonathan;s time (-O3 -ffast-math -gnatp -gnatN -funroll-loops): 14s
Jonathan's time (same opts, but using C log10()): 11s

so we still have 3 orders of magnitude to go to get to the g++ result:
0.02s

This is my final version, with the inlined GNAT implementation too:

with Ada.Numerics.Generic_Elementary_Functions;
with System.Machine_Code; use System.Machine_Code;
with Text_IO; use Text_IO;
procedure Log_Bench is
   type Real is digits 15;
   package Math is new Ada.Numerics.Generic_Elementary_Functions
(Real);
   use Math;
   Answer : Real := 0.0;
   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;
   function LogM (X : Real) return Real;
   pragma Inline_Always (LogM);
   function LogM (X : Real) return Real is
      Result : Real;
      NL : constant String := ASCII.LF & ASCII.HT;
   begin
      Asm (Template =>
         "fldln2               " & NL
       & "fxch                 " & NL
       & "fyl2x                " & NL,
         Outputs  => Real'Asm_Output ("=t", Result),
         Inputs   => Real'Asm_Input  ("0", X));
      return Result;
   end LogM;
   function LogL (X : Real) return Real;
   pragma Import (C, LogL, "log10");
begin
   for I in 1 .. 1_000_000 loop
      declare
         X : Real := 0.1;
      begin
         for J in 1 .. 500 loop
--              Answer := Answer + Log_Base_10_Of_E * LogM (X);
            Answer := Answer + LogL (X);
            X := X + 0.1;
         end loop;
      end;
   end loop;
   Put (Real'Image(Answer));
end Log_Bench;


This is a fragment of the assembler output from the g++ code:

	movsd	LC0(%rip), %xmm0
	call	_log10
	movsd	%xmm0, -3976(%rbp)
	movsd	LC1(%rip), %xmm0
	call	_log10
	movsd	%xmm0, -3968(%rbp)
	movsd	LC2(%rip), %xmm0
	call	_log10

and this is a fragment of the assembler from the last Ada:

	movapd	%xmm1, %xmm0
	movsd	%xmm1, -144(%rbp)
	addl	$10, %ebx
	call	_log10
	movsd	-144(%rbp), %xmm9
	addsd	-120(%rbp), %xmm0
	addsd	LC1(%rip), %xmm9
	movsd	%xmm0, -120(%rbp)
	movapd	%xmm9, %xmm0
	movsd	%xmm9, -144(%rbp)
	call	_log10
	movsd	-144(%rbp), %xmm8
	addsd	-120(%rbp), %xmm0
	addsd	LC1(%rip), %xmm8
	movsd	%xmm0, -120(%rbp)
	movapd	%xmm8, %xmm0
	movsd	%xmm8, -144(%rbp)
	call	_log10

at which point I have to leave it to the experts; why do the 7 Ada
instructions take so much time compared to the 2 g++ instructions???



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 18:26 ` (see below)
  2010-02-15 18:51   ` jonathan
@ 2010-02-15 20:00   ` sjw
  2010-02-15 21:17     ` jonathan
  2010-02-16 17:33   ` Colin Paul Gloster
  2 siblings, 1 reply; 21+ messages in thread
From: sjw @ 2010-02-15 20:00 UTC (permalink / raw)


On Feb 15, 6:26 pm, "(see below)" <yaldni...@blueyonder.co.uk> wrote:
> On 15/02/2010 10:58, in article
> alpine.LNX.2.00.1002151055530.17...@Bluewhite64.example.net, "Colin Paul
>
> Gloster" <Colin_Paul_Glos...@ACM.org> wrote:
> > Of the two programs shown, the fastest C++ implementation on one test
> > platform took less than one millisecond and the fastest Ada
> > implementation took one minute and 31 seconds and 874 milliseconds on
> > the same platform. Both g++ and gnatmake were from the same
> > installation of GCC 4.1.2 20080704 (Red Hat 4.1.2-44).
>
> Is that 1 millisecond for 1e6 calls? This implies 1ns per call in C++.
> I find it incredible that a log function could be so fast.
> I think the loop body must be evaluated at compile-time in C++.

I think it's a mixture of your point & Jonathan's; the loop body, with
the 500 calls to log10(), is executed once, then the compiler smartly
realizes that each iteration produces the same increment.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 20:00   ` sjw
@ 2010-02-15 21:17     ` jonathan
  2010-02-16  0:09       ` jonathan
  0 siblings, 1 reply; 21+ messages in thread
From: jonathan @ 2010-02-15 21:17 UTC (permalink / raw)


On Feb 15, 8:00 pm, sjw <simon.j.wri...@mac.com> wrote:
> On Feb 15, 6:26 pm, "(see below)" <yaldni...@blueyonder.co.uk> wrote:

> > Is that 1 millisecond for 1e6 calls? This implies 1ns per call in C++.
> > I find it incredible that a log function could be so fast.
> > I think the loop body must be evaluated at compile-time in C++.
>
> I think it's a mixture of your point & Jonathan's; the loop body, with
> the 500 calls to log10(), is executed once, then the compiler smartly
> realizes that each iteration produces the same increment.

Right ... there was never any mystery here ... that's why I thought a
translation of the original bench wasn't necessary. The remaining
puzzle
is the smallish difference between the gnat Log and the gcc Log. I
will
(also) leave this to the experts.  When I looked at this in the past,
it has always been because gnat did the calculation to 18
significant
figures (even if you use type Real is digits 15), gcc to 15.

Jonathan




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
                   ` (2 preceding siblings ...)
  2010-02-15 18:26 ` (see below)
@ 2010-02-15 23:04 ` Jeffrey R. Carter
  2010-02-16 14:54   ` Colin Paul Gloster
  2010-02-15 23:20 ` Randy Brukardt
  4 siblings, 1 reply; 21+ messages in thread
From: Jeffrey R. Carter @ 2010-02-15 23:04 UTC (permalink / raw)


Colin Paul Gloster wrote:
> with Ada.Numerics.Generic_Elementary_Functions;
> with Interfaces.C;
> with Ada.Text_IO;
> procedure Logarithmic_Work_In_Ada is
>    answer : Interfaces.C.double := 0.0;
>    package double_library is new 
> Ada.Numerics.Generic_Elementary_Functions(Interfaces.C.double);
>    package double_output_library is new 
> Ada.Text_IO.Float_IO(Interfaces.C.double);
> begin
> 
>    for I in 1 .. 1_000_000 loop --I would not have this loop but one 
> compiler crashed if
>                                 --the source file was sized a few 
> megabytes.
> 
> answer := Interfaces.C."+"(answer, 
> double_library.log(0.10000000000000000000
> , 10.0 ));
> --Lines produced by
> --for((i=1; i<=500; ++i)) do echo -n 'answer := Interfaces.C."+"(answer, 
> double_library.log(0' ; echo  "$i/10" | bc -l ; echo ', 10.0 ));'; done
> answer := Interfaces.C."+"(answer, 
> double_library.log(050.00000000000000000000
> , 10.0 ));
> 
> 
>    end loop;
> 
>    double_output_library.Put(answer);
> end;

IIUC, your Ada program is equivalent to

with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Text_IO;

with Interfaces.C;

procedure Optimization_Test is
    subtype Double is Interfaces.C.Double;
    use type Double;

    package Math is new Ada.Numerics.Generic_Elementary_Functions (Double);

    Answer : Double := 0.0;
begin -- Optimization_Test
    for I in 1 .. 1_000_000 loop
       Answer := Answer + Math.Log (0.1, 10.0);

       for J in 1 .. 500 loop
          Answer := Answer + Math.Log (Double (J) / 10.0, 10.0);
       end loop;

       Answer := Answer + Math.Log (50.0, 10.0);
    end loop;

    Ada.Text_IO.Put (Answer'Img);
end Optimization_Test;

On my machine I get something like

jrcarter@jrcarter-acer-laptop:~/Code$ gnatmake -O2 -gnatnp optimization_test.adb
gcc-4.3 -c -O2 -gnatnp optimization_test.adb
gnatbind -x optimization_test.ali
gnatlink optimization_test.ali
jrcarter@jrcarter-acer-laptop:~/Code$ time ./optimization_test
  6.34785378608078E+08

real	1m33.817s
user	1m33.810s
sys	0m0.000s

Note that suppressing runtime checks (-gnatp) is needed to be sort of equivalent 
to C++.

A good compiler could recognize that this adds a constant amount to Answer each 
time through the outer loop, and the outer loop is run a static constant number 
of times, and might optimize it to something like

with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Text_IO;

with Interfaces.C;

procedure Optimization_Test is
    subtype Double is Interfaces.C.Double;
    use type Double;

    package Math is new Ada.Numerics.Generic_Elementary_Functions (Double);

    function Inner_Loop return Double is
       Result : Double := 0.0;
    begin -- Inner_Loop
       for J in 1 .. 500 loop
          Result := Result + Math.Log (Double (J) / 10.0, 10.0);
       end loop;

       return Result;
    end Inner_Loop;
    pragma Inline (Inner_Loop);

    Answer : constant Double :=
       1.0E6 * (Math.Log (0.1, 10.0) + Inner_Loop + Math.Log (50.0, 10.0) );
begin -- Optimization_Test
    Ada.Text_IO.Put (Answer'Img);
end Optimization_Test;

This, on my machine and with the same options, gives something like

jrcarter@jrcarter-acer-laptop:~/Code$ time ./optimization_test  6.34785378539470E+08

real	0m0.009s
user	0m0.000s
sys	0m0.010s

I suspect this optimization is what the C++ compiler is doing, and the Ada 
compilers are not.

Whether a similar optimization may be applied to the calculations in your real 
program of interest is another question.

-- 
Jeff Carter
"Friends don't let friends program in C++."
Ludovic Brenta
114



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
                   ` (3 preceding siblings ...)
  2010-02-15 23:04 ` Jeffrey R. Carter
@ 2010-02-15 23:20 ` Randy Brukardt
  4 siblings, 0 replies; 21+ messages in thread
From: Randy Brukardt @ 2010-02-15 23:20 UTC (permalink / raw)


"Colin Paul Gloster" <Colin_Paul_Gloster@ACM.org> wrote in message 
news:alpine.LNX.2.00.1002151055530.17315@Bluewhite64.example.net...
> I have been improving a program by suppressing C++ in it. After
> speeding it up a lot by making changes, I have found one considerable
> part which calls a library routine, which is unfortunately very slow
> as provided as standard with a number of Ada compilers but which is
> very fast with implementations of other languages. For some Ada
> compilers perhaps I shall simply need to not rely on an implementation
> of this routine by an Ada vendor. Perhaps this post will motivate Ada
> vendors to speed up their implementations or for people to report
> timings for efficient implementations which are used by default by
> other Ada compilers.

I doubt it's possible in general. Ada has strong accuracy requirements on 
the implementation of Generic_Elementary_Functions, while other languages 
have little to say. The result is that it isn't possible for Ada to be as 
fast as possible because those techniques don't have the required accuracy. 
I haven't worked on this recently, but back in the day, the old 8087 
hardware instructions didn't have the required accuracy for Sine and 
Tangent, so a software solution had to be used (which of course was a lot 
slower).

(Yes, compilers can and do provide faster implementations of these functions 
that don't meet the accuracy requirements, but those solutions aren't 
portable in general.)

This is a major difference between Ada and most other programming languages: 
Ada defines error bounds for all numeric operations, so that it's possible 
to perform useful numeric analysis on an Ada program without knowing any at 
all about the target hardware. There is of course a cost to that capability. 
But it is an important capability which rarely is taken advantage of : as 
noted in a previous thread, without numerical analysis, you have no idea 
whether the results you are getting has any significance or not. And "not" 
is far more likely that people like to admit.

                                    Randy.





^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 21:17     ` jonathan
@ 2010-02-16  0:09       ` jonathan
  0 siblings, 0 replies; 21+ messages in thread
From: jonathan @ 2010-02-16  0:09 UTC (permalink / raw)


I said:

>The remaining puzzle
> is the smallish difference between the gnat Log and the gcc Log. I
> will (also) leave this to the experts.  When I looked at this in
> the past it has always been because gnat did the calculation to 18
> significant figures (even if you use type
> Real is digits 15), gcc to 15.

Well, I can't resist .. its easy to demonstrate (on Intel cpu's).
Let's do a benchmark of 10_000_000 base e Log's with 15 digits
and then 18 digits.  Must compile without -gnatn or -gnatN
so that it doesn't optimize away the constant in the inner loop.
I just used -O3. (Couldn't find anything faster.)

with ada.numerics.generic_elementary_functions;
with text_io; use text_io;

procedure log_bench_2 is

  type Real is digits 15;
--type Real is digits 18;

  package Math is
     new ada.numerics.generic_elementary_functions(Real);
  use Math;
  x, y : Real := 0.5;

begin

  for i in 1 .. 10_000_000 loop
    x := Log (y);
  end loop;
  Put (Real'Image (x));

end log_bench_2;

Using 15 digits I get:

-6.93147180559945E-01
real    0m0.209s
user    0m0.208s
sys     0m0.000s

Using 18 digits I get:

-6.93147180559945309E-01
real    0m0.208s
user    0m0.208s
sys     0m0.000s

So 18 digits are calculated just as fast as 15.

Jonathan



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 23:04 ` Jeffrey R. Carter
@ 2010-02-16 14:54   ` Colin Paul Gloster
  2010-02-16 15:24     ` Colin Paul Gloster
  2010-02-16 19:01     ` Jeffrey R. Carter
  0 siblings, 2 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-16 14:54 UTC (permalink / raw)


On Mon, 15 Feb 2010, Jeffrey R. Carter sent:

|--------------------------------------------------------------------------------|
|"[..]                                                                           |
|                                                                                |
|IIUC, your Ada program is equivalent to                                         |
|                                                                                |
|with Ada.Numerics.Generic_Elementary_Functions;                                 |
|with Ada.Text_IO;                                                               |
|                                                                                |
|with Interfaces.C;                                                              |
|                                                                                |
|procedure Optimization_Test is                                                  |
|   subtype Double is Interfaces.C.Double;                                       |
|   use type Double;                                                             |
|                                                                                |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions (Double);      |
|                                                                                |
|   Answer : Double := 0.0;                                                      |
|begin -- Optimization_Test                                                      |
|   for I in 1 .. 1_000_000 loop                                                 |
|      Answer := Answer + Math.Log (0.1, 10.0);                                  |
|                                                                                |
|      for J in 1 .. 500 loop                                                    |
|         Answer := Answer + Math.Log (Double (J) / 10.0, 10.0);"                |
|--------------------------------------------------------------------------------|

Aside from not encouraging division instructions when not necessary,
as I mentioned on
HTTP://Programmer.97Things.OReilly.com/wiki/index.php/Execution_Speed_versus_Maintenance_Effort
, I wanted to not have too high overhead obscuring the focus of
measuring speeds of log implementations.

|--------------------------------------------------------------------------------|
|"      end loop;                                                                |
|                                                                                |
|      Answer := Answer + Math.Log (50.0, 10.0);                                 |
|   end loop;                                                                    |
|                                                                                |
|   Ada.Text_IO.Put (Answer'Img);                                                |
|end Optimization_Test;                                                          |
|                                                                                |
|On my machine I get something like                                              |
|                                                                                |
|jrcarter@jrcarter-acer-laptop:~/Code$ gnatmake -O2 -gnatnp optimization_test.adb|
|gcc-4.3 -c -O2 -gnatnp optimization_test.adb                                    |
|gnatbind -x optimization_test.ali                                               |
|gnatlink optimization_test.ali                                                  |
|jrcarter@jrcarter-acer-laptop:~/Code$ time ./optimization_test                  |
| 6.34785378608078E+08                                                           |
|                                                                                |
|real   1m33.817s                                                                |
|user   1m33.810s                                                                |
|sys    0m0.000s"                                                                |
|--------------------------------------------------------------------------------|

time ./Optimization_Test_with_many_assignments_to_Answer_compiled_by_GCC4.4.3_with_-ffast-math
 6.34785378608078E+08

real    0m34.319s
user    0m34.318s
sys     0m0.004s
here.

|---------------------------------------------------------------------------------|
|"Note that suppressing runtime checks (-gnatp) is needed to be sort of equivalent|
|to C++."                                                                         |
|---------------------------------------------------------------------------------|

Thanks for the tip, but I do not program in Ada to really program in
C++ with Ada syntax.

|--------------------------------------------------------------------------------|
|"A good compiler could recognize that this adds a constant amount to Answer each|
|time through the outer loop, and the outer loop is run a static constant number |
|of times, and might optimize it to something like                               |
|                                                                                |
|with Ada.Numerics.Generic_Elementary_Functions;                                 |
|with Ada.Text_IO;                                                               |
|                                                                                |
|with Interfaces.C;                                                              |
|                                                                                |
|procedure Optimization_Test is                                                  |
|   subtype Double is Interfaces.C.Double;                                       |
|   use type Double;                                                             |
|                                                                                |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions (Double);      |
|                                                                                |
|   function Inner_Loop return Double is                                         |
|      Result : Double := 0.0;                                                   |
|   begin -- Inner_Loop                                                          |
|      for J in 1 .. 500 loop                                                    |
|         Result := Result + Math.Log (Double (J) / 10.0, 10.0);                 |
|      end loop;                                                                 |
|                                                                                |
|      return Result;                                                            |
|   end Inner_Loop;                                                              |
|   pragma Inline (Inner_Loop);                                                  |
|                                                                                |
|   Answer : constant Double :=                                                  |
|      1.0E6 * (Math.Log (0.1, 10.0) + Inner_Loop + Math.Log (50.0, 10.0) );     |
|begin -- Optimization_Test                                                      |
|   Ada.Text_IO.Put (Answer'Img);                                                |
|end Optimization_Test;                                                          |
|                                                                                |
|This, on my machine and with the same options, gives something like             |
|                                                                                |
|jrcarter@jrcarter-acer-laptop:~/Code$ time ./optimization_test                  |
|6.34785378539470E+08                                                            |
|                                                                                |
|real   0m0.009s                                                                 |
|user   0m0.000s                                                                 |
|sys    0m0.010s"                                                                |
|--------------------------------------------------------------------------------|

time ./Optimization_Test_with_a_single_assignment_to_Answer_compiled_by_GCC4.4.3_with_-ffast-math
 6.34785378539470E+08

real    0m0.002s
user    0m0.000s
sys     0m0.008s
here.

|--------------------------------------------------------------------------------|
|"I suspect this optimization is what the C++ compiler is doing, and the Ada     |
|compilers are not."                                                             |
|--------------------------------------------------------------------------------|

Actually, a C++ compiler optimized out calls to std::log10().

|--------------------------------------------------------------------------------|
|"Whether a similar optimization may be applied to the calculations in your real |
|program of interest is another question."                                       |
|--------------------------------------------------------------------------------|

Such an optimization can not help the log10 calls like that in the
real code because they are spread out in conditional statements
between hundreds of other statements instead of being an analytically
simple sequence of millions of calls to log, as per the following...
G4double G4LogLogInterpolation::Calculate(G4double x, G4int bin, 
					  const G4DataVector& points, 
					  const G4DataVector& data) const
{
  G4int nBins = data.size() - 1;
  G4double value = 0.;
  if (x < points[0])
    {
      value = 0.;
    }
  else if (bin < nBins)
    {
      /*..*/
      value = (std::log10(d1)*std::log10(e2/x) + std::log10(d2)*std::log10(x/e1)) /*..*/
  /*..*/
}
and
G4double G4SemiLogInterpolation::Calculate(G4double x, G4int bin, 
					  const G4DataVector& points, 
					  const G4DataVector& data) const
{
  G4int nBins = data.size() - 1; /*C++ programmers have a way of
                                   replicating statements across functions.*/
  G4double value = 0.;
  if (x < points[0])
    {
      value = 0.;
    }
  else if (bin < nBins)
    {
      /*..*/
      value = (d1*std::log10(e2/x) + d2*std::log10(x/e1)) /*..*/
  /*..*/
}
and
inline 
 size_t G4PhysicsLogVector::FindBinLocation(G4double theEnergy) const
{
  // For G4PhysicsLogVector, FindBinLocation is implemented using
  // a simple arithmetic calculation.
  //
  // Because this is a virtual function, it is accessed through a
  // pointer to the G4PhyiscsVector object for most usages. In this
  // case, 'inline' will not be invoked. However, there is a possibility 
  // that the user access to the G4PhysicsLogVector object directly and 
  // not through pointers or references. In this case, the 'inline' will
  // be invoked. (See R.B.Murray, "C++ Strategies and Tactics", Chap.6.6)

  return size_t( std::log10(theEnergy)//*Ugh, this division is unnecessary.*/dBin - baseBin );
}
and
G4double G4ProtonInelasticCrossSection::
GetCrossSection(G4double kineticEnergy, G4double atomicNumber, G4double nOfProtons)
{   
  /*..*/
  if(nOfNeutrons>1.5) fac2=std::log((nOfNeutrons));
  /*..*/
}
and
G4double G4LinLogLogInterpolation::Calculate(G4double x, G4int bin, 
					  const G4DataVector& points, 
					  const G4DataVector& data) const
{
  G4int nBins = data.size() - 1;
  G4double value = 0.;
  if (x < points[0])
    {
      value = 0.;
    }
  else if (bin < nBins)
    {
      /*..*/ /*C++ programmers have a way of replicating statements across functions...*/
      if(d1 > 0.0 && d2 > 0.0) { /*... and not remembering to include
                                   checks for mathematical
                                   well-definededness in each code
                                   clone nor indeed for each call to
                                   std::log10() in each statement
                                   guarded by two checks for
                                   mathematical well-definededness.*/
        value = (std::log10(d1)*std::log10(e2/x) + std::log10(d2)*std::log10(x/e1)) /*..*/
  /*..*/
}



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-16 14:54   ` Colin Paul Gloster
@ 2010-02-16 15:24     ` Colin Paul Gloster
  2010-02-16 19:01     ` Jeffrey R. Carter
  1 sibling, 0 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-16 15:24 UTC (permalink / raw)


On Tue, 16 Feb 2010, Colin Paul Gloster alleged:

|-------------------------------------------------------------------------------------------------|
|"[..]                                                                                            |
|                                                                                                 |
|time ./Optimization_Test_with_many_assignments_to_Answer_compiled_by_GCC4.4.3_with_-ffast-math   |
| 6.34785378608078E+08                                                                            |
|                                                                                                 |
|real    0m34.319s                                                                                |
|user    0m34.318s                                                                                |
|sys     0m0.004s                                                                                 |
|here.                                                                                            |
|                                                                                                 |
|[..]                                                                                             |
|                                                                                                 |
|time ./Optimization_Test_with_a_single_assignment_to_Answer_compiled_by_GCC4.4.3_with_-ffast-math|
| 6.34785378539470E+08                                                                            |
|                                                                                                 |
|real    0m0.002s                                                                                 |
|user    0m0.000s                                                                                 |
|sys     0m0.008s                                                                                 |
|here.                                                                                            |
|                                                                                                 |
|[..]"                                                                                            |
|-------------------------------------------------------------------------------------------------|

I apologize, those two runs were actually with GCC4.2.4.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 19:50     ` sjw
@ 2010-02-16 16:50       ` Colin Paul Gloster
  0 siblings, 0 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-16 16:50 UTC (permalink / raw)


[-- Attachment #1: Type: TEXT/PLAIN, Size: 12325 bytes --]

On Mon, 15 Feb 2010, S. J. W. posted:

|---------------------------------------------------------------------------|
|"[..]                                                                      |
|>                                                                          |
|> You see now what's happening.  With the gnatn switch the                 |
|> compiler is smart enough to call the Log just once, rather               |
|> than 10**6 times.                                                        |
|>                                                                          |
|> If you remove the -gnatn or -gnatN switches, then it runs in             |
|>  0m0.024s again.                                                         |
|                                                                           |
|The trouble is that that benchmark does something other than Colin's!"     |
|---------------------------------------------------------------------------|

That is not the problem. The code which I posted at the beginning of
this thread was not a means in itself, but was intended for timing
performances of implementations of logarithm functions in the base of
ten in a manner representative of real code which I use. The real code
is not dedicated to calculating something approximately equal to
6.3E+08. I could have written 500 * 1_000_000 calls or 3.14 * 1000
calls or a single call. A single call might have been overwhelmed by
overhead unrelated to the logarithm function. In the case of the C++
version when using a particular compilation switch, I failed in the
task because the hardcoded arguments I provided resulted in a trivial
and dramatic optimization which would not happen in the real code.

While it is unfortunate for Ada code in general that Ada compilers
fail to mimic this optimization of G++'s, that particular optimization
would not benefit the usage of logarithms in the real code I
mentioned. Dr. Jonathan Parker is free to pursue this problem in a
subthread or with vendors.

|---------------------------------------------------------------------------|
|"This might be a more accurate translation:                                |
|                                                                           |
|with Ada.Numerics.Generic_Elementary_Functions;                            |
|with Text_IO; use Text_IO;                                                 |
|procedure Log_Bench_0 is                                                   |
|   type Real is digits 15;                                                 |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions           |
|(Real);                                                                    |
|   use Math;                                                               |
|   Answer : Real := 0.0;                                                   |
|   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;       |
|begin                                                                      |
|   for I in 1 .. 1_000_000 loop                                            |
|      declare                                                              |
|         X : Real := 0.1;                                                  |
|      begin                                                                |
|         for J in 1 .. 500 loop                                            |
|            Answer := Answer + Log_Base_10_Of_E * Log (X);                 |
|            X := X + 0.1;                                                  |
|         end loop;                                                         |
|      end;                                                                 |
|   end loop;                                                               |
|   Put (Real'Image(Answer));                                               |
|end Log_Bench_0;                                                           |
|                                                                           |
|I've tried inlining GNAT's implementation (GCC 4.5.0, x86_64-aqpple-       |
|darwin10.2.0) and even just calling up the C log10 routine using an        |
|inline. None was very impressive compared to the g++ result.               |
|                                                                           |
|Colin's time: 37s                                                          |
|Jonathan's time (-O3 -ffast-math -gnatp): 16s                              |
|Jonathan;s time (-O3 -ffast-math -gnatp -gnatN -funroll-loops): 14s        |
|Jonathan's time (same opts, but using C log10()): 11s"                     |
|---------------------------------------------------------------------------|

That ordering does not necessarily hold...

GCC4.2.4...

gnatmake -O3 -ffast-math -gnatp Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp

time ./Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m14.328s
user    0m14.329s
sys     0m0.000s


gnatmake -O3 -ffast-math -gnatp -gnatN -funroll-loops Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops

time ./Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m14.346s
user    0m14.341s
sys     0m0.004s


GCC4.4.3 (slower than GCC4.2.4 for this program)...

gnatmake -O3 -ffast-math  Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m14.713s
user    0m14.689s
sys     0m0.000s


  gnatmake -O3 -ffast-math -gnatp Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m14.691s
user    0m14.693s
sys     0m0.000s


gnatmake -O3 -ffast-math -gnatp -gnatN -funroll-loops Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m14.690s
user    0m14.689s
sys     0m0.000s

|---------------------------------------------------------------------------|
|"so we still have 3 orders of magnitude to go to get to the g++ result:    |
|0.02s                                                                      |
|                                                                           |
|This is my final version, with the inlined GNAT implementation too:        |
|                                                                           |
|with Ada.Numerics.Generic_Elementary_Functions;                            |
|with System.Machine_Code; use System.Machine_Code;                         |
|with Text_IO; use Text_IO;                                                 |
|procedure Log_Bench is                                                     |
|   type Real is digits 15;                                                 |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions           |
|(Real);                                                                    |
|   use Math;                                                               |
|   Answer : Real := 0.0;                                                   |
|   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;       |
|   function LogM (X : Real) return Real;                                   |
|   pragma Inline_Always (LogM);                                            |
|   function LogM (X : Real) return Real is                                 |
|      Result : Real;                                                       |
|      NL : constant String := ASCII.LF & ASCII.HT;                         |
|   begin                                                                   |
|      Asm (Template =>                                                     |
|         "fldln2               " & NL                                      |
|       & "fxch                 " & NL                                      |
|       & "fyl2x                " & NL,                                     |
|         Outputs  => Real'Asm_Output ("=t", Result),                       |
|         Inputs   => Real'Asm_Input  ("0", X));                            |
|      return Result;                                                       |
|   end LogM;                                                               |
|   function LogL (X : Real) return Real;                                   |
|   pragma Import (C, LogL, "log10");                                       |
|begin                                                                      |
|   for I in 1 .. 1_000_000 loop                                            |
|      declare                                                              |
|         X : Real := 0.1;                                                  |
|      begin                                                                |
|         for J in 1 .. 500 loop                                            |
|--              Answer := Answer + Log_Base_10_Of_E * LogM (X);            |
|            Answer := Answer + LogL (X);                                   |
|            X := X + 0.1;                                                  |
|         end loop;                                                         |
|      end;                                                                 |
|   end loop;                                                               |
|   Put (Real'Image(Answer));                                               |
|end Log_Bench;                                                             |
|                                                                           |
|[..]"                                                                      |
|---------------------------------------------------------------------------|

Not all of those switches would yield fair proxies for timings of
logarithms in the real code which inspired this thread, but anyway...


64bit GCC4.2.4...
gnatmake -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math -largs /lib/libm.so.6

time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math
  6.34086408606382E+08

real    0m34.497s
user    0m34.494s
sys     0m0.004s


gnatmake -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m34.503s
user    0m34.506s
sys     0m0.000s


gnatmake -gnatN -funroll-loops -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m34.547s
user    0m34.546s
sys     0m0.004s

64bit GCC4.4.3...
gnatmake -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m34.257s
user    0m34.258s
sys     0m0.000s


gnatmake -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m34.474s
user    0m34.478s
sys     0m0.000s


gnatmake -gnatN -funroll-loops -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m34.188s
user    0m34.182s
sys     0m0.004s

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-15 18:26 ` (see below)
  2010-02-15 18:51   ` jonathan
  2010-02-15 20:00   ` sjw
@ 2010-02-16 17:33   ` Colin Paul Gloster
  2010-02-24 10:07     ` Colin Paul Gloster
  2 siblings, 1 reply; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-16 17:33 UTC (permalink / raw)


On Mon, 15 Feb 2010, William Findlay posted:

|------------------------------------------------------------------------|
|"On 15/02/2010 10:58, in article                                        |
|alpine.LNX.2.00.1002151055530.17315@Bluewhite64.example.net, "Colin Paul|
|Gloster" <Colin_Paul_Gloster@ACM.org> wrote:                            |
|                                                                        |
|> Of the two programs shown, the fastest C++ implementation on one test |
|> platform took less than one millisecond and the fastest Ada           |
|> implementation took one minute and 31 seconds and 874 milliseconds on |
|> the same platform. Both g++ and gnatmake were from the same           |
|> installation of GCC 4.1.2 20080704 (Red Hat 4.1.2-44).                |
|                                                                        |
|Is that 1 millisecond for 1e6 calls?"                                   |
|------------------------------------------------------------------------|

No, that was less than one millisecond for 500 * 10**6 C++ calls.

|------------------------------------------------------------------------|
|" This implies 1ns per call in C++.                                     |
|I find it incredible that a log function could be so fast.              |
|I think the loop body must be evaluated at compile-time in C++."        |
|------------------------------------------------------------------------|

The C++ compiler did manage to eliminate almost everything.

|------------------------------------------------------------------------|
|"On my system your Ada code gives:                                      |
|                                                                        |
|6.34086408536266E+08                                                    |
|                                                                        |
|real    0m33.918s                                                       |
|user    0m33.864s                                                       |
|sys     0m0.025s                                                        |
|                                                                        |
|And your original C++ code gives:                                       |
|                                                                        |
|6.34086e+08                                                             |
|real    0m0.110s                                                        |
|user    0m0.003s                                                        |
|sys     0m0.003s                                                        |
|                                                                        |
|But if I replace the C++ loop body by:                                  |
|                                                                        |
|      for(int j=1; j<=500; ++j)                                         |
|         answer += std::log10(j*0.100000000000000000000);               |
|It now gives:                                                           |
|                                                                        |
|6.34086e+08                                                             |
|real    0m18.112s                                                       |
|user    0m18.082s                                                       |
|sys    0m0.015s                                                         |
|                                                                        |
|This less than twice as fast as the more generalized Ada code.          |
|                                                                        |
|[..]"                                                                   |
|------------------------------------------------------------------------|

Thank you for exposing this flaw in the C++ code.

with Ada.Numerics.Generic_Elementary_Functions;
with Interfaces.C;
with Ada.Text_IO;
procedure Logarithmic_Work_In_Ada_with_a_Findlay_loop is
    answer : Interfaces.C.double := 0.0;
    package double_library is new Ada.Numerics.Generic_Elementary_Functions(Interfaces.C.double);
    package double_output_library is new Ada.Text_IO.Float_IO(Interfaces.C.double);
begin

    for I in 1 .. 1_000_000 loop
       for J in 1 .. 500 loop
          answer := Interfaces.C."+"(
                                     answer, double_library.log(
                                                                Interfaces.C."*"(
                                                                                 Interfaces.C.double(J),
                                                                                 0.100000000000000000000
                                                                                )
                                                                ,
                                                                10.0
                                                               )
                                    );
       end loop;
    end loop;

    double_output_library.Put(answer);
end;

gnatmake -O3 -ffast-math Logarithmic_Work_In_Ada_with_a_Findlay_loop.adb -o Logarithmic_Work_In_Ada_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math

time ./Logarithmic_Work_In_Ada_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m31.091s
user    0m31.090s
sys     0m0.004s

time ./Logarithmic_Work_In_Ada_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m31.094s
user    0m31.094s
sys     0m0.004s


gnatmake -O3 Logarithmic_Work_In_Ada_with_a_Findlay_loop.adb -o Logarithmic_Work_In_Ada_with_a_Findlay_loop_compiled_by_GCC4.4.3

  6.34086408606382E+08

real    0m31.388s
user    0m31.378s
sys     0m0.008s


g++ -O3 -ffast-math logarithmic_work_in_CPlusPlus_with_a_Findlay_loop.cc -o logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math

  time ./logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math
6.34086e+08
real    0m38.388s
user    0m38.390s
sys     0m0.000s

time ./logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math
6.34086e+08
real    0m38.547s
user    0m38.546s
sys     0m0.000s


g++ -O3 logarithmic_work_in_CPlusPlus_with_a_Findlay_loop.cc -o logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3

time ./logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3
6.34086e+08
real    0m38.428s
user    0m38.426s
sys     0m0.004s






with Ada.Numerics.Generic_Elementary_Functions;
with Interfaces.C;
with Ada.Text_IO;
procedure Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism is
    Log_Base_10_Of_The_Base_Of_The_Natural_Logarithm : constant Interfaces.C.Double := 0.434_294_481_903_251_827_651_129;

    answer : Interfaces.C.double := 0.0;
    package double_library is new Ada.Numerics.Generic_Elementary_Functions(Interfaces.C.double);
    package double_output_library is new Ada.Text_IO.Float_IO(Interfaces.C.double);
begin

    for I in 1 .. 1_000_000 loop
       for J in 1 .. 500 loop
          answer := Interfaces.C."+"
                                   (
                                     answer, Interfaces.C."*"
                                                            (
                                                              double_library.Log
                                                                               (
                                                                                 Interfaces.C."*"
                                                                                                (
                                                                                                  Interfaces.C.double(J),
                                                                                                  0.100000000000000000000
                                                                                                )
                                                                               )
                                                              ,
                                                              Log_Base_10_Of_The_Base_Of_The_Natural_Logarithm
                                                            )
                                   );
       end loop;
    end loop;

    double_output_library.Put(answer);
end;



gnatmake -O3 -ffast-math   Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math.adb -o   Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math

  time ./Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m14.434s
user    0m14.433s
sys     0m0.004s
-bash bluewhite64 /home/Colin_Paul/logarithms $


-bash bluewhite64 /home/Colin_Paul/logarithms $
  gnatmake -O3 Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism.adb -o Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3

  time ./Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3
  6.34086408606382E+08

real    0m14.450s
user    0m14.453s
sys     0m0.000s



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-16 14:54   ` Colin Paul Gloster
  2010-02-16 15:24     ` Colin Paul Gloster
@ 2010-02-16 19:01     ` Jeffrey R. Carter
  2010-02-17 10:25       ` Colin Paul Gloster
  1 sibling, 1 reply; 21+ messages in thread
From: Jeffrey R. Carter @ 2010-02-16 19:01 UTC (permalink / raw)


Colin Paul Gloster wrote:
> 
> |---------------------------------------------------------------------------------|
> |"Note that suppressing runtime checks (-gnatp) is needed to be sort of equivalent|
> |to C++."                                                                         |
> |---------------------------------------------------------------------------------|
> 
> Thanks for the tip, but I do not program in Ada to really program in
> C++ with Ada syntax.

I would hope not. But when comparing execution times between Ada and a language 
like C++, it's important not to try to compare apples to lugnuts.

-- 
Jeff Carter
"I don't know why I ever come in here. The
flies get the best of everything."
Never Give a Sucker an Even Break
102



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-16 19:01     ` Jeffrey R. Carter
@ 2010-02-17 10:25       ` Colin Paul Gloster
  0 siblings, 0 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-17 10:25 UTC (permalink / raw)


On Tue, 16 Feb 2010, Jeffrey R. Carter sent:

|------------------------------------------------------------------|
|"[..]                                                             |
|                                                                  |
|[..] when comparing execution times between Ada and a language    |
|like C++, it's important not to try to compare apples to lugnuts."|
|------------------------------------------------------------------|

Fair enough, but when I say Ada is better than C++ I am not comparing
an apple with an apple.

Anyway, as I mentioned in
news:alpine.LNX.2.00.1002161654110.21651@Bluewhite64.example.net
in response to Bill Findlay, G++ has produced much slower code than
GNAT (the GNATism is in standard Ada, merely the obvious way to do it
in standard Ada is different)...

gnatmake -O3 -ffast-math Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math.adb -o Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math

 time ./Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism_compiled_by_GCC4.4.3_with_-ffast-math
 6.34086408606382E+08

real    0m14.434s
user    0m14.433s
sys     0m0.004s


g++ -O3 -ffast-math logarithmic_work_in_CPlusPlus_with_a_Findlay_loop.cc -o logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math

 time ./logarithmic_work_in_CPlusPlus_with_a_Findlay_loop_compiled_by_GCC4.4.3_with_-ffast-math
6.34086e+08
real    0m38.388s
user    0m38.390s
sys     0m0.000s



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
  2010-02-16 17:33   ` Colin Paul Gloster
@ 2010-02-24 10:07     ` Colin Paul Gloster
  0 siblings, 0 replies; 21+ messages in thread
From: Colin Paul Gloster @ 2010-02-24 10:07 UTC (permalink / raw)


On Tue, 16 Feb 2010, Colin Paul Gloster alleged:

|------------------------------------------------------------------------------------------------------------------------|
|"[..]                                                                                                                   |
|                                                                                                                        |
|with Ada.Numerics.Generic_Elementary_Functions;                                                                         |
|with Interfaces.C;                                                                                                      |
|with Ada.Text_IO;                                                                                                       |
|procedure Logarithmic_Work_In_Ada_with_a_Findlay_loop_with_a_Parker_GNATism is                                          |
|   Log_Base_10_Of_The_Base_Of_The_Natural_Logarithm : constant                                                          |
|Interfaces.C.Double := 0.434_294_481_903_251_827_651_129;                                                               |
|                                                                                                                        |
|   answer : Interfaces.C.double := 0.0;                                                                                 |
|   package double_library is new                                                                                        |
|Ada.Numerics.Generic_Elementary_Functions(Interfaces.C.double);                                                         |
|   package double_output_library is new                                                                                 |
|Ada.Text_IO.Float_IO(Interfaces.C.double);                                                                              |
|begin                                                                                                                   |
|                                                                                                                        |
|   for I in 1 .. 1_000_000 loop                                                                                         |
|      for J in 1 .. 500 loop                                                                                            |
|         answer := Interfaces.C."+"                                                                                     |
|                                  (                                                                                     |
|                                    answer, Interfaces.C."*"                                                            |
|                                                           (                                                            |
|                                                             double_library.Log                                         |
|                                                                              (                                         |
|                                                                                Interfaces.C."*"                        |
|                                                                                               (                        |
|                                                                                                 Interfaces.C.double(J),|
|                                                                                                 0.100000000000000000000|
|                                                                                               )                        |
|                                                                              )                                         |
|                                                             ,                                                          |
|                                                             Log_Base_10_Of_The_Base_Of_The_Natural_Logarithm           |
|                                                           )                                                            |
|                                  );                                                                                    |
|      end loop;                                                                                                         |
|   end loop;                                                                                                            |
|                                                                                                                        |
|   double_output_library.Put(answer);                                                                                   |
|end;                                                                                                                    |
|                                                                                                                        |
|[..]"                                                                                                                   |
|------------------------------------------------------------------------------------------------------------------------|

Actually this is not a GNATism. I have noticed that
"*"(Left=>variable,
Right=>Log_Base_10_Of_The_Base_Of_The_Natural_Logarithm) is faster
than log(X=>variable, Base=>10.0) on a number of other compilers.



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2010-02-24 10:07 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
2010-02-15 13:02 ` John B. Matthews
2010-02-15 14:17   ` Colin Paul Gloster
2010-02-15 17:19     ` John B. Matthews
2010-02-15 14:54 ` jonathan
2010-02-15 15:04   ` jonathan
2010-02-15 19:50     ` sjw
2010-02-16 16:50       ` Colin Paul Gloster
2010-02-15 18:26 ` (see below)
2010-02-15 18:51   ` jonathan
2010-02-15 20:00   ` sjw
2010-02-15 21:17     ` jonathan
2010-02-16  0:09       ` jonathan
2010-02-16 17:33   ` Colin Paul Gloster
2010-02-24 10:07     ` Colin Paul Gloster
2010-02-15 23:04 ` Jeffrey R. Carter
2010-02-16 14:54   ` Colin Paul Gloster
2010-02-16 15:24     ` Colin Paul Gloster
2010-02-16 19:01     ` Jeffrey R. Carter
2010-02-17 10:25       ` Colin Paul Gloster
2010-02-15 23:20 ` Randy Brukardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox