我试图将一个范围的数字转换为另一个,保持比率。数学不是我的强项。

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).


当前回答

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;
}

其他回答

有一种情况,当您检查的所有值都相同时,@jerryjvl的代码将返回NaN。

if (OldMin != OldMax && NewMin != NewMax):
    return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
else:
    return (NewMax + NewMin) / 2

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);

}

捷径/简化方案

 NewRange/OldRange = Handy multiplicand or HM
 Convert OldValue in OldRange to NewValue in NewRange = 
 (OldValue - OldMin x HM) + NewMin

韦恩

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

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;
}