comp.lang.ada
 help / color / mirror / Atom feed
From: Colin Paul Gloster <Colin_Paul_Gloster@ACM.org>
Subject: Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
Date: Tue, 16 Feb 2010 14:54:04 +0000
Date: 2010-02-16T14:54:04+00:00	[thread overview]
Message-ID: <alpine.LNX.2.00.1002161431250.21651@Bluewhite64.example.net> (raw)
In-Reply-To: <hlcko7$6r7$1@tornado.tornevall.net>

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)) /*..*/
  /*..*/
}



  reply	other threads:[~2010-02-16 14:54 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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
replies disabled

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