Math was never my strong suit in school :(
int input_start = 0; // The lowest number of the range input.
int input_end = 254; // The lowest number of the range input.
int output_start = 500; // The lowest number of the range output.
int output_end = 5500; // The largest number of the range ouput.
int input = 127; // Input value.
int output = 0;
How can I convert the input value to the corresponding output value of that range?
For example, an input value of "0" would equal an output value of "500", an input value of "254" would equal an output value of "5500". I can't figure out how to calculate an output value if an input value is say 50 or 101.
I'm sure it's simple, I can't think right now :)
Edit: I just need whole numbers, no fractions or anything.
The crucial point here is to do the integer division (which includes rounding) at the right place. None of the answers so far got the parentheses right. Here is the right way:
Arduino has this built-in as map.
Example:
It also has the implementation on that page:
What that does is find out proportionally "how far into" the input range the input is. It then applies that proportion to the size of the output range to find out in absolute terms how far into the output range the output should be. It then adds the start of the output range to get the actual output number.
the formula is
I'll hook up this post here: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/ as it helped me a lot when trying to come up with this intuitively. Once you understand what the post is saying, it's trivial to come up with these formulas on your own. Note that I used to struggle with such questions as well. (I have no affiliations - just found it very useful)
say you have range
[input_start..input_end]
, let's start by normalising it such that 0 isinput_start
, and 1 isinput_end
. this is simple technique to make the problem easier.how do we do that? we'll, we'd have to shift everything left by input_start amount, such that if input x happens to be
input_start
, it should give zero.so, let's say
f(x)
is the function that does the conversion.let's try it:
works for
input_start
.at this point, it does not work for
input_end
yet, as we have not scaled it.let's just scale it down by the length of the range, then we'll have the biggest value (input_end) mapped to one.
ok, let's give it a try with
input_end
.f
(input_end) = (input_end - input_start) / (input_end - input_start) = 1
awesome, seems to work.
okay, next step, we'll actually scale it to output range. It is as trivial as just multiplying with the actual length of the output range, as such:
now, actually, we're almost done, we just have to shift it to right so that 0 starts from output_start.
let's give it a quick try.
you see that the first part of equation is pretty much multiplied by zero, thus cancelling everything out, giving you
let's try
input_end
as well.which in turn will end up as:
as you can see, it now seems to be mapped correctly.
Let's forget the math and try to solve this intuitively.
First, if we want to map input numbers in the range [
0
,x
] to output range [0
,y
], we just need to scale by an appropriate amount. 0 goes to 0,x
goes toy
, and a numbert
will go to(y/x)*t
.So, let's reduce your problem to the above simpler problem.
An input range of [
input_start
,input_end
] hasinput_end - input_start + 1
numbers. So it's equivalent to a range of [0
,r
], wherer = input_end - input_start
.Similarly, the output range is equivalent to [
0
,R
], whereR = output_end - output_start
.An input of
input
is equivalent tox = input - input_start
. This, from the first paragraph will translate toy = (R/r)*x
. Then, we can translate they
value back to the original output range by addingoutput_start
:output = output_start + y
.This gives us:
Or, another way:
Now, this being C, and division in C truncates, you should try to get a more accurate answer by calculating things in floating-point:
If wanted to be even more correct, you would do a rounding instead of truncation in the final step. You can do this by writing a simple
round
function:Then: