Math 如何缩小具有已知最小值和最大值的数字范围

Math 如何缩小具有已知最小值和最大值的数字范围,math,range,scaling,max,minimum,Math,Range,Scaling,Max,Minimum,因此,我试图找出如何获取一个数字范围,并缩小数值以适应一个范围。之所以要这样做,是因为我试图在JavaSwingJPanel中绘制省略号。我希望每个椭圆的高度和宽度在1-30的范围内。我有一些方法可以从我的数据集中找到最小值和最大值,但在运行时之前我不会得到最小值和最大值。有没有一种简单的方法可以做到这一点?假设您想要将范围[min,max]缩放到[a,b]。您正在寻找满足以下条件的(连续)函数 f(min) = a f(max) = b 在您的情况下,a将是1,b将是30,但让我们从更简单的

因此,我试图找出如何获取一个数字范围,并缩小数值以适应一个范围。之所以要这样做,是因为我试图在JavaSwingJPanel中绘制省略号。我希望每个椭圆的高度和宽度在1-30的范围内。我有一些方法可以从我的数据集中找到最小值和最大值,但在运行时之前我不会得到最小值和最大值。有没有一种简单的方法可以做到这一点?

假设您想要将范围
[min,max]
缩放到
[a,b]
。您正在寻找满足以下条件的(连续)函数

f(min) = a
f(max) = b
在您的情况下,
a
将是1,
b
将是30,但让我们从更简单的事情开始,尝试将
[min,max]
映射到范围
[0,1]

min
放入一个函数并从中取出0可以用

f(x) = x - min   ===>   f(min) = min - min = 0
所以这几乎就是我们想要的。但是当我们实际需要1时,输入
max
会给我们
max-min
。因此,我们必须对其进行扩展:

        x - min                                  max - min
f(x) = ---------   ===>   f(min) = 0;  f(max) =  --------- = 1
       max - min                                 max - min
这就是我们想要的。所以我们需要做一个平移和缩放。现在,如果我们想得到
a
b
的任意值,我们需要一些更复杂的东西:

       (b-a)(x - min)
f(x) = --------------  + a
          max - min
您可以验证为
x
输入
min
现在得到
a
,输入
max
得到
b

您可能还注意到,
(b-a)/(max-min)
是新范围大小和原始范围大小之间的比例因子。因此,我们首先将
x
转换为
-min
,将其缩放到正确的因子,然后将其转换回新的最小值
a


希望这有帮助。

为了方便起见,这里是一个Java形式的Increst算法。根据需要添加错误检查、异常处理和调整

public class Algorithms { 
    public static double scale(final double valueIn, final double baseMin, final double baseMax, final double limitMin, final double limitMax) {
        return ((limitMax - limitMin) * (valueIn - baseMin) / (baseMax - baseMin)) + limitMin;
    }
}
测试人员:

final double baseMin = 0.0;
final double baseMax = 360.0;
final double limitMin = 90.0;
final double limitMax = 270.0;
double valueIn = 0;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));
valueIn = 360;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));
valueIn = 180;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));

90.0
270.0
180.0

我遇到了这个解决方案,但它并不真正符合我的需要。因此,我在d3源代码中挖掘了一点。我个人建议像d3.scale那样做


因此,在这里您可以将域扩展到范围。优点是你可以将标志翻转到你的目标范围。这很有用,因为计算机屏幕上的y轴是自上而下的,所以大值的y轴很小

公共类重新缩放{
私人最终双量程0,量程1,域0,域1;
公共重缩放(双域0,双域1,双范围0,双范围1){
这个0.range0=range0;
此参数为0.range1=range1;
this.domain0=domain0;
this.domain1=domain1;
}
专用双插值(双x){
返回范围0*(1-x)+范围1*x;
}
专用双无公司(双x){
双b=(域1-域0)!=0?域1-域0:1/域1;
返回(x-域0)/b;
}
公共双重缩放(双x){
返回插值(非合并(x));
}
}
这是一个测试,你可以明白我的意思

公共类重新缩放测试{
@试验
公共void testRescale(){
重新缩放r;
r=新的重新缩放(5,7,0,1);
Assert.assertTrue(r.rescale(5)==0);
Assert.assertTrue(r.rescale(6)=0.5);
Assert.assertTrue(r.rescale(7)==1);
r=新的重新缩放(5,7,1,0);
Assert.assertTrue(r.rescale(5)=1);
Assert.assertTrue(r.rescale(6)=0.5);
Assert.assertTrue(r.rescale(7)==0);
r=新的重新缩放(-3,3,0,1);
Assert.assertTrue(r.rescale(-3)==0);
Assert.assertTrue(r.rescale(0)=0.5);
Assert.assertTrue(r.rescale(3)=1);
r=新的重新缩放(-3,3,-1,1);
Assert.assertTrue(r.rescale(-3)=-1);
Assert.assertTrue(r.rescale(0)=0);
Assert.assertTrue(r.rescale(3)=1);
}
}

