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

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


当前回答

增加了KOTLIN版本的数学解释

假设我们有一个介于(OMin, Omax)之间的刻度,我们在这个范围内有一个值X

我们要把它转换成比例(NMin, NMax)

我们知道X,我们需要找到Y,比值必须相等:

 => (Y-NMin)/(NMax-NMin) = (X-OMin)/(OMax-OMin)  
      
 =>  (Y-NMin)/NewRange = (X-OMin)/OldRange 

 =>   Y = ((X-OMin)*NewRange)/oldRange)+NMin  Answer
   

从实用主义的角度来看,我们可以这样写这个问句:

 private fun  convertScale(oldValueToConvert:Int): Float {
       // Old Scale 50-100
       val oldScaleMin = 50
       val oldScaleMax = 100
       val oldScaleRange= (oldScaleMax - oldScaleMin)

       //new Scale 0-1
       val newScaleMin = 0.0f
       val newScaleMax = 1.0f
       val newScaleRange=  (newScaleMax - newScaleMin)
     
       return ((oldValueToConvert - oldScaleMin)* newScaleRange/ oldScaleRange) + newScaleMin
    }

JAVA

/**
     * 
     * @param x
     * @param inMin
     * @param inMax
     * @param outMin
     * @param outMax
     * @return
     */
        private long normalize(long x, long inMin, long inMax, long outMin, long outMax) {
          long outRange = outMax - outMin;
          long inRange  = inMax - inMin;
          return (x - inMin) *outRange / inRange + outMin;
        }

用法:

float brightness = normalize(progress, 0, 10, 0,255);

其他回答

在由PenguinTD提供的清单中,我不明白为什么范围是颠倒的,它不需要颠倒范围就能工作。线性范围转换基于线性方程Y=Xm+n,其中m和n是从给定的范围推导出来的。与其将范围称为min和max,不如将它们称为1和2。所以公式是:

Y = (((X - x1) * (y2 - y1)) / (x2 - x1)) + y1

当X=x1时Y=y1,当X=x2时Y=y2。X1, x2, y1和y2可以取任意正值或负值。在宏中定义表达式使其更有用,它可以与任何参数名称一起使用。

#define RangeConv(X, x1, x2, y1, y2) (((float)((X - x1) * (y2 - y1)) / (x2 - x1)) + y1)

在所有实参都是整数值的情况下,浮点强制转换将确保浮点除法。 根据应用程序的不同,可能不需要检查x1=x2和y1==y2的范围。

捷径/简化方案

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

韦恩

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

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

}

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