将区间映射到更小的区间的算法

20

我尝试搜索过,但由于我的问题性质,我无法找到令人满意的答案。

我的问题是:我正在尝试将从0到2000(理想情况下上限可调整)的数字映射到范围从10到100的更小间隔。 上限会映射(2000->100),下限也是如此。 除此之外,在区间[0;2000]内,一个条目比另一个条目大,那么在[0;100]中映射的条目也应该更大

我认为这个问题不特定于语言,但以防你想知道,今天我正在使用Javascript。


你的范围是整数还是实数/浮点数/十进制数?你需要将源中的不同条目映射到目标中的不同条目吗? - Chowlett
1
刚刚在输入完这个问题后,我想到了一个(对我来说)可接受的解决方案:我计算了其区间中第一项的百分比值,然后将该百分比转换到新的区间。 - Marceau
6个回答

49
To map
[A, B] --> [a, b]

use this formula
(val - A)*(b-a)/(B-A) + a

正如其他答案所正确提到的,这是线性映射。

基本上

y = m*x + c

c = intersection at y-axis
m = slope determined by two known point (A, a), (B, b) = (b-a)/(B-A)

我最终做了一些看起来非常相似的东西。上面有一个描述,但脚本在这里:(nMinValue是B,nMaxFontSize是a)var nPercentage = ((modifier-nMinValue)/(nMaxValue - nMinValue))*100; var nFontSize = parseInt((nBiggestFont-nSmallestFont)*(nPercentage/100)+nSmallestFont); - Marceau

7
我认为,不是给你一个直接映射的公式,更好的方法是解释它背后的思想:
假设我们想将区间[0,1]映射到区间[1,3],这可以看作是寻找f(x)=Ax+B的问题,使得对于区间[0,1]中的任何x,结果都应该是在区间[1,3]中的f(x)。
从这个角度来看,我们已经知道了一些值:
  1. x = 0 & f(0) = 1 => f(0) = A*0 + B = 1 => B = 1
  2. x = 1 & f(1) = 3 => f(1) = A*1 + B = 3 <=> A + 1 = 3 => A=2
从(1)和(2)可以得出结论,将区间[0,1]映射到[1,3]的函数是f(x) = 2x + 1。
在您的情况下,您现在应该具备所有必要的知识,以能够映射[0,2000]区间到[10,100]。

3
// Given a value from intervalA, returns a mapped value from intervalB.
function intervalicValueMap(intervalA, intervalB, valueIntervalA) {
    var valueIntervalB = (valueIntervalA - intervalA[0]) * (intervalB[1] - intervalB[0]) 
                            / (intervalA[1] - intervalA[0]) + intervalB[0];

    valueIntervalB = Math.round(valueIntervalB); // Ommit rounding if not needed.
    return valueIntervalB;
}

var intervalA = [100, 200];
var intervalB = [1, 10];
var valueIntervalA = 170;
var valueIntervalB = intervalicValueMap(intervalA, intervalB, valueIntervalA);

console.log(valueIntervalB); // Logs 7

1

这里可以提供一种优化的方式来映射您的x数据, 这段伪代码展示了一个映射函数的主要思路:

  • Avoid problems with x values out of b1 - b2's range.
  • Deals with array mapping

    function map(var x, var b1, var b2, var s1, var s2)
    {
        var i;
        var result;
    
        i = 0;
        while(i < sizeof(s2))
            if(x < b1)
                result[i++] = s1;
            else if (x > b2)
                result[i++] = s2;
            else
                result[i] = (x - b1) / (b2 - b1 ) * (s2[i] - s1[i]) + s1[i++];
        return (result);
    }
    

1
一个简单的线性映射将把x映射到x*90/2000+10

1

使用Python中的Numpy库给出的答案:

import numpy as np  

# [A, B]: old interval
# [a, b] new interval
new_value = np.interp(old_value, [A, B], [a, b])
print(new_value)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接