# 【官方双语】那么……什么是卷积？

- Source: https://www.bilibili.com/video/BV1Vd4y1e7pj (哔哩哔哩)
- Creator: 3Blue1Brown
- Published: 2022-12-21T10:30:00.000Z
- Transcribed by Memora: 2026-07-03T14:40:16.253Z
- Canonical page: https://dailymemora.com/bilibili/15

> Transcript and summary produced by Memora from the publicly available
> video linked above. The original video belongs to its creator.

## Summary

### 卷积是一种滑动、相乘、求和的操作

与加法或乘法不同，卷积通过**翻转**一个列表或函数，**滑动**它经过另一个，**相乘**对齐的项，并**求和**来组合两个列表或函数。骰子点数和的概率说明了这一点：结果中的每一项是索引之和为给定值的索引对的乘积之和。将`[1,2,3]`与`[4,5,6]`进行卷积会产生一个新序列。同样的操作也用作**移动平均**：一个小核（例如，全部为1/5）在数据上滑动产生平滑版本。扩展到二维，一个3×3的1/9网格平均相邻像素，从而模糊图像。

### 卷积核驱动图像处理和CNN

- **高斯模糊**：一个中心权重较大的核比均匀平均更真实地衰减。
- **边缘检测**：左侧为正数、右侧为负数的核突出垂直边缘（负值显示为红色，正值显示为蓝色）；旋转版本检测水平边缘。
- **锐化**和其他效果通过特定核实现，构成**卷积神经网络**的基础。

### 卷积是多项式乘法

在代数上，两个列表的卷积等同于它们的表示多项式的乘法：乘积中的每个系数来自沿成对乘积的对角线求和。这一见解提出了一种更快的算法：在足够多的点上评估两个多项式，逐点相乘这些值，然后通过插值恢复系数。选择**均匀分布的复数（单位根）**引入冗余，**快速傅里叶变换（FFT）**利用这一点，以**O(n log n)**时间计算卷积，而不是朴素的O(n²)。

### FFT使卷积在大规模上实用

FFT将操作从O(n²)减少到O(n log n)。过程是：计算两个列表的FFT（将它们视为在特殊点评估的多项式系数），逐点相乘结果，然后应用逆FFT。这样廉价地得到卷积。该方法适用于卷积出现的任何地方——添加概率分布、大规模图像处理等。

### FFT可以通过数字卷积乘以大整数

普通乘法本质上是对数字进行**卷积**加上进位。因此，FFT比学校教授的O(n²)方法更快地乘以大整数，尽管数字必须非常大才能使开销得到回报。视频预告了下一个主题：连续情况下的卷积，特别是概率分布。

## Key points

- 卷积翻转一个列表，滑动它经过另一个，相乘对齐的项，并求和以产生新序列。
- 在图像处理中，卷积核可以模糊（高斯），检测边缘（正/负分割），锐化；它们是卷积神经网络的核心。
- 卷积在代数上等同于多项式乘法，其中系数来自沿对角线求和成对乘积。
- 快速傅里叶变换（FFT）通过评估多项式在单位根上，逐点相乘，并进行逆变换，以O(n log n)时间计算卷积。
- 普通整数乘法是数字卷积加上进位，因此FFT可以比标准O(n²)方法更快地乘以大数，但仅对极大输入有效。

## Chapters

