From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,13280cdb905844e4 X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news4.google.com!feeder.news-service.com!188.40.43.213.MISMATCH!feeder.eternal-september.org!eternal-september.org!.POSTED!not-for-mail From: Colin Paul Gloster Newsgroups: comp.lang.ada 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 Organization: A noiseless patient Spider Message-ID: References: Reply-To: Colin Paul Gloster Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Injection-Date: Tue, 16 Feb 2010 14:56:22 +0000 (UTC) Injection-Info: news.motzarella.org; posting-host="kheEuXGHhE2Z5eF1gAST+A"; logging-data="25236"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19HSCQ/lf7hETmcHCywPVcqkBQZeRckK23wJB5QquZU6w==" User-Agent: Alpine 2.00 (LNX 1167 2008-08-23) In-Reply-To: Cancel-Lock: sha1:L0LDUjZsIvWwBsc0asZaL/f/mv0= X-X-Sender: Colin_Paul@Bluewhite64.example.net Xref: g2news1.google.com comp.lang.ada:9265 Date: 2010-02-16T14:54:04+00:00 List-Id: 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)) /*..*/ /*..*/ }