TIP: Click on subject to list as thread! ANSI
echo: os2prog
to: Mike Bilow
from: David Noon
date: 1995-12-10 21:58:04
subject: Cube root

On Wednesday, 95/12/06, Mike Bilow wrote to Mike Fisher about "Cube
root" as follows:

MB>  MF>                root:=exp(ln(P)/Q);
MB> 
MB> Am I really missing something here, or does Pascal have no 
MB> support for direct exponentiation?

Hi Mike,

You have just stumbled on one reason why I have felt for 20 years that
Pascal is a little too limited to be a real-world programming
language.

MB> The Qth root of P is 
MB> equal to P raised to the 1/Q power.  Using C, it is a heck 
MB> of a lot more efficient to compute a Qth root as such:
MB> 
MB>    double P, Q, root;
MB> 
MB>    root = pow(P, 1.0 / Q);

This is correct about pow() being more efficient than exp(ln()), but
it is not necessarily optimal.

MB> The direct exponentiation form uses a double precision 
MB> special case division -- taking a reciprocal -- which 
MB> corresponds to a machine instruction on the Intel math 
MB> coprocessor, while the logarithmic form uses a double 
MB> precision division that is not a special case.

The savings of using pow() are much greater than the handfull of CPU
cycles difference between a reciprocal and a full division.

MB> The direct 
MB> exponentiation form also incurs one function call, while 
MB> the logarithmic form incurs two.

This is also true. But there is more ...

Since I had nothing better to do today, I cooked up a couple of
programs that implemented the Newton-Raphson algorithm for solving
cube roots and compared this with raising the number to a one-third
power.

Firstly, I coded it in FORTRAN IV and used MS FORTRAN 5.1 to produce a
16:16 OS/2 executable. This yielded a slightly unexpected result that
the N-R method took about 25% longer than exponentiation. From this, I
gathered that exponentiation is handled by means other than calls to
log() and exp().

I then re-coded it in C and used Borland C/C++ 3.1 to produce a 16:16
DOS program. This gave me the more expected result that the N-R method
took about 40% less time than using pow(). I think that pow() is
implemented in the BCAF 3.1 run-time as exp(log()) without any further
thought on Borland's part.

So, I copied the code to use Borland C/C++ for OS/2 1.5 to produce a
0:32 OS/2 executable. This gave a very surprising result indeed! The
N-R method took 150% more time (two and a half times as long) to
execute than did pow().

Finally, I de-Borlandised the C source and compiled using C Set ++
2.01. This gave the even more extreme result that the N-R method took
more than 3 times as long as using pow(). What is more, the pow()
supplied by IBM ran almost twice as fast as the pow() supplied by
Borland for OS/2.

From the foregoing, I would conclude that implemnters of C/C++ do not
use exp(log()) any longer for coding pow(). Instead, they use some
more specialised algorithm, possibly with special cases for [small]
integer roots.

But, Pascal programmers cannot readily exploit this, since there is no
exponentiation supported directly by the language. So their situation
is like that of BCAF 3.1 programmers. Indeed, I would expect the code
in the BP7 RTL to be nearly identical to that in the BCAF 3.1 RTL, but
with no means of condensing the logarithm and exponentiation into a
single call. In fact, Wirth himself suggests using EXP(y*LN(x)) to
calculate x^y. Hence, the Newton-Raphson algorithm would be more
efficient for obtaining cube roots. [Strangely enough, Wirth
implemented the SQR() function to calculate x*x. When designing Pascal,
he seems to have ignored the significant to focus on the trivial.]

There is still one gotcha. The pow() function of C/C++ and the **
operator of FORTRAN do not like non-integer exponents of negative
numbers. You have to take absolute value and then re-apply the sign,
which is a little clumsy. The N-R method works just peachy keen with
negative arguments.

Therefore, I attach [Pascal] source code for the Newton-Raphson cube
root.

BTW, 'fair dinkum' means 'genuine'. ... :-)

Regards

Dave


========================== CUBRT.PAS =========================

{ A function to calculate cube roots
  using the Newton-Raphson method.}

FUNCTION CUBRT(N : REAL) : REAL;

CONST
     eps = 1E-12; { Adjust for hardware precision }
VAR
     x, xnew : REAL;
BEGIN
     IF N = 0 THEN
          xnew := 0
     ELSE IF N > 0 THEN
          xnew := 1
     ELSE
          xnew := -1;

     IF xnew  0 THEN
     REPEAT
          x := xnew;
          xnew := (x + x + N/SQR(x))*(1E0/3E0)
     UNTIL ABS(x-xnew) >= ABS(x)*eps;

     CUBRT := xnew
END;

==============================================================

 * KWQ/2 1.2i * Program call to load Windows NT- "Here_piggy_piggy_piggy"
--- Maximus/2 3.00
* Origin: DoNoR/2,Woking UK (44-1483-725167) (2:440/4)
SEEN-BY: 270/101 620/243 711/401 409 410 413 430 807 808 809 934 955 712/407
SEEN-BY: 712/515 517 628 713/888 800/1 7877/2809
@PATH: 440/4 141/209 270/101 712/515 711/808 809 934

SOURCE: echomail via fidonet.ozzmosis.com

Email questions or comments to sysop@ipingthereforeiam.com
All parts of this website painstakingly hand-crafted in the U.S.A.!
IPTIA BBS/MUD/Terminal/Game Server List, © 2025 IPTIA Consulting™.