Very often we have a scale of values that can be generalized and described as a real number within the range of 0 and 1, 0 being the lowest value and 1 being the highest. For example if we are building an airplane with highest possible altitude of 5 miles we can represent the current altitude with a number from 0 to 1, in this case 0 will represent the plane on the ground and 1 on it’s highest altitude of 5 miles. This may be useful in many different situations, for example if you show this value to a person or instrument that is not familiar with the specific value but can understand the idea of minimum and maximum of this value. Another useful scenario would be in you want to represent this value in a diagram, arranging it from 0 to 1 makes it easy to plot on a surface of any size.
Now we can imagine a situation when we will need to be more sensitive for the value changes near the minimum. For example if we go back to our airplane example. When a plane is taking off very little modification of the altitude may be very important simply because we have more buildings, towers and hills near the ground. But once a highest altitude is reached, 50 feet higher or lower may not be of such a big importance. In this case we may want to plot the altitude of a plane in such a way to make changes near the minimum of 0 more noticeable than changes near the maximum, and of course the transition between those two should be gradual.
Now we can think of four general transformations that we can use to alter our 0 to 1 scale.
- Make changes near the maximum more noticeable.
- Make changes near the minimum more noticeable.
- Make changes at both extremes more noticeable.
- Make changes at the middle more noticeable.
Now let’s see how do we expect the graphs of those transformations to look:
Now we have to come up with a function that describes each of these for equations.
- The first one is quite easy as it is quite obviously the part of the parabola between the values of 0 and 1, so the first equation is y = x^2
- The second looks like the same parabola but up side down and moved one point to the right and one to the top. To flip the parabola we can multiply it by negative one like this
y = (x^2)*-1. To move it up one point we simply add one or y = (x^2)*-1 + 1 and of course the same can be written as just y = 1 - (x^2). To move it one point to the right we subtract 1 from x before taking the power, or the final formula will be y = 1 – (x – 1)^2
- The third gets a little bit more complicated. It looks like x raised to the third power but a little bit squeezed and moved to the right and up. So we start with y = x ^ 3. Now we have to move it up 0.5 points to get the bending point just between 0 and 1. That looks simple y = x ^ 3 + 0.5. And we do the same just before taking the power in order to move it right, or y = (x – 0.5) ^ 3 + 0.5. To squeeze the graph we have to multiply x ^ 3 by some constant value, let’s call it C, or y = C ((x – 0.5) ^ 3 + 0.5). We don’t know that value but we know that if x is 1 and y is 1, that value should satisfy the equation, so we deduce this
1 = C (1 – 0.5) ^ 3 + 0.5
1 – 0.5 = C (1 – 0.5) ^ 3
0.5 = C (1 – 0.5) ^ 3
C = 0.5 / (0.5 ^ 3)
C = 0.5 / 0.125
C = 4
So at the end our formula is y = 4(x - 0.5) ^ 3 + 0.5
- The fourth graph looks like a reflection of a third graph around the diagonal line y = x. So we have to swap the x and y, or
x = 4(y – 0.5)^3 + 0.5
(x – 0.5) / 4 = (y – 0.5)^3
((x – 0.5) / 4 ) ^ (1/3) = y – 0.5
y = ((x – 0.5) / 4 ) ^ (1/3) + 0.5
That technically could be our solution but the problem is that the values of x between 0 and 0.5 will produce negative number and event though cubic root of a negative number shouldn’t be a problem, the windows function for taking a power returns not a number value for any negative number. So to get around this we have to modify our equation as
y = sign(x – 0.5)(abs(x – 0.5) / 4 ) ^ (1/3) + 0.5 where sign is a function that returns –1 if the number is negative 0 if it’s 0 and 1 if the number is positive. And here are our graphs with the corresponding equations.
Now let’s write those equations in C#
public static double ShiftNearZero(double x){
if(x < 0 || x > 1) throw new ArgumentException("X must be between 0 and 1");
return Math.Pow(x, 2);
}
public static double ShiftNearOne(double x){
if(x < 0 || x > 1) throw new ArgumentException("X must be between 0 and 1");
return 1 - Math.Pow(x - 1, 2);
}
public static double ShiftBetweenZeroAndOne(double x){
if(x < 0 || x > 1) throw new ArgumentException("X must be between 0 and 1");
return 4 * Math.Pow(x – 0.5, 3) + 0.5;
}
public static double ShiftNearZeroAndOne(double x){
if(x < 0 || x > 1) throw new ArgumentException("X must be between 0 and 1");
return Math.Sign(x – 0.5) * Math.Pow(Math.Abs(x – 0.5)/4D, 1/3D) + 0.5;
}
Another thing we may want to consider is if we want to make those four diagrams even more extreme. Let’s look at the four cases:
- y = x^N, where N is any even integer
higher than 2, for example y = x ^ 4
- y = (1-(x-1)^N), where N is any even integer
higher than 2, for example y = (1-(x-1) ^ 6)
- y = C(x-0.5)^N+0.5, where N is any odd integer higher than 3,
and C is a constant that will squeeze the graph to make it pass through 0,0 and 1,1.
We can calculate this constant by replacing y and x with 1, as the graph should pass
through point 1,1
1 = C(1-0.5)^N+0.5
1 – 0.5 = C 0.5 ^ N
C = 0.5 / 0.5 ^ N
So our final formula will be
y = (0.5 / 0.5 ^ N)(x-0.5)^N+0.5, where N is any odd integer higher than 3 for example
y = (0.5 / 0.5 ^ 5)(x-0.5)^5+0.5
- The fourth graph would look like
y = sign(x – 0.5)(abs(x – 0.5) / C ) ^ (1/3) + 0.5
and when we replace C (we use the same C because this graph is reflection of the previous one)
we will end up with
y = sign(x – 0.5)(abs((x-0.5)/(0.5/0.5^N))^(1/N))+0.5, for example
y = sign(x – 0.5)(abs((x-0.5)/(0.5/0.5^7))^(1/7))+0.5
If on the other hand you need to change the curvature gradually
I can recommend another formula. Here it is:
In C# that would look like:
private static double Transform(double value, double curveture)
{
return (Math.Pow(value, curveture) + (1 - Math.Pow(1 - value, 1/curveture)))/2;
}
The value or X is the value of your coefficient that you want to transform.
The curvature or N is the value that will determine the direction and degree of
the curvature. N must be between 0 and positive infinity. If it is less than 0
the values of X will be shifted closer to 1 of Y. If N is 1 the line will be just
a diagonal line, so X will equal Y. If N is more than 1 the values of X will be
shifted closer to 0 of Y. Here is an example of that: