No late homework submissions, but two drops. Any score is a full score.

Exams will be video-proctored and submitted via Gradescope.

An **algorithm** is a well-defined procedure for carrying out a given task. In this class, we will discuss arithmetic, graphs, scheduling, games, hashing, etc.

We will develop skills to design algorithms that halt and are

- correct (return the correct answer on every input)
- efficient (primarily in time, but will also discuss space/randomness, etc.)

Today, we will focus on addition and multiplication. We want algorithms and such that

- and is efficient
- and is efficient

How are integer inputs represented? Over time, people have devised different systems such as Roman numerals and Arabic numerals. The Arabic numeral system is called a **positional numeral system**. For example, in , the position of gives it a different meaning than the position of . This is as opposed to Arabic numerals, where means the same thing in the third position of as in the first or second position.

With digits, we can represent any integer between and . This is not the case with Roman numerals, which are more compact in their representation of various numbers. However, we will use Arabic numerals in this course.

First idea: "count by fingers"

Add to , times:

- Correctness:
- Efficiency: if are each -digit numbers, the time of the algorithm is

Second idea: "carry method"

For each digit location , sum digits at plus any carry from location .

- Correctness:
- Efficiency: , where is a constant 1-digit addition table lookup time, depending on your hardware

Can we do better than ? Only if we multithread, and in that case we'd need a critical section to handle carries.

First idea: "do , times"

- Correctness:
- Efficiency: , where in the cost to add

Second idea: "long multiplication"

Generally,

- Correctness:
- Efficiency: overall, (computing the products is steps, adding them up is another steps)

Can we do better? Yes!

We do not wish to count the exact number of elementary operations of an algorithm. We want to study growth rates a function of input size instead.

The addition algorithm ran in , which means that

The multiplication algorithm ran in , which means that

More generally, if for large enough , we have .

There is other notation that we will practice in discussion and homework:

- = at least
- = both and

Illustrative example of a powerful technique called **divide & conquer**

Since multiplication distributes over addition:

The running time of this algorithm is , where .

Remember that when summing the geometric series , we calculate where .

In our case, . This algorithm is, in fact, slower than our previous algorithm. Divide and conquer does not blindly give you a faster algorithm, but we're on the right track for a more clever recursion.

We don't need to compute and , only their sum! Then,

- return

This algorithm is now , as we break into 2 parts and do 3 multiplications instead of 4.