Why does this algorithm (about computing a^n) work?

Click For Summary

Discussion Overview

The discussion revolves around understanding the algorithm for computing a^n, where a is any integer and n is a nonnegative integer, using a specific Pascal-style pseudocode. Participants seek to clarify the roles of different parts of the algorithm, particularly focusing on the operations involving variables b and c, and how they contribute to the final result.

Discussion Character

  • Exploratory
  • Technical explanation
  • Conceptual clarification
  • Debate/contested

Main Points Raised

  • Some participants explain that the algorithm relies on the relationship a^n = b * (c^k), where b accumulates the product and c is squared as needed.
  • Others argue that understanding how b "knows" its value before multiplication with c is crucial, leading to confusion about the algorithm's logic.
  • A few participants suggest tracing the algorithm step by step with specific examples, such as k = 37, to clarify how the values of b and c evolve through iterations.
  • Some participants propose that the comment in the pseudocode only holds true if the order of operations is modified, indicating a potential flaw in the original description.
  • There is a discussion about the implications of using different integer sizes in computing powers, particularly in relation to the environment's bit capacity.
  • One participant highlights the importance of recognizing the binary representation of the exponent to understand when k will be odd or even during the algorithm's execution.

Areas of Agreement / Disagreement

Participants express varying levels of understanding regarding the algorithm, with some clarifying specific parts while others remain confused about the logic behind how b accumulates the correct value. There is no consensus on the clarity of the pseudocode's comment or the necessity of modifying the algorithm for it to hold true.

Contextual Notes

Some participants note that the pseudocode is not intended to be executed as real Pascal code, which may lead to misunderstandings about its functionality. Additionally, there are concerns about the limitations of integer sizes in different computing environments.

s3a
Messages
828
Reaction score
8

Homework Statement


Here is the algorithm (which works perfectly) for computing a^n for any integer a and a nonnegative integer n in Pascal-style pseudocode.:
Code:
k := n; b := 1; c:= a;
{a^n  = b * (c^k)}
while k <> 0 do begin
    if k mod 2 = 0 then begin
        k := k div 2;
        c := c * c;
    end else begin
        k := k - 1;
        b := b * c;
    end;
end;

Homework Equations


The given algorithm for computing a^n, where a is any integer and n is a nonnegative integer.

The Attempt at a Solution


I just wanted to know why this code works.

In particular, could someone please help me understand the roles that
Code:
c := c * c;
and
Code:
b := b * c;
play in the algorithm (because I'm trying to also understand the algorithm and not just memorize it)?

Any input would be GREATLY appreciated!
 
Physics news on Phys.org
I don't see how it returns the result, but the idea is simple - half of the algorithm is covered by the comment {a^n = b * (c^k)} (that's what b:=b*c; does), the other half relies on the fact a2n = an*an (that's what c:=c*c; does).
 
Last edited:
Trace how it works step by step, for say k = 37. You should be able to see how it calculates b = a^37, and what c contains at each step. (Note, there are a lot fewer that 37 iterations round the loop, so this shouldn't take too long).
 
AlephZero said:
Trace how it works step by step, for say k = 37.
Note - since a is an integer, you'd need a 64 bit environment to calculate even in the case of a = 2, (2^37). For a 32 bit environment, a smaller value of k would be needed.
 
s3a said:

Homework Statement


Here is the algorithm (which works perfectly) for computing a^n for any integer a and a nonnegative integer n in Pascal-style pseudocode.:
Code:
k := n; b := 1; c:= a;
{a^n  = b * (c^k)}
while k <> 0 do begin
    if k mod 2 = 0 then begin
        k := k div 2;
        c := c * c;
    end else begin
        k := k - 1;
        b := b * c;
    end;
end;
The only thing missing from this description is the output. When the loop ends, the final result is in b.

Take 2^10 as an example.
Before looping: k=10; b=1; c=2
At end of 1st pass: k=5; b=1; c=4
At end of 2nd pass: k=4; b=4; c=4
At end of 3rd pass: k=2; b=4; c=16
At end of 4th pass: k=1; b=64; c=16
At end of 5th pass: k=0; b=1024; c=16

The comment "a^n = b * (c^k)" is the clue. For each pass through the loop a^n is still equal to "b * (c^k)".
 
rcgldr said:
Note - since a is an integer, you'd need a 64 bit environment to calculate even in the case of a = 2, (2^37). For a 32 bit environment, a smaller value of k would be needed.

The question says it is pseudocode, not real Pascal code to be executed. Some languages have arbitrary-precision arithmetic as a part of the language standard - see http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#Stand-alone_application_software for a list.

The statement
Here is the algorithm (which works perfectly) for computing a^n for any integer a and a nonnegative integer n
couldn't possibly be correct otherwise.
 
Everyone:
Thank you for your answers.

Borek:
About the result, it is in the final value of b. What you said made me understand the
Code:
c := c * c;
part, so thanks for that.

Everyone:
However, I'm still confused about the
Code:
b := b * c;
part, because I have trouble with intuitively understanding how b “knows” which value to have prior to being multiplied by c.

Please tell me if that doesn't make sense, so I could find another way of explaining it.

AlephZero, .Scott:
I probably should have said this, but I have already worked out the algorithm several times before posting this thread.

rcgldr:
As AlephZero said, the code in my opening post is (Pascal-style) pseudocode (instead of “real” Pascal code).

Everyone:
Also, is it just me, or does the comment given in the opening post's pseudocode only hold true if the code is modified to be as follows?:
Code:
k := n; b := 1; c:= a;
{a^n  = b * (c^k)}
while k <> 0 do begin
    if k mod 2 = 0 then begin
        c := c * c;
        k := k div 2;
    end else begin
        b := b * c;
        k := k - 1;
    end;
end;
 
s3a said:
Everyone:
However, I'm still confused about the
Code:
b := b * c;
part, because I have trouble with intuitively understanding how b “knows” which value to have prior to being multiplied by c.
Please tell me if that doesn't make sense, so I could find another way of explaining it.
b doesn't "know" what value to have - it just has a value. The assignment statement above says to multiply the current values of b and c, and put the resulting product back in b, thereby overwriting the previous value. For example, if at the start b is 20 and c is 3, b's new value will be 60.
 
s3a said:
Also, is it just me, or does the comment given in the opening post's pseudocode only hold true if the code is modified to be as follows?
The order of operations doesn't matter, the statement only holds true after both c and k or both b and k are updated.
 
  • #10
s3a said:
Everyone:
However, I'm still confused about the
Code:
b := b * c;
part, because I have trouble with intuitively understanding how b “knows” which value to have prior to being multiplied by c.

Please tell me if that doesn't make sense, so I could find another way of explaining it.[/code]
OK, here is how the code works:
1) You start with one condition where a^n = b c^k, specifically when b=1, c=a, and k=n.
2) When k is odd, you decrement k and multiply b by c. So a^n is still equal to b c^k.
3) When k is even, you have k and square c. So a^n is still equal to b c^k.
4) By continuous checking cases 2 and 3, you eventually get to k=1. At that point, you have a^n = bc.
5) Since 1 is odd, you will decrement k and set b=b*c. At that point a^n = b c^k, but the value of k is zero, so c^k is 1 and you have a^n = b.

