비율을 유지하면서 한 숫자 범위를 다른 숫자 범위로 변환하려고합니다. 수학은 나의 장점이 아닙니다.
포인트 범위는 -16000.00 ~ 16000.00 범위의 이미지 파일이 있지만 일반적인 범위는 훨씬 적습니다. 내가하고 싶은 것은이 값을 0-100의 정수 범위로 압축하는 것입니다. 여기서 0은 가장 작은 점의 값이고 100은 가장 큰 값입니다. 사이의 모든 점은 일부 정밀도가 손실 되더라도 상대적인 비율을 유지해야합니다. 파이썬에서는이 작업을 수행하고 싶지만 일반 알고리즘조차 충분합니다. 최소 / 최대 또는 두 범위 중 하나를 조정할 수있는 알고리즘을 선호합니다 (즉, 두 번째 범위는 0 ~ 100 대신 -50 ~ 800 일 수 있음).
답변
NewValue = (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
또는 좀 더 읽기 쉽습니다.
OldRange = (OldMax - OldMin)
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
또는 이전 범위가 0 인 경우 ( OldMin = OldMax ) 를 보호하려는 경우 :
OldRange = (OldMax - OldMin)
if (OldRange == 0)
NewValue = NewMin
else
{
NewRange = (NewMax - NewMin)
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin
}
이 경우 가능한 새로운 범위 값 중 하나를 임의로 선택해야합니다. 상황에 따라 합리적인 선택이 될 수있다 : NewMin
( 샘플 참조 ), NewMax
또는(NewMin + NewMax) / 2
답변
그것은 간단한 선형 변환입니다.
new_value = ( (old_value - old_min) / (old_max - old_min) ) * (new_max - new_min) + new_min
따라서 -16000에서 16000까지의 스케일에서 10000을 0에서 100까지의 새로운 스케일로 변환하면 다음과 같습니다.
old_value = 10000
old_min = -16000
old_max = 16000
new_min = 0
new_max = 100
new_value = ( ( 10000 - -16000 ) / (16000 - -16000) ) * (100 - 0) + 0
= 81.25
답변
실제로 위의 답변이 깨지는 경우가 있습니다. 잘못된 입력 값, 잘못된 입력 범위, 부정적인 입력 / 출력 범위와 같은.
def remap( x, oMin, oMax, nMin, nMax ):
#range check
if oMin == oMax:
print "Warning: Zero input range"
return None
if nMin == nMax:
print "Warning: Zero output range"
return None
#check reversed input range
reverseInput = False
oldMin = min( oMin, oMax )
oldMax = max( oMin, oMax )
if not oldMin == oMin:
reverseInput = True
#check reversed output range
reverseOutput = False
newMin = min( nMin, nMax )
newMax = max( nMin, nMax )
if not newMin == nMin :
reverseOutput = True
portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
if reverseInput:
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin)
result = portion + newMin
if reverseOutput:
result = newMax - portion
return result
#test cases
print remap( 25.0, 0.0, 100.0, 1.0, -1.0 ), "==", 0.5
print remap( 25.0, 100.0, -100.0, -1.0, 1.0 ), "==", -0.25
print remap( -125.0, -100.0, -200.0, 1.0, -1.0 ), "==", 0.5
print remap( -125.0, -200.0, -100.0, -1.0, 1.0 ), "==", 0.5
#even when value is out of bound
print remap( -20.0, 0.0, 100.0, 0.0, 1.0 ), "==", -0.2
답변
확인하는 모든 값이 동일한 경우 @jerryjvl의 코드가 NaN을 반환하는 조건이 있습니다.
if (OldMin != OldMax && NewMin != NewMax):
return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
else:
return (NewMax + NewMin) / 2
답변
나는 이것을 위해 BNF 를 파헤 치지 않았지만 Arduino 문서에는 그 기능에 대한 훌륭한 예가 있었고 그 고장이 있습니다. 파이썬에서 def renaming을 다시 매핑 (map이 내장되어 있기 때문에)을 추가하고 유형 캐스트와 중괄호를 제거 (즉, 모든 ‘long’을 제거)하여 이것을 사용할 수있었습니다.
실물
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;
}
파이썬
def remap(x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
답변
PenguinTD가 제공 한 목록에서 범위가 반전 된 이유를 이해하지 못하므로 범위를 바꾸지 않고도 작동합니다. 선형 범위 변환은 선형 방정식에 기초하는 Y=Xm+n
, m
그리고 n
주어진 범위로부터 유도된다. 범위를 min
and 로 참조하는 대신 max
1과 2로 참조하는 것이 좋습니다. 따라서 수식은 다음과 같습니다.
Y = (((X - x1) * (y2 - y1)) / (x2 - x1)) + y1
어디 Y=y1
때 X=x1
, 그리고 Y=y2
때 X=x2
. x1
, x2
, y1
및 y2
특정 수 positive
또는 negative
값. 매크로에서 표현식을 정의하면 더 유용하므로 인수 이름과 함께 사용할 수 있습니다.
#define RangeConv(X, x1, x2, y1, y2) (((float)((X - x1) * (y2 - y1)) / (x2 - x1)) + y1)
float
캐스트는 모든 인수가있는 경우에는 소수점 부문 부동 보장 할 integer
값. 응용 프로그램에 따라이 범위를 체크 할 필요가 없습니다 x1=x2
와 y1==y2
.
답변
다음은 전체 목록을 확장하는 기능을 포함하여 복사 및 붙여 넣기 용이성을위한 간단한 Python 함수입니다.
def scale_number(unscaled, to_min, to_max, from_min, from_max):
return (to_max-to_min)*(unscaled-from_min)/(from_max-from_min)+to_min
def scale_list(l, to_min, to_max):
return [scale_number(i, to_min, to_max, min(l), max(l)) for i in l]
다음과 같이 사용할 수 있습니다.
scale_list([1,3,4,5], 0, 100)
[0.0, 50.0, 75.0, 100.0]
제 경우에는 다음과 같이 로그 곡선을 스케일하고 싶었습니다.
scale_list([math.log(i+1) for i in range(5)], 0, 50)
[0.0, 21.533827903669653, 34.130309724299266, 43.06765580733931, 50.0]