Sure, this notation can look weird
for(int x = -10; x <= 10; x = x + 5) {
...
}
but it’s not unheard of
I would only change x = x + 5
to x += 5
because it does make it easier to read.
Another way to do this is perhaps by doing a while
loop
int x = -10;
while(x <= 10) {
…
x += 5;
}
Or do
loop
int x = -10;
do {
...
x += 5;
} while(x <= 10);
All of these will have the same number of iterations, where x =
-10, -5, 0, 5, 10
Now depending on what you’re trying to achieve, it might be smarter to start off from the premise of having a known count of iterations. This changes the code into counter/transformation recipe, where you can keep your counter fairly simple to read.
for(int i = 0; i < 5; i++) {
int x = 5 * i - 10; // -10, -5, 0, 5, 10
}
It becomes a little more problematic if you don’t know the count of iterations in advance. In that case:
int start = -10;
int end = 10;
int step = 5;
int count = (end - start) / step + 1;
for(int i = 0; i < count; i++) {
int x = start + step * i; // -10, -5, 0, 5, 10
}
But let me show you another trick to help you untangle from these things altogether.
What you’re doing here is simply a uniform spread of points along some line.
So the transformation shown above is known as a linear transformation.
This means you can easily apply linear interpolation (aka the lerp), and in fact an advanced form of it, known as linear remapping.
Here’s what linear interpolation does: Given some start and end, compute any point in between using some measure of weight between them, think of it as a percentage. This, in general, works the best with floating points, but it can be adjusted to work with the integers as well. It’s for the best to apply this kind of integer rounding right at the end, however.
static float lerp(float a, float b, float t) => a * (1f - t) + b * t;
Where t is known as the interpolant. Now you can do
var start = -10f;
var end = 10f;
var step = 1f / 4f;
for(float t = 0f; t <= 1f; t += step) {
int x = (int)MathF.Floor(lerp(start, end, t)); // -10, -5, 0, 5, 10
}
But here’s what linear remapping is all about.
First you do an inverse of the lerp, where you pass in the actual value, and get back the interpolant t.
static float invLerp(float a, float b, float v) => (v - a) / (b - a);
This can backfire when a and b are the same value, so I like to do this to define the infinitesimal range between them
static float invLerp(float a, float b, float b) => substNaN((v - a) / (b - a), 1f);
static float substNaN(float n, float s) => float.IsNaN(n)? s : n;
Now you can define remapping as
static public float remap(float i1, float i2, float o1, float o2, float v)
=> lerp(o1, o2, invLerp(i1, i2, v));
Which doesn’t look terribly complicated in itself right?
Now you have a universal linear transformator that can easily transform a value from one line to another.
If there is a linear relationship between the two, this is as simple as
var x = remap(minPower, maxPower, maxFrequency, minFrequency, someGuy);
Notice that the frequency min and max are swapped, meaning that if someGuy is closer to minPower, the outcome will be closer to maxFrequency.
And if the relationship isn’t linear, at least make sure you get the interpolant first.
var t = invLerp(minPower, maxPower, someGuy);
And then make an AnimationCurve as suggested by Kurt-Dekker, to which you can plug your t
var frequency = myCurve.Evaluate(t);
I don’t know if you can see what I see, but you should be free from the perils of living among the filthy numbers, as if they carry meanings by themselves.