- [0:00](https://dailymemora.com/bilibili/15?t=0) Introduction to Convolutions
- [7:28](https://dailymemora.com/bilibili/15?t=448) Applications and Fast Fourier Transform

## Transcript

**[0:00]**  Suppose I give you two different lists of numbers, or maybe two different functions,

**[0:04]**  and I ask you to think of all the ways you might combine those two lists to get a new list of

**[0:08]**  numbers, or combine the two functions to get a new function. Maybe one simple way that comes to

**[0:13]**  mind is to simply add them together term by term. Likewise with the functions, you can add all the

**[0:18]**  corresponding outputs. In a similar vein, you could also multiply the two lists term by term

**[0:23]**  and do the same thing with the functions. But there's another kind of combination just as

**[0:28]**  fundamental as both of those, but a lot less commonly discussed, known as a convolution.

**[0:34]**  But unlike the previous two cases, it's not something that's merely inherited from an

**[0:38]**  operation you can do to numbers. It's something genuinely new for the context of lists of numbers

**[0:43]**  or combining functions. They show up all over the place. They are ubiquitous in image processing.

**[0:49]**  It's a core construct in the theory of probability. They're used a lot in solving differential equations,

**[0:54]**  and one context where you've almost certainly seen it, if not by this name, is multiplying two

**[0:59]**  polynomials together. As someone in the business of visual explanations, this is an especially great

**[1:04]**  topic, because the formulaic definition, in isolation and without context, can look kind of

**[1:09]**  intimidating. But if we take the time to really unpack what it's saying, and before that, actually

**[1:14]**  motivate why you would want something like this, it's an incredibly beautiful operation. And I have to

**[1:19]**  admit, I actually learned a little something while putting together the visuals for this project. In

**[1:24]**  the case of convolving two different functions, I was trying to think of different ways you might

**[1:27]**  picture what that could mean. And with one of them, I had a little bit of an aha moment for why it is

**[1:32]**  that normal distributions play the role that they do in probability, why it's such a natural shape for

**[1:38]**  a function. But I'm getting ahead of myself. There's a lot of setup for that one. In this video,

**[1:42]**  our primary focus is just going to be on the discrete case, and in particular, building up to a very

**[1:47]**  unexpected but very clever algorithm for computing these. And I'll pull out the discussion for the

**[1:52]**  continuous case into a second part. It's very tempting to open up with the image processing

**[2:00]**  examples, since they're visually the most intriguing. But there are a couple bits of finickiness that make

**[2:05]**  the image processing case less representative of convolutions overall. So instead, let's kick things off

**[2:10]**  with probability. And in particular, one of the simplest examples that I'm sure everyone here has thought

**[2:15]**  about at some point in their life, which is rolling a pair of dice and figuring out the chances of seeing

**[2:20]**  various different sums. And you might say, not a problem, not a problem. Each of your two dice has

**[2:25]**  six different possible outcomes, which gives us a total of 36 distinct possible pairs of outcomes.

**[2:31]**  And if we just look through them all, we can count up how many pairs have a given sum.

**[2:36]**  And arranging all the pairs in a grid like this, one pretty nice thing is that all of the pairs that

**[2:41]**  have a constant sum are visible along one of these different diagonals. So simply counting how many

**[2:47]**  exist on each of those diagonals will tell you how likely you are to see a particular sum.

**[2:53]**  And I'd say, very good, very good. But can you think of any other ways that you might visualize

**[2:57]**  the same question? Other images that can come to mind to think of all the distinct pairs that have a

**[3:03]**  given sum? And maybe one of you raises your hand and says, yeah, I've got one. Let's say you picture

**[3:08]**  these two different sets of possibilities each in a row, but you flip around that second row.

**[3:14]**  That way, all of the different pairs which add up to seven line up vertically like this.

**[3:19]**  And if we slide that bottom row all the way to the right, then the unique pair that adds up to two,

**[3:23]**  the snake eyes, are the only ones that align. And if I slunk that over one unit to the right,

**[3:29]**  the pairs which align are the two different pairs that add up to three. And in general, different offset

**[3:34]**  values of this lower array, which remember I had to flip around first, reveal all the distinct pairs

**[3:40]**  that have a given sum. As far as probability questions go, this still isn't especially

**[3:48]**  interesting because all we're doing is counting how many outcomes there are in each of these categories.

**[3:53]**  But that is with the implicit assumption that there's an equal chance for each of these faces to

**[3:57]**  come up. But what if I told you I have a special set of dice that's not uniform? Maybe the blue

**[4:02]**  die has its own set of numbers describing the probabilities for each face coming up,

**[4:06]**  and the red die has its own unique distinct set of numbers. In that case, if you wanted to figure out,

**[4:11]**  say, the probability of seeing a two, you would multiply the probability that the blue die is a

**[4:16]**  one times the probability that the red die is a one. And for the chances of seeing a three,

**[4:22]**  you look at the two distinct pairs where that's possible, and again, multiply the corresponding

**[4:26]**  probabilities, and then add those two products together. Similarly, the chances of seeing a four

**[4:32]**  involves multiplying together three different pairs of possibilities and adding them all together.

**[4:37]**  And in the spirit of setting up some formulas, let's name these top probabilities a1, a2, a3,

**[4:42]**  and so on, and name the bottom ones b1, b2, b3, and so on. And in general, this process where we're

**[4:48]**  taking two different arrays of numbers, flipping the second one around, and then lining them up at

**[4:53]**  various different offset values, taking a bunch of pairwise products and adding them up, that's one of the

**[4:58]**  fundamental ways to think about what a convolution is. So just to spell it out a little more exactly,

**[5:07]**  through this process, we just generated probabilities for seeing two, three, four,

**[5:10]**  on and on up to 12. And we got them by mixing together one list of values a and another list of

**[5:16]**  values b. In the lingo, we'd say the convolution of those two sequences gives us this new sequence,

**[5:22]**  the new sequence of 11 values, each of which looks like some sum of pairwise products. If you prefer,

**[5:28]**  another way you could think about the same operation is to first create a table of all the

**[5:33]**  pairwise products, and then add up along all these diagonals. Again, that's a way of mixing together

**[5:39]**  these two sequences of numbers to get us a new sequence of 11 numbers. It's the same operation as

**[5:44]**  the sliding windows thought, just another perspective. Putting a little notation to it, here's how you

**[5:48]**  might see it written down. The convolution of a and b, denoted with this little asterisk, is a new list,

**[5:54]**  and the nth element of that list looks like a sum. And that sum goes over all different pairs

**[6:00]**  of indices, i and j, so that the sum of those indices is equal to n. It's kind of a mouthful,

**[6:06]**  but for example, if n was 6, the pairs we're going over are 1 and 5, 2 and 4, 3 and 3, 4 and 2,

**[6:13]**  5 and 1. All the different pairs that add up to 6. But honestly, however you write it down,

**[6:18]**  the notation is secondary in importance to the visual you might hold in your head for the process.

**[6:23]**  Here, maybe it helps to do a super simple example, where I might ask you what's the convolution of

**[6:28]**  the list 1, 2, 3 with the list 4, 5, 6. You might picture taking both of these lists, flipping around

**[6:34]**  that second one, and then starting with its slid all the way over to the left. Then the pair of values

**[6:38]**  which align are 1 and 4, multiply them together, and that gives us our first term of our output.

**[6:43]**  Slide that bottom array one unit to the right, the pairs which align are 1, 5 and 2 and 4,

**[6:49]**  multiply those pairs, add them together, and that gives us 13, the next entry in our output.

**[6:54]**  Slide things over once more, and we'll take 1 times 6 plus 2 times 5 plus 3 times 4,

**[6:59]**  which happens to be 28. One more slide, and we get 2 times 6 plus 3 times 5, and that gives us 27.

**[7:07]**  And finally, the last term will look like 3 times 6. If you'd like, you can pull up whatever your

**[7:12]**  favorite programming languages, and your favorite library that includes various numerical operations,

**[7:17]**  and you can confirm I'm not lying to you. If you take the convolution of 1, 2, 3 against 4, 5, 6,

**[7:22]**  this is indeed the result that you'll get. We've seen one case where this is a natural and desirable

**[7:28]**  operation, adding up to probability distributions, and another common example would be a moving average.

**[7:33]**  Imagine you have some long list of numbers, and you take another smaller list of numbers that all add up to

**[7:39]**  1. In this case, I just have a little list of five values, and they're all equal to 1 fifth.

**[7:44]**  Then if we do this sliding window convolution process, and kind of close our eyes and sweep

**[7:49]**  under the rug what happens at the very beginning of it, once our smaller list of values entirely

**[7:53]**  overlaps with the bigger one, think about what each term in this convolution really means.

**[7:59]**  At each iteration, what you're doing is multiplying each of the values from your data by 1 fifth,

**[8:04]**  and adding them all together. Which is to say, you're taking an average of your data inside this

**[8:09]**  little window. Overall, the process gives you a smoothed out version of the original data.

**[8:15]**  And you could modify this, starting with a different little list of numbers,

**[8:18]**  and as long as that little list all adds up to 1, you can still interpret it as a moving average.

**[8:23]**  In the example shown here, that moving average would be giving more weight towards the central value.

**[8:28]**  This also results in a smoothed out version of the data.

**[8:30]**  If you do kind of a two-dimensional analog of this, it gives you a fun algorithm for blurring a given

**[8:38]**  image. And I should say, the animations I'm about to show are modified from something I originally made

**[8:44]**  for part of a set of lectures I did with the Julia lab at MIT for a certain OpenCourseWare class that

**[8:49]**  included an image processing unit. There we did a little bit more to dive into the code behind all of

**[8:54]**  this, so if you're curious I'll leave you some links. But focusing back on this blurring example,

**[8:58]**  what's going on is I've got this little 3x3 grid of values that's marching along our original image,

**[9:04]**  and if we zoom in, each one of those values is 1 ninth, and what I'm doing at each iteration

**[9:09]**  is multiplying each of those values by the corresponding pixel that it sits on top of.

**[9:13]**  And of course in computer science we think of colors as little vectors of three values,

**[9:18]**  representing the red, green, and blue components. When I multiply all these little values by 1 ninth,

**[9:22]**  and I add them together, it gives us an average along each color channel, and the corresponding

**[9:27]**  pixel for the image on the right is defined to be that sum. The overall effect, as we do this for

**[9:33]**  every single pixel on the image, is that each one kind of bleeds into all of its neighbors, which gives

**[9:39]**  us a blurrier version than the original. In the lingo, we'd say that the image on the right is a

**[9:44]**  convolution of our original image with a little grid of values. Or more technically, maybe I should say

**[9:49]**  that it's the convolution with a 180 degree rotated version of that little grid of values.

**[9:54]**  Not that it matters when the grid is symmetric, but it's just worth keeping in mind that the

**[9:58]**  definition of a convolution, as inherited from the pure math context, should always invite you to

**[10:03]**  think about flipping around that second array. If we modify this slightly, we can get a much more

**[10:08]**  elegant blurring effect by choosing a different grid of values. In this case, I have a little 5x5 grid,

**[10:13]**  but the distinction is not so much its size. If we zoom in, we notice that the value in the middle is a

**[10:18]**  lot bigger than the value towards the edges. And where this is coming from is they're all sampled

**[10:23]**  from a bell curve, known as a Gaussian distribution. That way, when we multiply all of these values by

**[10:29]**  the corresponding pixel that they're sitting on top of, we're giving a lot more weight to that central

**[10:33]**  pixel, and much less towards the ones out at the edge. And just as before, the corresponding pixel on

**[10:38]**  the right is defined to be this sum. As we do this process for every single pixel, it gives a blurring effect

**[10:44]**  which much more authentically simulates the notion of putting your lens out of focus or something like

**[10:49]**  that. But blurring is far from the only thing that you can do with this idea. For instance, take a look

**[10:54]**  at this little grid of values, which involves some positive numbers on the left, and some negative

**[10:59]**  numbers on the right, which I'll color with blue and red respectively. Take a moment to see if you can

**[11:04]**  predict and understand what effect this will have on the final image.

**[11:08]**  So in this case, I'll just be thinking of the image as grayscale instead of colored. So each of

**[11:15]**  the pixels is just represented by one number instead of three. And one thing worth noticing is that as

**[11:19]**  we do this convolution, it's possible to get negative values. For example, at this point here,

**[11:24]**  if we zoom in, the left half of our little grid sits entirely on top of black pixels, which would have

**[11:29]**  a value of zero. But the right half of negative values all sit on top of white pixels, which would have

**[11:34]**  a value of one. So when we multiply corresponding terms and add them together, the result will be

**[11:40]**  very negative. And the way I'm displaying this with the image on the right is to color negative

**[11:44]**  values red and positive values blue. Another thing to notice is that when you're on a patch that's all

**[11:49]**  the same color, everything goes to zero, since the sum of the values in our little grid is zero.

**[11:55]**  This is very different from the previous two examples, where the sum of our little grid was one,

**[11:59]**  which let us interpret it as a moving average and hence a blur.

**[12:02]**  All in all, this little process basically detects wherever there's variation in the pixel value as

**[12:08]**  you move from left to right. And so it gives you a kind of way to pick up on all the vertical edges

**[12:13]**  from your image. And similarly, if we rotated that grid around so that it varies as you move from the

**[12:20]**  top to the bottom, this will be picking up on all the horizontal edges, which in the case of our little

**[12:26]**  pie creature image does result in some pretty demonic eyes. This smaller grid, by the way, is often

**[12:32]**  called a kernel. And the beauty here is how just by choosing a different kernel, you can get

**[12:36]**  different image processing effects, not just blurring your edge detection, but also things like

**[12:40]**  sharpening. For those of you who have heard of a convolutional neural network, the idea there is

**[12:44]**  to use data to figure out what the kernels should be in the first place, as determined by whatever the

**[12:49]**  neural network wants to detect. Another thing I should maybe bring up is the length of the output.

**[12:55]**  For something like the moving average example, you might only want to think about the terms when both of the

**[13:00]**  windows fully align with each other. Or in the image processing example, maybe you want the final

**[13:05]**  output to have the same size as the original. Now, convolutions as a pure math operation always

**[13:10]**  produce an array that's bigger than the two arrays that you started with, at least assuming one of

**[13:14]**  them doesn't have a length of one. Just know that in certain computer science contexts, you often want

**[13:19]**  to deliberately truncate that output. Another thing worth highlighting is that in the computer science

**[13:27]**  context, this notion of flipping around that kernel before you let it march across the original,

**[13:32]**  often feels really weird and just uncalled for. But again, note that that's what's inherited from

**[13:37]**  the pure math context, where like we saw with the probabilities, it's an incredibly natural thing to

**[13:42]**  do. And actually, I can show you one more pure math example where even the programmers should care

**[13:47]**  about this one, because it opens the doors for a much faster algorithm to compute all of these.

**[13:52]**  To set up what I mean by faster here, let me go back and pull up some Python again,

**[13:56]**  and I'm going to create two different relatively big arrays. Each one will have 100,000 random

**[14:01]**  elements in it, and I'm going to assess the runtime of the convolve function from the numpy library.

**[14:08]**  And in this case, it runs it for multiple different iterations, tries to find an average,

**[14:12]**  and it looks like, on this computer at least, it averages at 4.87 seconds. By contrast,

**[14:17]**  if I use a different function from the scipy library called fft-convolve, which is the same

**[14:23]**  thing just implemented differently, that only takes 4.3 milliseconds on average, so three orders

**[14:29]**  of magnitude improvement. And again, even though it flies under a different name, it's giving the same

**[14:33]**  output that the other convolve function does, it's just doing something to go about it in a cleverer way.

**[14:42]**  Remember how, with the probability example, I said another way you could think about the convolution was

**[14:47]**  to create this table of all the pairwise products, and then add up those pairwise products along the

**[14:52]**  diagonals. There's of course nothing specific to probability. Anytime you're convolving two different

**[14:57]**  lists of numbers, you can think about it this way. Create this kind of multiplication table with all

**[15:01]**  pairwise products, and then each sum along the diagonal corresponds to one of your final outputs.

**[15:07]**  One context where this view is especially natural is when you multiply together two polynomials.

**[15:13]**  For example, let me take the little grid we already have and replace the top terms with

**[15:17]**  1, 2x, and 3x squared, and replace the other terms with 4, 5x, and 6x squared. Now think about

**[15:24]**  what it means when we're creating all of these different pairwise products between the two lists.

**[15:29]**  What you're doing is essentially expanding out the full product of the two polynomials I have written

**[15:34]**  down. And then when you add up along the diagonal, that corresponds to collecting all like terms.

**[15:40]**  Which is pretty neat. Expanding a polynomial and collecting like terms is exactly the same process

**[15:45]**  as a convolution. But this allows us to do something that's pretty cool. Because think

**[15:51]**  about what we're saying here. We're saying if you take two different functions and you multiply them

**[15:56]**  together, which is a simple pointwise operation, that's the same thing as if you had first extracted

**[16:01]**  the coefficients from each one of those, assuming they're polynomials, and then taken a convolution

**[16:06]**  of those two lists of coefficients. What makes that so interesting is that convolutions feel in

**[16:12]**  principle a lot more complicated than simple multiplication. And I don't just mean conceptually

**[16:17]**  they're harder to think about. I mean computationally it requires more steps to perform a convolution

**[16:22]**  than it does to perform a pointwise product of two different lists. For example, let's say I gave

**[16:27]**  you two really big polynomials, say each one with a hundred different coefficients. Then if the way you

**[16:33]**  multiply them was to expand out this product, you know filling in this entire 100 by 100 grid of

**[16:39]**  pairwise products, that would require you to perform 10,000 different products. And then when you're

**[16:44]**  collecting all the like terms along the diagonals, that's another set of around 10,000 operations.

**[16:50]**  More generally in the lingo we'd say the algorithm is O of n squared, meaning for two lists of size n,

**[16:56]**  the way that the number of operations scales is in proportion to the square of n.

**[17:01]**  On the other hand, if I think of two polynomials in terms of their outputs, for example sampling

**[17:06]**  their values at some handful of inputs, then multiplying them only requires as many operations

**[17:12]**  as the number of samples, since again it's a pointwise operation. And with polynomials,

**[17:17]**  you only need finitely many samples to be able to recover the coefficients. For example, two outputs

**[17:22]**  are enough to uniquely specify a linear polynomial, three outputs would be enough to uniquely specify

**[17:27]**  a quadratic polynomial. And in general, if you know n distinct outputs, that's enough to uniquely

**[17:33]**  specify a polynomial that has n different coefficients. Or if you prefer we could phrase

**[17:38]**  this in the language of systems of equations. Imagine I tell you I have some polynomial,

**[17:43]**  but I don't tell you what the coefficients are. Those are a mystery to you. In our example you might

**[17:47]**  think of this as the product that we're trying to figure out. And then suppose I say I'll just tell

**[17:52]**  you what the outputs of this polynomial would be if you inputted various different inputs like 0,

**[17:57]**  1, 2, 3, on and on. And I give you enough so that you have as many equations as you have unknowns.

**[18:04]**  It even happens to be a linear system of equations, so that's nice. And in principle, at least,

**[18:09]**  this should be enough to recover the coefficients. So the rough algorithm outline then would be whenever

**[18:14]**  you want to convolve two lists of numbers, you treat them like they're coefficients of two

**[18:18]**  polynomials, you sample those polynomials at enough outputs, multiply those samples point-wise,

**[18:25]**  and then solve this system to recover the coefficients as a sneaky backdoor way to find

**[18:29]**  the convolution. And as I've stated it so far at least, some of you could rightfully complain,

**[18:35]**  Grant, that is an idiotic plan. Because for one thing, just calculating all these samples for one of

**[18:40]**  the polynomials we know already takes on the order of n squared operations. Not to mention, solving that

**[18:46]**  system is certainly going to be computationally as difficult as just doing the convolution in the

**[18:51]**  first place. So like, sure, we have this connection between multiplication and convolutions, but all

**[18:57]**  of the complexity happens in translating from one viewpoint to the other. But there is a trick,

**[19:03]**  and those of you who know about Fourier transforms and the FFT algorithm might see where this is going.

**[19:08]**  If you're unfamiliar with those topics, what I'm about to say might seem completely out of the blue.

**[19:12]**  Just know that there are certain paths you could have walked in math that make this more of an

**[19:16]**  expected step. Basically the idea is that we have a freedom of choice here. If instead of evaluating

**[19:21]**  at some arbitrary set of inputs, like 0, 1, 2, 3, on and on, you choose to evaluate on a very

**[19:27]**  specially selected set of complex numbers, specifically the ones that sit evenly spaced on the unit circle,

**[19:33]**  what are known as the roots of unity, this gives us a friendlier system. The basic idea is that by

**[19:39]**  finding a number where taking its powers falls into this cycling pattern, it means that the system we

**[19:45]**  generate is going to have a lot of redundancy in the different terms that you're calculating,

**[19:49]**  and by being clever about how you leverage that redundancy, you can save yourself a lot of work.

**[19:56]**  This set of outputs that I've written has a special name, it's called the discrete

**[19:59]**  Fourier transform of the coefficients, and if you want to learn more, I actually did another lecture

**[20:05]**  for that same Julia MIT class all about discrete Fourier transforms, and there's also a really excellent

**[20:10]**  video on the channel Reducible talking about the fast Fourier transform, which is an algorithm for

**[20:15]**  computing these more quickly. Also Veritasium recently did a really good video on FFTs, so you've

**[20:20]**  got lots of options. And that fast algorithm really is the point for us. Again, because of all this

**[20:26]**  redundancy, there exists a method to go from the coefficients to all of these outputs, where instead

**[20:31]**  of doing on the order of n squared operations, you do on the order of n times the log of n operations,

**[20:36]**  which is much, much better as you scale to big lists. And importantly, this FFT algorithm goes

**[20:42]**  both ways. It also lets you go from the outputs to the coefficients. So bringing it all together,

**[20:47]**  let's look back at our algorithm outline. Now we can say whenever you're given two long lists of

**[20:52]**  numbers and you want to take their convolution, first compute the fast Fourier transform of each one

**[20:57]**  of them, which in the back of your mind you can just think of as treating them like they're the

**[21:01]**  coefficients of a polynomial and evaluating it at a very specially selected set of points.

**[21:06]**  Then multiply together the two results that you just got point-wise, which is nice and fast,

**[21:11]**  and then do an inverse fast Fourier transform. And what that gives you is the sneaky backdoor way

**[21:16]**  to compute the convolution that we were looking for. But this time it only involves O of n log n

**[21:21]**  operations. That's really cool to me. This very specific context where convolutions show up,

**[21:27]**  multiplying two polynomials, opens the doors for an algorithm that's relevant everywhere else where

**[21:32]**  convolutions might come up. If you want to add probability distributions, do some large image

**[21:37]**  processing, whatever it might be. And I just think that's such a good example of why you should be

**[21:41]**  excited when you see some operation or concept in math show up in a lot of seemingly unrelated areas.

**[21:48]**  If you want a little homework, here's something that's fun to think about. Explain why when you

**[21:52]**  multiply two different numbers, just ordinary multiplication the way we all learn in elementary

**[21:57]**  school. What you're doing is basically a convolution between the digits of those numbers.

**[22:02]**  There's some added steps with carries and the like, but the core step is a convolution.

**[22:07]**  In light of the existence of a fast algorithm, what that means is if you have two very large

**[22:12]**  integers, then there exists a way to find their product that's faster than the method we learn

**[22:16]**  in elementary school. That instead of requiring O of n squared operations, only requires O of n log n,

**[22:22]**  which doesn't even feel like it should be possible. The catch is that before this is actually useful

**[22:27]**  in practice, your numbers would have to be absolutely monstrous. But still, it's cool that such an

**[22:32]**  algorithm exists. And next up, we'll turn our attention to the continuous case, with a special

**[22:38]**  focus on probability distributions.
