숫자 범위를 다른 범위에 매핑
수학은 학교에서 내 강한 옷이 아니었다.
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;
입력 값을 해당 범위의 해당 출력 값으로 어떻게 변환 할 수 있습니까?
예를 들어 입력 값 "0"은 출력 값 "500"과 같고 입력 값 "254"는 출력 값 "5500"과 같습니다. 입력 값이 50 또는 101이면 출력 값을 계산하는 방법을 알 수 없습니다.
나는 그것이 간단하다고 확신합니다. 지금은 생각할 수 없습니다. :)
편집 : 정수, 분수 또는 아무것도 필요하지 않습니다.
수학을 잊고 직관적으로 해결해 봅시다.
첫째, [ 0
, x
] 범위의 입력 숫자 를 출력 범위 [ 0
, y
] 에 매핑 하려면 적절한 양으로 크기를 조정하면됩니다. 0은 0, x
은 y
, 숫자 t
는 (y/x)*t
.
따라서 위의 간단한 문제로 문제를 줄여 보겠습니다.
입력 범위 [ input_start
, input_end
]에는 input_end - input_start + 1
숫자 가 있습니다. 따라서 [ 0
, r
] 의 범위와 동일합니다 r = input_end - input_start
. 여기서 .
마찬가지로 출력 범위는 [ 0
, R
] 와 같습니다 R = output_end - output_start
. 여기서 .
의 입력은 input
동일하다 x = input - input_start
. 이것은 첫 번째 단락에서 y = (R/r)*x
. 그런 다음, 우리는 번역 할 수 있습니다 y
추가하여 원래의 출력 범위에 값 다시 output_start
: output = output_start + y
.
이것은 우리에게 제공합니다 :
output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start)
또는 다른 방법 :
/* Note, "slope" below is a constant for given numbers, so if you are calculating
a lot of output values, it makes sense to calculate it once. It also makes
understanding the code easier */
slope = (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)
이제 이것은 C이고 C의 나눗셈이 잘립니다. 부동 소수점으로 계산하여 더 정확한 답을 얻으려고 노력해야합니다.
double slope = 1.0 * (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)
더 정확하고 싶다면 마지막 단계에서 잘림 대신 반올림을 수행합니다. 간단한 round
함수 를 작성하면 됩니다.
#include <math.h>
double round(double d)
{
return floor(d + 0.5);
}
그때:
output = output_start + round(slope * (input - input_start))
Arduino에는이 기능이 map으로 내장되어 있습니다 .
예:
/* Map an analog value to 8 bits (0 to 255) */
void setup() {}
void loop()
{
int val = analogRead(0);
val = map(val, 0, 1023, 0, 255);
analogWrite(9, val);
}
또한 해당 페이지에 구현이 있습니다.
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
여기서 중요한 점은 올바른 위치에서 정수 나누기 (반올림 포함)를 수행하는 것입니다. 지금까지 괄호가 맞지 않은 답변이 없습니다. 올바른 방법은 다음과 같습니다.
int input_range = input_end - input_start;
int output_range = output_end - output_start;
output = (input - input_start)*output_range / input_range + output_start;
공식은
f (x) = (x-입력 _ 시작) / (입력 _ 종료-입력 _ 시작) * (출력 _ 종료-출력 _ 시작) + 출력 _ 시작
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 is input_start
, and 1 is input_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.
f(x) = x - input_start
let's try it:
f(input_start) = input_start - input_start = 0
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.
f(x) = (x - input_start) / (input_end - input_start)
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:
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)
now, actually, we're almost done, we just have to shift it to right so that 0 starts from output_start.
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
let's give it a quick try.
f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
you see that the first part of equation is pretty much multiplied by zero, thus cancelling everything out, giving you
f(input_start) = output_start
let's try input_end
as well.
f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
which in turn will end up as:
f(input_end) = output_end - output_start + output_start = output_end
as you can see, it now seems to be mapped correctly.
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start
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.
ReferenceURL : https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another
'IT TIP' 카테고리의 다른 글
nullable 형식을 비교하는 방법은 무엇입니까? (0) | 2021.01.05 |
---|---|
Xcode, 중복 기호 _main (0) | 2021.01.05 |
일시적으로 stdout / stderr 리디렉션 (0) | 2021.01.05 |
왜 벡터 (0) | 2021.01.05 |
numpy의 반복되지 않는 난수 (0) | 2021.01.05 |