我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。
I have an image file where point values may range from -16000.00 to 16000.00 though the typical range may be much less. What I want to do is compress these values into the integer range 0-100, where 0 is the value of the smallest point, and 100 is the value of the largest. All points in between should keep a relative ratio even though some precision is being lost I'd like to do this in python but even a general algorithm should suffice. I'd prefer an algorithm where the min/max or either range can be adjusted (ie, the second range could be -50 to 800 instead of 0 to 100).
这个例子将歌曲的当前位置转换为20 - 40的角度范围。
/// <summary>
/// This test converts Current songtime to an angle in a range.
/// </summary>
[Fact]
public void ConvertRangeTests()
{
//Convert a songs time to an angle of a range 20 - 40
var result = ConvertAndGetCurrentValueOfRange(
TimeSpan.Zero, TimeSpan.FromMinutes(5.4),
20, 40,
2.7
);
Assert.True(result == 30);
}
/// <summary>
/// Gets the current value from the mixValue maxValue range.
/// </summary>
/// <param name="startTime">Start of the song</param>
/// <param name="duration"></param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <param name="value">Current time</param>
/// <returns></returns>
public double ConvertAndGetCurrentValueOfRange(
TimeSpan startTime,
TimeSpan duration,
double minValue,
double maxValue,
double value)
{
var timeRange = duration - startTime;
var newRange = maxValue - minValue;
var ratio = newRange / timeRange.TotalMinutes;
var newValue = value * ratio;
var currentValue= newValue + minValue;
return currentValue;
}
C++变体
我发现PenguinTD的解决方案很有用,所以我把它移植到c++,如果有人需要它:
float remap(float x, float oMin, float oMax, float nMin, float nMax ){
//range check
if( oMin == oMax) {
//std::cout<< "Warning: Zero input range";
return -1; }
if( nMin == nMax){
//std::cout<<"Warning: Zero output range";
return -1; }
//check reversed input range
bool reverseInput = false;
float oldMin = min( oMin, oMax );
float oldMax = max( oMin, oMax );
if (oldMin == oMin)
reverseInput = true;
//check reversed output range
bool reverseOutput = false;
float newMin = min( nMin, nMax );
float newMax = max( nMin, nMax );
if (newMin == nMin)
reverseOutput = true;
float portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin);
if (reverseInput)
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin);
float result = portion + newMin;
if (reverseOutput)
result = newMax - portion;
return result; }
使用Numpy和interp函数,你可以将你的值从旧范围转换为新范围:
>>> import numpy as np
>>> np.interp(0, [-16000,16000], [0,100])
50.0
你也可以尝试映射一个值列表:
>>> np.interp([-16000,0,12000] ,[-16000,16000], [0,100])
array([ 0. , 50. , 87.5])
我在一个用js解决的问题中使用了这个解决方案,所以我想我将分享翻译。谢谢你的解释和解决方案。
function remap( x, oMin, oMax, nMin, nMax ){
//range check
if (oMin == oMax){
console.log("Warning: Zero input range");
return None;
};
if (nMin == nMax){
console.log("Warning: Zero output range");
return None
}
//check reversed input range
var reverseInput = false;
oldMin = Math.min( oMin, oMax );
oldMax = Math.max( oMin, oMax );
if (oldMin != oMin){
reverseInput = true;
}
//check reversed output range
var reverseOutput = false;
newMin = Math.min( nMin, nMax )
newMax = Math.max( nMin, nMax )
if (newMin != nMin){
reverseOutput = true;
};
var portion = (x-oldMin)*(newMax-newMin)/(oldMax-oldMin)
if (reverseInput){
portion = (oldMax-x)*(newMax-newMin)/(oldMax-oldMin);
};
var result = portion + newMin
if (reverseOutput){
result = newMax - portion;
}
return result;
}