我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。
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).
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; }
我写了一个函数用R来做这个,方法和上面一样,但是我需要在R中做很多次,所以我想分享一下,以防它对任何人有帮助。
convertRange <- function(
oldValue,
oldRange = c(-16000.00, 16000.00),
newRange = c(0, 100),
returnInt = TRUE # the poster asked for an integer, so this is an option
){
oldMin <- oldRange[1]
oldMax <- oldRange[2]
newMin <- newRange[1]
newMax <- newRange[2]
newValue = (((oldValue - oldMin)* (newMax - newMin)) / (oldMax - oldMin)) + newMin
if(returnInt){
return(round(newValue))
} else {
return(newValue)
}
}
PHP的港口
发现PenguinTD的解决方案很有用,所以我将其移植到PHP。帮助你自己!
/**
* =====================================
* Remap Range
* =====================================
* - Convert one range to another. (including value)
*
* @param int $intValue The value in the old range you wish to convert
* @param int $oMin The minimum of the old range
* @param int $oMax The maximum of the old range
* @param int $nMin The minimum of the new range
* @param int $nMax The maximum of the new range
*
* @return float $fResult The old value converted to the new range
*/
function remapRange($intValue, $oMin, $oMax, $nMin, $nMax) {
// Range check
if ($oMin == $oMax) {
echo 'Warning: Zero input range';
return false;
}
if ($nMin == $nMax) {
echo 'Warning: Zero output range';
return false;
}
// Check reversed input range
$bReverseInput = false;
$intOldMin = min($oMin, $oMax);
$intOldMax = max($oMin, $oMax);
if ($intOldMin != $oMin) {
$bReverseInput = true;
}
// Check reversed output range
$bReverseOutput = false;
$intNewMin = min($nMin, $nMax);
$intNewMax = max($nMin, $nMax);
if ($intNewMin != $nMin) {
$bReverseOutput = true;
}
$fRatio = ($intValue - $intOldMin) * ($intNewMax - $intNewMin) / ($intOldMax - $intOldMin);
if ($bReverseInput) {
$fRatio = ($intOldMax - $intValue) * ($intNewMax - $intNewMin) / ($intOldMax - $intOldMin);
}
$fResult = $fRatio + $intNewMin;
if ($bReverseOutput) {
$fResult = $intNewMax - $fRatio;
}
return $fResult;
}
我没有为此挖掘BNF,但Arduino文档有一个很好的函数示例,它是分解的。我可以在Python中通过简单地添加一个def重命名到remap(因为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;
}
Python
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
https://www.arduino.cc/en/reference/map
Java版本
不管你喂它什么,它都能工作!
我把所有内容都展开了,这样便于学习。当然,最后舍入是可选的。
private long remap(long p, long Amin, long Amax, long Bmin, long Bmax ) {
double deltaA = Amax - Amin;
double deltaB = Bmax - Bmin;
double scale = deltaB / deltaA;
double negA = -1 * Amin;
double offset = (negA * scale) + Bmin;
double q = (p * scale) + offset;
return Math.round(q);
}