irr*_*ate 489
假设您要将范围缩放[min,max]
到[a,b]
.您正在寻找满足的(连续)功能
f(min) = a
f(max) = b
Run Code Online (Sandbox Code Playgroud)
在你的情况下,a
将是1,b
将是30,但让我们从更简单的东西开始,并尝试映射[min,max]
到范围[0,1]
.
把min
成函数获得了0可以与实现
f(x) = x - min ===> f(min) = min - min = 0
Run Code Online (Sandbox Code Playgroud)
这几乎就是我们想要的.但是当我们真正想要时,投入max
会给我们max - min
1.所以我们必须扩展它:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
Run Code Online (Sandbox Code Playgroud)
这就是我们想要的.所以我们需要进行翻译和缩放.现在,如果不是我们想要得到的任意值a
和b
,我们需要一些更复杂的:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Run Code Online (Sandbox Code Playgroud)
您可以验证投入min
对x
现在给a
,并把在max
给b
.
您可能还会注意到,这(b-a)/(max-min)
是新范围的大小和原始范围的大小之间的缩放系数.因此,其实我们是第一平移x
通过-min
,它扩展到了正确的因素,然后再翻译回最多的新的最小值a
.
希望这可以帮助.
Cha*_*ton 43
这里有一些用于复制粘贴的JavaScript(这是烦人的答案):
function scaleBetween(unscaledNum, minAllowed, maxAllowed, min, max) {
return (maxAllowed - minAllowed) * (unscaledNum - min) / (max - min) + minAllowed;
}
Run Code Online (Sandbox Code Playgroud)
像这样应用,将范围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));
}
Run Code Online (Sandbox Code Playgroud)
0.00,18.37,48.98,55.10,85.71,100.00
编辑:
我知道我很久以前就回答了这个问题,但是我现在使用的是一个更清洁的功能:
Array.prototype.scaleBetween = function(scaledMin, scaledMax) {
var max = Math.max.apply(Math, this);
var min = Math.min.apply(Math, this);
return this.map(num => (scaledMax-scaledMin)*(num-min)/(max-min)+scaledMin);
}
Run Code Online (Sandbox Code Playgroud)
应用如下:
[-4, 0, 5, 6, 9].scaleBetween(0, 100);
Run Code Online (Sandbox Code Playgroud)
[0,30.76923076923077,69.23076923076923,76.92307692307692,100]
Jav*_*a42 27
为方便起见,这里是Java形式的Irritate算法.根据需要添加错误检查,异常处理和调整.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
测试:
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
Run Code Online (Sandbox Code Playgroud)
Vic*_*Vic 20
这是我理解的方式:
x
一个范围内的百分比是多少假设你有一个范围从.0
到100
.给定该范围内的任意数字,该范围内的"百分比"是多少?这应该是相当简单的,0
会0%
,50
会50%
和100
会100%
.
现在,如果你的范围是20
到100
?我们不能应用与上面相同的逻辑(除以100),因为:
20 / 100
Run Code Online (Sandbox Code Playgroud)
不给我们0
(20
应该是0%
现在).这应该很容易修复,我们只需要0
为该情况制作分子20
.我们可以通过减去:
(20 - 20) / 100
Run Code Online (Sandbox Code Playgroud)
但是,这不再适用100
了,因为:
(100 - 20) / 100
Run Code Online (Sandbox Code Playgroud)
不给我们100%
.同样,我们也可以通过从分母中减去它来解决这个问题:
(100 - 20) / (100 - 20)
Run Code Online (Sandbox Code Playgroud)
找出%x
在一个范围内的更通用的等式将是:
(x - MIN) / (MAX - MIN)
Run Code Online (Sandbox Code Playgroud)
现在我们知道数字在一个范围内的百分比,我们可以应用它来将数字映射到另一个范围.我们来看一个例子吧.
old range = [200, 1000]
new range = [10, 20]
Run Code Online (Sandbox Code Playgroud)
如果我们在旧范围内有一个数字,那么这个数字在新范围内会是多少?让我们说数字是400
.首先,弄清楚400
旧范围内的百分比.我们可以应用上面的等式.
(400 - 200) / (1000 - 200) = 0.25
Run Code Online (Sandbox Code Playgroud)
所以,400
在于25%
旧范围.我们只需要确定25%
新范围的数量.想想什么50%
的[0, 20]
是.这样10
对吗?你是怎么得到答案的?好吧,我们可以这样做:
20 * 0.5 = 10
Run Code Online (Sandbox Code Playgroud)
但是,怎么样[10, 20]
?我们现在需要改变一切10
.例如:
((20 - 10) * 0.5) + 10
Run Code Online (Sandbox Code Playgroud)
一个更通用的公式是:
((MAX - MIN) * PERCENT) + MIN
Run Code Online (Sandbox Code Playgroud)
要什么样的原始示例25%
的[10, 20]
是:
((20 - 10) * 0.25) + 10 = 12.5
Run Code Online (Sandbox Code Playgroud)
因此,400
在范围内[200, 1000]
将映射到12.5
范围内[10, 20]
要从x
旧范围映射到新范围:
OLD PERCENT = (x - OLD MIN) / (OLD MAX - OLD MIN)
NEW X = ((NEW MAX - NEW MIN) * OLD PERCENT) + NEW MIN
Run Code Online (Sandbox Code Playgroud)
KIC*_*KIC 11
我遇到了这个解决方案,但这并不适合我的需要.所以我在d3源代码中挖掘了一下.我个人会建议像d3.scale那样做.
所以在这里你将域缩放到范围.优点是您可以将标志翻转到目标范围.这很有用,因为计算机屏幕上的y轴自上而下,因此较大的值具有较小的y.
public class Rescale {
private final double range0,range1,domain0,domain1;
public Rescale(double domain0, double domain1, double range0, double range1) {
this.range0 = range0;
this.range1 = range1;
this.domain0 = domain0;
this.domain1 = domain1;
}
private double interpolate(double x) {
return range0 * (1 - x) + range1 * x;
}
private double uninterpolate(double x) {
double b = (domain1 - domain0) != 0 ? domain1 - domain0 : 1 / domain1;
return (x - domain0) / b;
}
public double rescale(double x) {
return interpolate(uninterpolate(x));
}
}
Run Code Online (Sandbox Code Playgroud)
这是测试,你可以看到我的意思
public class RescaleTest {
@Test
public void testRescale() {
Rescale r;
r = new Rescale(5,7,0,1);
Assert.assertTrue(r.rescale(5) == 0);
Assert.assertTrue(r.rescale(6) == 0.5);
Assert.assertTrue(r.rescale(7) == 1);
r = new Rescale(5,7,1,0);
Assert.assertTrue(r.rescale(5) == 1);
Assert.assertTrue(r.rescale(6) == 0.5);
Assert.assertTrue(r.rescale(7) == 0);
r = new Rescale(-3,3,0,1);
Assert.assertTrue(r.rescale(-3) == 0);
Assert.assertTrue(r.rescale(0) == 0.5);
Assert.assertTrue(r.rescale(3) == 1);
r = new Rescale(-3,3,-1,1);
Assert.assertTrue(r.rescale(-3) == -1);
Assert.assertTrue(r.rescale(0) == 0);
Assert.assertTrue(r.rescale(3) == 1);
}
}
Run Code Online (Sandbox Code Playgroud)