Exponentially-spaced integers
2020-05-05It's often useful to have exponentially-spaced integers, so that they are evenly distributed when plotted on a logarithmic scale. The simplest way to generate them is to exponentiate linearly-spaced numbers and then round:
1 2 3 | julia> round.(Int, exp.(0:7))'
1×8 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}:
1 3 7 20 55 148 403 1097
|
Past the first decade, which is significantly rounded, these integers are perfectly spaced: However, they're not very familiar to most people, and it's possible for the rounding step to produce duplicates, making them potentially tricky to generate. If you're willing to sacrifice the spacing a little more, I want to show you why integers of the form can be a very convenient alternative.
Powers of two
Some of the nicest exponentially-spaced integers around are the powers of two, which are trivial to generate and easily recognizable: Such elegance!
Filling in the gaps
If is sufficient for your purposes, I'm not sure why you're even here. But what if the spacing is a bit too large? The jump from to is quite a big one, and could be beyond your capabilities. Maybe you're looking for something more in line with your budget.
Logarithmically speaking, the closest integer to the halfway point between and is , but there's a good chance that I had never encountered this number in my entire life until I computed it for this purpose. I don't know anything about it. How can I trust it?
No, that won't do. Instead, we'll cheat a little bit and use . That really takes me back! What a nice, dependable integer. It turns out that since is the average of and . Thus, in addition to the powers of two, we can also use powers of two multiplied by three: A clean source of unlimited numbers!
Less flippantly, integers with large prime factors, like , are unfavourable for some algorithms. For example, certain FFT algorithms fare better on arrays whose sizes have small prime factors. Thus, there are applications for which it's better to use numbers purposely constructed from small factors.
Let's visualize the amount of imperfection in the layout of these additional numbers. If we draw two octaves (say, from to , although the actual values don't matter), we get three powers of two (, , ): In linear space (filled), the distances between them are uneven (one is twice the other), but in log space (hollow), they are properly spaced. If we add in the fillers and , we see that they are nicely located in the middle of each octave when viewed linearly, but are slightly off-kilter logarithmically: This is the price to be paid for having such pleasant numbers to work with.
Ad nauseam
There's no reason to stop there, of course. In addition to dividing the interval from to into two segments using , we could split each of those further with and , making a total of four segments. The first of these fractions gives us whose inclusion looks like The second one results in and completes this round of filling:
Using with , we have obtained integers that are locally spaced linearly, and are therefore convenient to handle, but are globally spaced logarithmically, and therefore span many orders of magnitude. Naturally, the next round would be based on , , , and , yielding for a total of eight values per octave, but it's usually not necessary to go that far.
Jumping ahead
Before I leave you alone to ponder the usefulness of this approach, I'd like to point out one practical consideration. If you're interested in exponentially-growing quantities, it can be detrimental to have all sorts of small values running around underfoot. For example, using and starting at , we get which are consecutive even integers. We didn't do all that work just to end up generating even numbers!
To remedy this, you can stagger the start of each sequence. For example, if the gap between and is sufficiently small, but grows too large after that point, the sequence can be started at instead of . Then, if and and are close enough, the and sequences can be started at and , respectively, instead of and . The staggered start allows us to tidy this (on a linear scale): into this: Much better! The improved variant starts out linear for the first few octaves, but automatically switches to exponential spacing beyond that.