숫자 범위를 다른 범위로 매핑
수학은 학교 다닐 때 내 강점이 아니었다.
int input_start = 0; // The lowest number of the range input.
int input_end = 254; // The largest 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 output.
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 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;
}
공식은
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
이 투고는 여기에 접속하겠습니다.https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/은 직관적으로 생각해 낼 때 큰 도움이 되었습니다.게시물이 무엇을 말하고 있는지 이해한 후, 이러한 공식들을 스스로 생각해 내는 것은 사소한 일이다.저도 그런 질문으로 고민하고 있었습니다.(소속관계는 없고 매우 유용하다고 느꼈을 뿐입니다)
범위가 있다고 합니다.[input_start..input_end]우선 0이 0이 되도록 정규화해 봅시다.input_start, 및은 , '1'입니다input_end이것은 문제를 쉽게 하기 위한 간단한 기술입니다.
가 "입력 x"가 될 양만큼 나머지 우리는 입력 x가 우연히 입력 x에 영향을 줄 수 있도록 input_start 양만큼 남은 모든 것을 이동시켜야 합니다.input_start0으로 하다
그럼 이렇게 해 볼까요?f(x)이치노
f(x) = x - input_start
시험해 봅시다.
f(input_start) = input_start - input_start = 0
works에서 input_start.
가 없다input_end아직 규모를 조정하지 않았기 때문에
범위 길이로 축소하면 최대값(input_end)이 1에 매핑됩니다.
f(x) = (x - input_start) / (input_end - input_start)
요?input_end.
f(input_end) = (input_end - input_start) / (input_end - input_start) = 1
효과가 있는 것 같네요
다음 단계에서는 출력 범위까지 크기를 조정합니다.이는 출력 범위의 실제 길이에 곱하는 것만큼 단순합니다.
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)
이제 거의 완료되었으므로 0이 output_start에서 시작되도록 오른쪽으로 이동하면 됩니다.
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
한 번 해보죠.
f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
방정식의 첫 번째 부분은 거의 0을 곱한 것입니다. 따라서 모든 것을 소거하고, 여러분에게
f(input_start) = output_start
해 보자input_end뿐만 아니라.
f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
결과적으로 다음과 같은 결과가 됩니다.
f(input_end) = output_end - output_start + output_start = output_end
보시는 바와 같이 이제 지도는 제대로 된 것 같습니다.
이것은 모든 범위를 모든 범위에 매핑하는 것을 보증합니다.
나는 이 방법을 썼는데, 이것은 한 범위의 숫자를 다른 것으로 매핑하는 대수 공식을 정확히 따랐다.계산은 정밀도를 유지하기 위해 2배로 수행되며, 마지막에는 메서드 인수에 소수 자릿수를 지정하더라도 Double을 반환합니다.
기능은 다음과 같이 동작합니다.범위 A와 B의 끝에 라벨을 붙였습니다.이것은 범위를 낮게 시작하여 높게 끝낼 필요가 없기 때문입니다.첫 번째 범위는 300 ~-7000, 두 번째 범위는 -3500 ~ 5500으로 설정할 수 있습니다.범위에 대해 선택한 숫자에 차이가 없습니다.이 값은 올바르게 매핑됩니다.
mapOneRangeToAnother(myNumber, fromRangeA, fromRangeB, toRangeA, toRangeB, decimalPrecision)
다음은 이 기능을 사용하는 간단한 예입니다.
범위: ~ ( - 400 ~800 )
범위: ~ 신 10000 : 10000 ~3500
: 250
double sourceA = -400;
double sourceB = 800;
double destA = 10000;
double destB = 3500;
double myNum = 250;
double newNum = mapOneRangeToAnother(myNum,sourceA,sourceB,destA,destB,2);
Result: 6479.17
또한 정수가 필요한 경우 소수점 0자리 결과를 반환하고 다음과 같이 결과를 int에 캐스트하도록 지시합니다.
int myResult = (int) mapOneRangeToAnother(myNumber, 500, 200, -350, -125, 0);
또는 함수를 선언하여 int를 반환하고 마지막 행을 return(더블)에서 return(int)으로 변경할 수도 있습니다.
OPs ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」
int myResult = (int) mapOneRangeToAnother(input, input_start, input_end, output_start, output_end, 0);
기능은 다음과 같습니다.
public static double mapOneRangeToAnother(double sourceNumber, double fromA, double fromB, double toA, double toB, int decimalPrecision ) {
double deltaA = fromB - fromA;
double deltaB = toB - toA;
double scale = deltaB / deltaA;
double negA = -1 * fromA;
double offset = (negA * scale) + toA;
double finalNumber = (sourceNumber * scale) + offset;
int calcScale = (int) Math.pow(10, decimalPrecision);
return (double) Math.round(finalNumber * calcScale) / calcScale;
}
이 기능은 카운터에서 페이드아웃을 하기 위해서도 사용하고 있습니다만, 불투명도는 0에서 1까지의 값이기 때문에 카운터를 0에서 100까지의 값으로 설정하고, 0에서 100까지의 범위를 매핑하면, 0에서 100까지의 수치를 기본으로 0에서 1까지의 모든 분수를 취득합니다.이런 함수를 사용하면 메인 코드가 더 보기 좋기 때문에 실제 계산을 바로 하는 것보다 더 깔끔한 방법입니다.
주행거리가 다를 수 있습니다.즐기세요! :-)
여기서 중요한 것은 정수 나눗셈(반올림 포함)을 올바른 위치에서 수행하는 것입니다.지금까지 괄호 안에 맞는 답은 하나도 없었다.올바른 방법은 다음과 같습니다.
int input_range = input_end - input_start;
int output_range = output_end - output_start;
output = (input - input_start)*output_range / input_range + output_start;
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start
그러면 입력 범위가 비례적으로 "얼마나 먼"지 알 수 있습니다.그런 다음 이 비율을 출력 범위의 크기에 적용하여 출력이 출력 범위에 얼마나 있어야 하는지 절대적인 관점에서 확인합니다.그런 다음 출력 범위의 시작을 추가하여 실제 출력 번호를 가져옵니다.
언급URL : https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another
'programing' 카테고리의 다른 글
| 플레인 JavaScript로 div 높이 가져오기 (0) | 2022.12.20 |
|---|---|
| Runtime Error: 응용 프로그램 컨텍스트 외부에서 작업 (0) | 2022.12.20 |
| JavaScript에서 여러 변수 선언 (0) | 2022.12.20 |
| python 목록에는 pop()이 있지만 push()는 없는 이유는 무엇입니까? (0) | 2022.12.20 |
| Vuejs는 변경을 검출하여 사용자 개입 없이 페이지를 갱신합니다. (0) | 2022.12.20 |