以下是一些用于复制粘贴轻松的JavaScript(这是Express的答案):

像这样应用,将范围10-50缩放到0-100之间

var unscaledNums = [10, 13, 25, 28, 43, 50];

var maxRange = Math.max.apply(Math, unscaledNums);
var minRange = Math.min.apply(Math, unscaledNums);

for (var i = 0; i < unscaledNums.length; i++) {
  var unscaled = unscaledNums[i];
  var scaled = scaleBetween(unscaled, 0, 100, minRange, maxRange);
  console.log(scaled.toFixed(2));
}
如是:

[-4, 0, 5, 6, 9].scaleBetween(0, 100);
[0,30.769230769223077,69.23076923076923,76.92307692307692100]


我是这样理解的:


x
的百分比在一个范围内是多少 假设您的范围是从
0
100
。给定该范围内的任意数字,该范围内的“百分比”是多少?这应该很简单,
0
将是
0%
50
将是
50%
100
将是
100%

现在,如果您的范围是
20
100
?我们不能应用与上述相同的逻辑(除以100),因为:

不会给我们
0
20
现在应该是
0%
)。这应该很容易解决,对于
20
的情况,我们只需要使分子
0
。我们可以通过减去:

(20 - 20) / 100
但是,这不再适用于
100
,因为:

(100 - 20) / 100
没有给我们提供100%的
。同样,我们也可以通过从分母中减去:

(100 - 20) / (100 - 20)
找出%
x
在一个范围内的值的更一般化方程是:

(x - MIN) / (MAX - MIN)
((MAX - MIN) * PERCENT) + MIN

将范围缩放到另一个范围 现在我们知道了一个数字在一个范围内的百分比,我们可以应用它将该数字映射到另一个范围。让我们看一个例子

old range = [200, 1000]
new range = [10, 20]
如果我们有一个旧范围内的数字,那么新范围内的数字是多少?让我们假设数字是
400
。首先,找出旧范围内的百分比
400
。我们可以应用上面的方程式

(400 - 200) / (1000 - 200) = 0.25
因此,
400
位于旧范围的
25%
。我们只需要计算出新范围的
25%
是多少。想想
[0,20]
50%
是什么。应该是
10
对吗?你是怎么得出这个答案的?好吧,我们可以这样做:

20 * 0.5 = 10
但是,从
[10,20]
开始呢?我们需要按
10(400 - 200) / (1000 - 200) = 0.25
20 * 0.5 = 10
((20 - 10) * 0.5) + 10
((MAX - MIN) * PERCENT) + MIN
((20 - 10) * 0.25) + 10 = 12.5
OLD PERCENT = (x - OLD MIN) / (OLD MAX - OLD MIN)
NEW X = ((NEW MAX - NEW MIN) * OLD PERCENT) + NEW MIN
public class MinMaxColumnSpec
{
    /// <summary>
    /// To reduce repetitive computations, the min-max formula has been refactored so that the portions that remain constant are just computed once.
    /// This transforms the forumula from
    /// x' = (b-a)(x-min)/(max-min) + a
    /// into x' = x(b-a)/(max-min) + min(-b+a)/(max-min) + a
    /// which can be further factored into
    /// x' = x*Part1 + Part2
    /// </summary>
    public readonly double Part1, Part2;

    /// <summary>
    /// Use this ctor to train a new scaler.
    /// </summary>
    public MinMaxColumnSpec(double[] columnValues, int newMin = 0, int newMax = 1)
    {
        if (newMax <= newMin)
            throw new ArgumentOutOfRangeException("newMax", "newMax must be greater than newMin");

        var oldMax = columnValues.Max();
        var oldMin = columnValues.Min();

        Part1 = (newMax - newMin) / (oldMax - oldMin);
        Part2 = newMin + (oldMin * (newMin - newMax) / (oldMax - oldMin));
    }

    /// <summary>
    /// Use this ctor for previously-trained scalers with known constants.
    /// </summary>
    public MinMaxColumnSpec(double part1, double part2)
    {
        Part1 = part1;
        Part2 = part2;
    }

    public double Scale(double x) => (x * Part1) + Part2;
}