If you don't understand this, let me know and I will try to explain it better.
Basically, you set a^n = b c^k, and then keep on driving k down towards zero. When it reaches 0, b must have the result.
 
  • #11
Mark44 (and everyone else):
I meant:
What about the logic behind the algorithm ensures that, in the end, b is the exact multiplicand that, when multiplied with c, yields a^n?

In other words, what about the logic ensures that b compounds to the exact value needed for the next time k is odd?

rcgldr:
Oh, that makes sense.

Edit:
.Scott, I just saw that you posted something, I will check it out now.
 
  • #12
.Scott, I think I get it now!

Okay, so what the algorithm does is it defines a^n by the product b * c^k, and it works on accumulating “numeric weight” in the c variable by continually squaring the value that c holds and raising that new value held in the c variable by half the exponent (such that the algorithm keeps the a^n = b * c^k equation true, but has yet to shift the “numeric weight” to the b variable), as long as k is even, and, then, when k is odd, works on shifting that “numeric weight” to the b variable, by making use of the fact that a^n = (b * c) * c^(k – 1).

Does it seem like I understand it now?
 
  • #13
The insight needed is to recognize that if the exponent is expressed as a binary number, you can see when k is going to be odd or even as the algorithm progresses.

For example, if n is 37, expressing 37 as a binary number gives 100101. Start at the right and moving left one bit at a time, you can how k will be even or odd each step.

If the exponent were just a power of two, all that would be needed is to do c := c*c the appropriate number of times. If n isn't exactly a power of two, then you will need to do the b := b*c when a non zero bit shifts off the right end of the binary representation of n as you shift it right.

That's what the:

if k mod 2 = 0 then begin
k := k div 2;

is all about. It's converting the exponent to binary, one bit at a time.
 
  • #14
s3a said:
Also, is it just me, or does the comment given in the opening post's pseudocode only hold true if the code is modified to be as follows?:

Code:
k := n; b := 1; c:= a;
{a^n  = b * (c^k)}
while k <> 0 do begin
    if k mod 2 = 0 then begin
        c := c * c;
        k := k div 2;
    end else begin
        b := b * c;
        k := k - 1;
    end;
end;

As other said, that makes no difference. Personally I would have written if like this, which seems more logical to me because you do all the processing for one binary digit of k on one pass through the loop, not sometimes one pass and sometimes two:

Code:
while k <> 0 do begin
    if k mod 2 <> 0 then begin
        b := b * c;
    end;
    c := c * c;
    k := k div 2;
end;

Note the "k := k - 1" is no longer needed.
 
  • #15
Okay, so I think I finally get it.

Thanks everyone!
 

Similar threads

  • · Replies 1 ·
Replies
1
Views
1K
  • · Replies 4 ·
Replies
4
Views
2K
  • · Replies 1 ·
Replies
1
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
Replies
2
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 14 ·
Replies
14
Views
2K
Replies
33
Views
5K
  • · Replies 7 ·
Replies
7
Views
2K