2e + 2e =?= 2(e+1) ?
it is true that left-hand side can be simplified
check:
28 + 28 ==
Computer Scientists need to know powers of 2
(they arise many places such as binary representation,
binary sizes of memory, ...)
as follows:
obtain higher powers of 2 from those basic ones plus key convenient observation:
e.g. obtain 231 as follows:
decompose 31 into 10s plus whatever's left over:
231 == 2()
== by Law (i)
which is
which is
thus if you ever see some text involving say 231 - 1,
you can relatively easily have a sense of how much that is
logarithm
inverse of exponentiation is
the function logb(z) returns value e such that be == z
i.e. logb(z) returns the power to which you need to raise b to get z
e.g. log2(32) returns
because works for the value y in the equation 2y == 32
e.g. log10(1000) returns
e.g. log2(1000) returns
Laws of Logarithms [pages A7-8 (in Appendix of our textbook)]:
0. b(logb(z)) == z
0.5 logb(be) == e
1. logb(x*y) == logb(x) + logb(y)
2. logb(xy) == y*logb(x)
3. loga(x) == logb(x)/logb(a)
(there are further ones; refer to your prior studies of math...
e.g. logb(x/y) == logb(x) - logb(y)
)
e.g. [0] 2log2(32) := 2 :=
e.g. [3] log2(1000) := log10(1000)/log10() := /
e.g. [1] consider seeking log5(80000)
well, note:
80000 == 8*10*10*10*10
== 8*()*()*()*()
== (gathering powers)
then log5(80000) := log5() := by (1)
which is
e.g. [2] log5(53) := 3*log5(5) := 3*
notation semi-common in Computer Science:
"lg(z)" is an abbreviation for "log2(z)"
e.g. lg(16) :=
factoring numbers
some numbers factor into smaller ones
e.g. 15 :=
e.g. 42 :=
e.g. 18 :=
e.g. 40 :=
e.g. 64 :=
some numbers do not factor into smaller ones, in which case we call them
e.g.
e.g.
e.g.
(1 not called "prime" because not significant as a factor for other numbers)
a number n is called "composite" iff .
e.g. 18 is composite
to completely/thoroughly factor a number into all its primes,
first divide out and save all the factors of the first prime ,
then divide out and save all the factors of the next prime ,
then divide out and save all the factors of the next prime ,
then divide out and save all the factors of the next prime ,
then divide out and save all the factors of the next prime ,
and so on
in our textbook, primes less than 100 are listed
at bottom page 210 in Section 3.5:
2, 3, 5, 7, 11, ...
can easily check divisibility for first three primes 2,3,5:
* a number is divisible by 2 iff its last digit is
* a number is divisible by 3 iff the sum of its digits is divisible by 3
can repeat if sum of digits isn't one digit
* a number is divisible by 5 iff
to check divisibility by larger primes,
you need to do the division and check whether it comes out even
DON'T BOTHER CHECKING PRIMES WHOSE SQUARES ARE LARGER THAN NUMBER
if reach this point, number is prime
e.g. for 24:
e.g. for 25:
e.g. for 26:
e.g. for
factorial
[page 145 in Section 2.3 of our textbook]
used for counting numbers of permutations, combinations of items
e.g. when analyzing sorting
the "factorial" of an integer n, denoted ,
is the product of all the integers from n down to 1
e.g. 2! := 2*1 :=
e.g. 5! := 5*4*3*2*1 :=
as a special case, 0! is defined to be
why isn't 0! := 0?
well, though it's true that when summing a number of values,
if the number of values is zero then we get the result ,
despite that situation with summing,
when multiplying a number of values,
if the number of values is zero then we get the result
e.g.:
23 = 2*2*2 :=
22 = 2*2 :=
21 = 2 :=
20 = _ :=
as if there's always an implicit "*1" or something
similarly:
3! = 3*2*1 :=
2! = 2*1 :=
1! = 1 :=
0! = _ :=
if the choice were different,
various properties would break down
e.g. that 2e+1 = 2*2e :
23 = 2*22
22 = 2*21
21 = 2*20
and similarly (n+1)! = (n+1)*n! :
3! = 3*2!
2! = 2*1!
1! = 1*0!
floor, ceiling
[pages 142-45 in Section 2.3 of our textbook]
these are Mathematicians' notations
for ~~rounding/truncation of floating-point number to integer -- down or up
⌊x⌋ denotes the "floor" of x
a.k.a.
(for not-quite-up-to-date Web-browsers: |_x_| )
which is the greatest integer less than or equal to x
⌈x⌉ denotes the "ceiling" of x
a.k.a.
(for not-quite-up-to-date Web-browsers: |¯x¯| )
which is the least integer greater than or equal to x
e.g. ⌊1.414⌋ :=
(for not-quite-up-to-date Web-browsers: |_1.414_| )
e.g. ⌊1.618⌋ :=
(for not-quite-up-to-date Web-browsers: |_1.618_| )
e.g. ⌈1.414⌉ :=
(for not-quite-up-to-date Web-browsers: |¯1.414¯| )
e.g. ⌈1.618⌉ :=
(for not-quite-up-to-date Web-browsers: |¯1.618¯| )
e.g. usage: floor "⌊x⌋" used often in programs
using "|(int)|" to convert |double| to |int|
e.g. application for ceiling "⌈x⌉":
* pigeonhole principle (presented later)
* when searching a list using binary search,
how many times may compare against the target
⌈lg(list.length)⌉
e.g. what may be the number of days between two times given in milliseconds
well, the number of ms per day is
1000ms/s * 60s/m * 60m/h * 24h/d := ms/d
then
but if the time-difference in days is ,
do you say the number of days between the two times is 57 or 58??
using floor, ⌊57.87...⌋ :=
(for not-quite-up-to-date Web-browsers: |_57.87_| )
using ceiling, ⌈57.87...⌉ :=
(for not-quite-up-to-date Web-browsers: |¯57.87¯| )
quotient, remainder/modulus
[pages 200ff. in Section 3.4 of our textbook]
basic features of division for integers:
"division algorithm":
the issue is, how can you do division
if you don't already know it
but have simpler operations such as + and - ?
divide integer a by positive divisor d by
repeatedly subtracting d from a (using r for intermediate values)
while using q to count number of subtractions done
until left with remainder r less than d.
the results are the final values of:
* q, which is the quotient — the
number of times d can be taken away from a; and
* r, the remainder
Note:
I won't be requiring you to write code like this in this course (MTH 225).
But I do expect you to be able to understand it,
considering this course's ~~prerequisite CS 162.
int[] division_algorithm(int n, int d) {
if ( d <= 0 )
throw new IllegalArgumentException("divisor should be positive");
int q = 0, r = n;
// typically, reduce high value, until remainder is less than |d|:
while ( d <= r ) {
r -= d;
q++;
}
// alternatively, if value was negative, increase until not negative:
while ( r < 0 ) {
r += d;
q--;
}
int[] results = {q, r};
return results;
}
(our textbook presents somewhat different version page 225)
like CS 251 MIPS computer instruction div
yields quotient in one register, remainder in another
e.g. (3rd grade?) divide 126 by 23:
note quotient q := ⌊n/d⌋
(for not-quite-up-to-date Web-browsers: |_ n / d _| )
e.g. 48/5 := ;
⌊48/5⌋ := ⌊⌋ :=
(for not-quite-up-to-date Web-browsers: |_ 48 / 5 _| := ... )
(when doing division of two declared integers,
Java and other programming languages automatically yield
integer truncation like that
instead of real n/d
but handling negative values maybe more as you would expect)
more abstractly (i.e. instead of referring to that primitive algorithm),
if n is any integer and d is a positive integer
then dividing n by d yields unique integers q and r
with r one of the values {0,1,2,..,(d-2),(d-1)}
such that n == d*q + r
we call q the "quotient" and r the "remainder"
e.g. dividing n=48 by d=5 yields q := and r :=
satisfying (n=48) == (d=5)*(q=) + (r=)
and (r=) being one of the values {0,1,2,...,(d-2=),(d-1=)}
and there are no other possibilities for q and r satisfying the conditions
notably that r must be one of the values {0,1,2,..,(d-2),(d-1)}
don't say
dividing n=48 by d=5 yields q := 10 and r := -2
e.g. dividing n=52 by d=3 yields q := and r :=
e.g. dividing n=64 by d=8 yields q := and r :=
e.g. dividing n = -25 by d = 7 yields q := and r :=
the values for r being considered here are only {0,1,2,...,(d-2=),(d-1=)}
not considering possible negative values for r
which forces q := and r :=
satisfying (n=-25) == (d=7)*(q=) + (r=)
again note quotient q := ⌊n/d⌋
(for not-quite-up-to-date Web-browsers: |_ n / d _| )
e.g. (-25)/7 := ;
⌊(-25)/7⌋ := ⌊⌋ :=
(for not-quite-up-to-date Web-browsers: |_ (-25) / 7 _| := ... )
actually we'll focus more on remainder (r) than quotient
further special notation for it is as follows:
"n d" returns the remainder r obtained as above
here "mod" may be read
and d called the "modulus"
so might use identifier instead of "d"
this operation called "modulus operation"
e.g. 27 mod 5 :=
e.g. 21 mod 7 :=
(in Java as well as in C++ and C, can use for "mod"
but again whereas here consider only nonnegative remainders,
in a program % can yield negative value if operands are negative
(probably because such a scheme easier to implement))
application of mod:
consider game such as Minesweeper
program places mines at apparently randomly chosen locations
(5,2), (6,3), (0,7), ...
how obtain those random values 5, 2, 6, 3, 0, 7, ...?
"linear congruential method" provides such pseudo-random integers
x0, x1, x2, x3, ... as follows
start with seed s say (last few digits of) current time
e.g.
have modulus say 2000
multiplier μ say 101,
increment c say 997
start x0 := s
then generate succesive apparently random integers as follows:
xnext := (μ*xprev + c) mod m
e.g. x1 := (101* + 997) mod 2000
:= ( + 997) mod 2000
:= mod 2000
:=
e.g. x2 := (101* + 997) mod 2000
:= ( + 997) mod 2000
:= mod 2000
:=
e.g. x3 := (101* + 997) mod 2000
:= ( + 997) mod 2000
:= mod 2000
:=
e.g. x4 := (101* + 997) mod 2000
:= ( + 997) mod 2000
:= mod 2000
:=
e.g. x5 := (101* + 997) mod 2000
:= ( + 997) mod 2000
:= mod 2000
:=
thus x0 := , x1 := , x2 := , x3 := ,
x4 := , x5 := , ...
system maintains sequence of x-values like that behind the scenes
so if you request a random number between 0 and a small value k,
e.g. if you use Java Random.nextInt(k)
then system gives you xcurrent mod k i.e. x_current % k
e.g. if k is 10
mod 10 yields
mod 10 yields
mod 10 yields
mod 10 yields
mod 10 yields
·
·
·
will appear random
except sequence will repeat
... xm-2, xm-1,
xm=x0, xm+1=x1, xm+2=x2, ...
so called "pseudo"-random
computer-systems' pseudorandom number generators
use very large m to stave this off
&~&~digressions
~~digression part 1. "A Little 'Arithmancy'"
in-class activity
getting started thinking more consciously about
number representation
than you might otherwise
[Acknowledgement: I learned this trick from Pablo Trefftz]
I'm such a fan of the Harry Potter books
such as
that I can do Arithmancy with such.
Each of you choose a three-digit number say a whose digits
from left to right are descending
e.g. 987 or 421 or 530
but not 123 nor 767
nor 007 (—not truly three-digit)
Let b be the reverse of a; write b under a.
e.g. 987
789
Perform the subtraction a - b, obtaining say c.
e.g. 987 - 789 = ...
Then let d be the reverse of that last result c; write d under c.
Perform the addition c + d , obtaining say e.
Now a volunteer is needed.
Volunteer, let f be the number obtained from the first three digits
of your number e, and let g be the last digit.
Look at page number f in this book, and on this page count down g lines.
Concentrate on the word at the front of that line...
Is it ?
Explication of the math:
Let H, T, and U denote the three digits
of the initial three-digit number a
so a = 100*H + 10*T + 1*U and 9 ≥ H > T > U ≥ 0
The reverse of a, namely b, is UTH; i.e. b = 100*U + 10*T + 1*H.
Then c := a - b = .
Let X := H - U. Then note 9 ≥ X ≥ 2.
Then c = .
Or, doing the 'borrowing' from higher-order digits that is standard
during subtraction,
c = .
Then the reverse of c, namely d, is .
Then e := c + d = = ,
i.e. e is .
And then f is and g is .
Knowing all this in advance, for this trick you need to memorize just one word
from the book.
The point of that activity is to raise your awareness about
(decimal) number representation
to prepare for the next activities.
~~digression part 2. "A Little Binary"
rem. puzzle of first lecture:
Suppose the following:
* You have an employee who is supposed to work for you for seven days.
* The salary for this employee is supposed to be one ounce of gold per day.
* You have a seven-ounce brick of gold.
* Instead of waiting till the end of the seven days to pay the total salary,
the employee should have one ounce by the end of the first day,
two ounces by the end of the second day,
three ounces by the end of the third day,
and so on.
* The brick of gold has graduated one-ounce marking lines as follows:
+---+---+---+---+---+---+---+
| . . . . . . |
| . . . . . . |
| . . . . . . |
+---+---+---+---+---+---+---+
* The only way you can divide the brick of gold is by using a saw which you
have to make straight cuts along those graduated marking lines.
* You do not want to make more than two cuts (because cutting causes
loss of gold sawdust).
as mentioned that day,
what's happening here is actually
whereas we (humans) typically represent numbers using decimal sequences of digits
involving powers of ten
with ..., a hundreds place, a tens place, and a ones place,
(see digression 1 above),
binary also works
involving powers of two
with ..., a fours place, a twos place, and a ones place:
decimal | binary
--------+-------
1 | 001
2 | 010
3 | 011
4 | 100
5 | 101
6 | 110
7 | 111
... | ...
that chart shows how each decimal number from 1 to 7
can be represented by an appropriate combination of the three
values 4, 2, and 1
(just as every number from 1 to 999 can be represented by some appropriate combination
of the values 100,10,1).
binary representation
which I'll be discussing below
is important for Computer Science.
~~digression part 3: "A Little Ternary"
Computer Science uses further number representations,
particularly hexadecimal and octal.
Though this third activity doesn't involve them,
the point is to make you aware that there can be further number representations
in addition to base ten, base two
[Acknowledgement: I learned about this puzzle from Andy Felt.]
A farmer had a 40-pound rock used as a counterweight on scales
to measure weights of containers of produce.
A 'friend' borrowed the rock, but they dropped it,
and it broke into four pieces.
The farmer said,
"That's OK: actually now I can achieve weights equal to every number
up to 40."
What are the weights of the pieces?
Solution:
Mathematical explication:
binary representation of integers
(Section 3.6 of our textbook)
need to know this material
to be able to understand how computers encode all data
well, remembering back to ,
what is the interpretation
of our normal decimal i.e. base-ten representation of integers?
digits are
e.g. 397ten has 3 in 100s place, 9 in 10s place, 7 in 1s place
i.e. 397ten ==
I use notation "di" for the digit in the 10i place
e.g. for 397ten, d0 = , d1 = , d2 =
why might decimal representation concern any of you now?
well, someone has to implement Integer.toString(int)
which depends on handling (individual) digits; what if it's you?
public class ... {
public static void main(String[] args) {
int n_given = new Random() .nextInt(1000);
System.out.println("n_given's digit d0: " + digit(n_given, 0));
System.out.println("n_given's digit d1: " + digit(n_given, 1));
System.out.println("n_given's digit d2: " + digit(n_given, 2));
}
for each of a given number ngiven's digits di
corresponding to our base's powers 10i,
di := ⌊ngiven / 10i⌋ mod 10
(for not-quite-up-to-date Web-browsers: ... |_ ngiven / 10i _| ...)
public static int digit(int n_given, int place) {
}
}
e.g. ⌊397 / 100⌋ mod 10
:= ⌊397/⌋ mod 10
:= ⌊⌋ mod 10
:= which is d0
e.g. ⌊397 / 101⌋ mod 10
:= ⌊397/⌋ mod 10
:= ⌊⌋ mod 10
:= mod 10
:= which is d1
e.g. ⌊397 / 102⌋ mod 10
:= ⌊397/⌋ mod 10
:= ⌊⌋ mod 10
:= mod 10
:= which is d2
anyway, people(/computers) have used and still use some bases other than ten
ancient Babylonians used base sixty(!)
various LINUX/UNIX utilities such as access-control use
base-eight representation called
for base eight, digits are
e.g. 162eight == 1*82 + 6*81 + 2*80
== ten + ten + ten
== ten
and Computer Science also uses hexadecimal which is base
used for compactness and convenient conversion with the following base:
fundamental base Computer Science uses is
ultimately because it's easiest to build machines
processing data represented this way
this was an insight of in 1945:
The all-or-none, two-equilibrium arrangements
[of electronic components] are [best]. [Then]
it is natural to use a system of arithmetic
in which the digits are also two-valued.
"First Draft of a Report on the EDVAC
[Electronic Discrete Variable Automatic Computer]"
in that paper, von Neumann specified further basic features
for design of computers
e.g. central arithmetic unit, memory, stored program, ...
all computers now conform to that design called "von Neumann architecture"
anyway,
base-two arithmetic called
for base two, digits are only
abbreviates "binary digit"
e.g. 110two
i.e. 110two == 1*22 + 1*21 + 0*20
== ten + ten + ten
== ten
(reversing: ten == 110two)
e.g. 1001011two
i.e. 1001011two == 1*26 + 0*25 + 0*24 + 1*23 + 0*22 + 1*21 + 1*20
== ten +
+ ten + + ten + ten
== ten
(reversing: ten == 1001011two)
thus can obtain decimal representation of a number presented in binary
like with base ten above,
for each of a given number ngiven's binary digits bi
corresponding to powers 2i,
e.g. for 1001011two, b0 = , b1 = , b2 = ,
b3 = , b4 = , b5 = , b6 =
bi := ⌊ngiven / 2i⌋ mod 2
(for not-quite-up-to-date Web-browsers: ... |_ ngiven / 2i _| ...)
e.g. for b0 ⌊75 / 20⌋ mod 2
:= ⌊75/⌋ mod 2
:= ⌊⌋ mod 2
:= which is b0
e.g. for b1 ⌊75 / 21⌋ mod 2
:= ⌊75/⌋ mod 2
:= ⌊⌋ mod 2
:= mod 2
:= which is b1
e.g. for b2 ⌊75 / 22⌋ mod 2
:= ⌊75/⌋ mod 2
:= ⌊⌋ mod 2
:= mod 2
:= which is b2
incidentally, notice that
⌊75 / 22⌋ == ⌊⌊75 / 21⌋ / 2⌋
and we had already calculated ⌊75 / 21⌋
generally, ⌊u / ve+1⌋ == ⌊⌊u / ve⌋ / v⌋
(as u/ve+1 == (u/ve)/v )
enabling us to do these evaluations more easily as follows:
e.g. ⌊75 / 23⌋ mod 2
:= ⌊⌊75 / 22⌋ / 2⌋ mod 2
:= ⌊ / 2⌋ mod 2
:= ⌊⌋ mod 2
:= mod 2
:= which is b3
e.g. ⌊75 / 24⌋ mod 2
:= ⌊⌊75 / 23⌋ / 2⌋ mod 2
:= ⌊ / 2⌋ mod 2
:= mod 2
:= which is b4
e.g. ⌊75 / 25⌋ mod 2
:= ⌊⌊75 / 24⌋ / 2⌋ mod 2
:= ⌊ / 2⌋ mod 2
:= mod 2
:= which is b5
e.g. ⌊75 / 26⌋ mod 2
:= ⌊⌊75 / 25⌋ / 2⌋ mod 2
:= ⌊ / 2⌋ mod 2
:= mod 2
:= which is b6
such processing actually provides algorithm
for obtaining binary representation of a number
presented in decimal
here's ≈Java encoding of this algorithm:
(≈p.221 in our textbook)
Note:
I won't be requiring you to write code like this in this course (MTH 225).
But I do expect you to be able to understand it,
considering this course's ~~prerequisite CS 162.
void base_2_expansion(int n, int[] b) { // resulting bits stored in |b[]|
// i.e. this code will set |b[]|
// to be {...,1,0,1,1,0,0,...}
// as appropriate
// let |ngiven| denote the initial given value for e
int k = 0;
while ( n > 0 ) {
// at this point n == ⌊ngiven/2n⌋
b[k] = n % 2;
n = n/2; // in Java, division of |int|s automatically does floor
// so this statement |n = n/2;| resets n
// to: ⌊⌊ngiven / 2k⌋ / 2⌋
// which is: ⌊ngiven / 2(k+1)⌋
k = k + 1; // then with k changed here to k + 1,
// n == ⌊ngiven / 2k⌋ for the new k
}
// assume |b[]| otherwise contains zeroes
}
e.g. what may be binary representation of 98ten?
98 = . . . ?0?or?1? ?0?or?1? ?0?or?1? ?0?or?1? ?0?or?1? ?0?or?1?
[ten] -------- -------- -------- -------- -------- -------- [two]
25=32 24=16 23=8 22=4 21=2 20=1
place place place place place place
invoke base_2_expansion(98, int_array) as follows:
void base_2_expansion(int n, int[] b) {
// let |ngiven| denote the initial given value for n:
int k = 0;
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 98 == ⌊98/20⌋
b[k] = n % 2; // b[0] = 98 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 49 == ⌊98/21⌋
b[k] = n % 2; // b[1] = 49 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 24 == ⌊98/22⌋
b[k] = n % 2; // b[2] = 24 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 12 == ⌊98/23⌋
b[k] = n % 2; // b[3] = 12 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 6 == ⌊98/24⌋
b[k] = n % 2; // b[4] = 6 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 3 == ⌊98/25⌋
b[k] = n % 2; // b[5] = 3 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
{
// at this point n == ⌊ngiven/2n⌋ i.e. 1 == ⌊98/26⌋
b[k] = n % 2; // b[6] = 1 % 2 ;
n = n/2 ;
k = k + 1 ;
}
while ( n > 0 )
}
summarizing,
i.e. 98ten == *26 + *25 + *24 + *23 + *22 + *21 + *20
== two
application of binary representation of integers:
repeated squaring algorithm good way to do exponentiation
a straightforward way to do exponentiation is as follows:
the following code is supposed to return ae:
Note:
I won't be requiring you to write code like this in this course (MTH 225).
But I do expect you to be able to understand it,
considering this course's ~~prerequisite CS 162.
int exponentiation(int a, int e) {
}
note loop repeats e times
thus do operations in the loop such as the important multiplication e times
well consider what occurs in cryptographic secure communication:
a message such as "HI" represented as number a e.g. a=0910
and then need to calculate ae (modulo another value m)
where e is a number such as the following:
692,469,504,614,203,622,460,465,868,734,959,711,852,932,318,
302,149,455,793,493,889,446,970,470,508,640,328,165,696,445,
236,740,914,740,354,470,714,166,287,934,901,598,998,105,531,
316,760,680,771,813
the number of seconds required by a computer
to do e multiplications
would be at least the following:
692,469,504,614,203,622,460,465,868,734,959,711,852,932,318,
302,149,455,793,493,889,446,970,470,508,640,328,165,696,445,
236,740,914,740,354,470,714,166,287,934,901,598,998,105,531,
316,760 s.
in years that's more than the following:
692,469,504,614,203,622,460,465,868,734,959,711,852,932,318,
302,149,455,793,493,889,446,970,470,508,640,328,165,696,445,
236,740,914,740,354,470,714,166,287,934,901,598,998,105 y.
instead of that,
repeated squaring algorithm faster way to calculate ae
even with that value of e
loop (shown below) will repeat only times(!)
which requires only a fraction of a second
to understand this algorithm,
consider first a simple example:
suppose e is 8192
and suppose the following operations are performed:
sqrrep := a;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
at that point have ae — doing only operations, not 8192(!)
what if e is 139264 which is 131072 + 8192 ?
result := 1;
sqrrep := a;
// now sqrrep is a1 which is a20
sqrrep := sqrrep * sqrrep;
// now sqrrep is a2 which is a21
sqrrep := sqrrep * sqrrep;
// now sqrrep is a4 which is a22
·
·
·
sqrrep := sqrrep * sqrrep;
// now sqrrep is a8192 which is a213
result := result * sqrrep;
// now result is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
sqrrep := sqrrep * sqrrep;
// now sqrrep is a which is a2
result := result * sqrrep;
at the end here that last multiplication result * sqrrep
is a8192 * a131072 (which is a213 * a217 )
which equals a
(which is a)
by Law 1 of Exponents
which equals a139264 i.e. ae which was desired
(incidentally note that e=139264ten == 100010000000000000two
and the binary representation reflects that e is 1*217 + 1*213 )
the repeated squaring algorithm for calculating ae generalizes
from the preceding examples:
start result at 1 and sqrrep at a ;
repeatedly square sqrrep so sqrrep holds values of a
raised to successive powers of two;
and include value of sqrrep in result
if e contains the corresponding power of two.
here's Java encoding of this algorithm:
int exponentiation(int a, int e) {
int result = 1;
int sqrrep = a;
while ( e > 0 ) {
// e == ⌊egiven / 2i⌋ and sqrrep == a2i
if ( e % 2 == 1 ) // as above with binary representation
// this condition corresponds
// to egiven containing 2i
result = result * sqrrep; // so make |result| contain sqrrep == a2i
sqrrep = sqrrep * sqrrep; // advance sqrrep to a2(i+1)
e = ⌊e/2⌋; // advance e to ⌊egiven/2(i+1)⌋
}
return result;
}
as above when determining binary representation,
e % 2 == 1 holds iff egiven contains corresponding 2i ;
and (as indicated in examples for 8192 etc. above),
sqrrep is the corresponding a2i
incidentally, further for cryptography,
we may not care about full result so much as
result mod another number m
in this case actually do mod m different times during the algorithm
as shown in our textbook by Rosen p.226 (Algorithm 5)
e.g. to calculate 91027 mod 2001
don't straightforwardly start 91027 (= )
that would lose precision
(even if not with this relatively small example exponent 27,
consider more realistic large exponent indicated above)
int modular_exponentiation(
int a, int e, int m // a := , e := , m :=
)
{
int result = 1; // result :=
int sqrrep = a % m; // sqrrep := % :=
while ( e > 0 ) { // > 0 :=
if ( e % 2 == 1 ) // % 2 == 1 := == 1 :=
result = result * sqrrep % m;
// result := * %
// := %
// :=
sqrrep = sqrrep * sqrrep % m;
// sqrrep := * %
// := %
// :=
e = ⌊e/2⌋; // e := ⌊/2⌋ := ⌊⌋ :=
}
while ( e > 0 ) { // > 0 :=
if ( e % 2 == 1 ) // % 2 == 1 := == 1 :=
result = result * sqrrep % m;
// result := * %
// := %
// :=
sqrrep = sqrrep * sqrrep % m;
// sqrrep := * %
// := %
// :=
e = ⌊e/2⌋; // e := ⌊/2⌋ := ⌊⌋ :=
}
while ( e > 0 ) { // > 0 :=
if ( e % 2 == 1 ) // % 2 == 1 := == 1 :=
result = result * sqrrep % m;
sqrrep = sqrrep * sqrrep % m;
// sqrrep := * %
// := %
// :=
e = ⌊e/2⌋; // e := ⌊/2⌋ := ⌊⌋ :=
}
while ( e > 0 ) { // > 0 :=
if ( e % 2 == 1 ) // % 2 == 1 := == 1 :=
result = result * sqrrep % m;
// result := * %
// := %
// :=
sqrrep = sqrrep * sqrrep % m;
// sqrrep := * %
// := %
// :=
e = ⌊e/2⌋; // e := ⌊/2⌋ := ⌊⌋ :=
}
while ( e > 0 ) { // > 0 :=
if ( e % 2 == 1 ) // % 2 == 1 := == 1 :=
result = result * sqrrep % m;
// result := * %
// := %
// :=
sqrrep = sqrrep * sqrrep % m;
// sqrrep := * %
// := %
// :=
e = ⌊e/2⌋; // e := ⌊/2⌋ := ⌊⌋ :=
}
while ( e > 0 ) { // > 0 :=
return result; // return
}
secure communication would transmit 0211 instead of 0910 ("HI")
but then what?
well, receiver would calculate (211867) mod 2001 :=
the receiver needs to know
stay tuned for explanation of that in next lecture-module
(Copyright © 2008 by
Hugh McGuire
—
for thoughts about this, see
http://www.cis.gvsu.edu/~mcguire/teaching/copyright_thoughts.html .)