将一个数字范围映射到另一个

时间:2018-10-28 18:04:15

标签: javascript floating-point

我正在尝试将一个十进制数字范围映射到另一个十进制数字范围。在下面的示例中,它是范围0.0-> 2.0映射到0.0-> 0.8。我似乎无法达到0.8的输出范围-它在0.722处止损。我认为问题是如何计算比例变量,但不确定如何解决。谁能看到我要去哪里错了?

function myscale (num, in_min, in_max, out_min, out_max, factor)
{
	// number map
	var scale = Math.max(0.0, num - in_min) / (in_max - in_min);

	// calculate easing curve
	var r = out_min + (Math.pow(scale, factor) * (out_max - out_min));

	// 64-bit floating point representation fix
	r = parseFloat(r.toFixed(10));

	// return mapped scale number
	return r;
}

var text = "";
var i;

for (i = 0.0; i <= 2.0; i = i + 0.1)
{ 
    text += myscale(i, 0.0, 2.0, 0.0, 0.8, 2) + "<br />";
}

document.getElementById("demo").innerHTML = text;
<!DOCTYPE html>
<html>
<body>

<b>Numbers mapped from 0 to 0.8</b>

<p id="demo"></p>

</body>
</html>

2 个答案:

答案 0 :(得分:1)

您可以采用其他方法进行迭代,直到该值小于所需值为止。最后,取得greates值,并在for循环外使用该值调用函数,该值带有浮点加数字错误。

function myscale (num, in_min, in_max, out_min, out_max, factor) {
	// number map
	var scale = Math.max(0.0, num - in_min) / (in_max - in_min);

	// calculate easing curve
	var r = out_min + (Math.pow(scale, factor) * (out_max - out_min));

	// 64-bit floating point representation fix
	r = parseFloat(r.toFixed(10));

	// return mapped scale number
	return r;
}

var text = "";
var i;

for (i = 0; i < 2; i += 0.1) { 
    text += myscale(i, 0, 2, 0, 0.8, 2) + "<br />";
}
text += myscale(2, 0, 2, 0, 0.8, 2) + "<br />";

document.getElementById("demo").innerHTML = text;
<b>Numbers mapped from 0 to 0.8</b>
<p id="demo"></p>

答案 1 :(得分:0)

非整数值不应用于循环控制,除非您已为浮点算术正确设计了循环。通常,使用整数算术实现循环控制会更容易。 (在循环控制中使用非整数值时,浮点舍入错误可能会导致迭代器值在迭代中稍微高于或低于最终值,而理想情况下会等于最终值。这使得可以精确控制迭代器的迭代次数。循环结束很困难。)

对于问题中的情况,我们要进行十分之一的迭代,一个简单的解决方案是按10进行缩放,因此0、2.0和0.1变为0、20和1:

for (var ProxyI = 0; ProxyI <= 20; ProxyI = ProxyI += 1)
{
    var RealI = ProxyI / 10.0;
    text += myscale(RealI, 0.0, 2.0, 0.0, 0.8, 2) + "<br />";
}

通常,如果我们想从Start迭代到End,包括Increment,那么Increment最好将距离Start均匀地除以到End,但是浮点运算会产生干扰,那么我们可以使用:

var NumberOfIntervals = Math.round((End - Start) / Interval);
for (var ProxyI = 0; ProxyI <= NumberOfIntervals; ProxyI = ProxyI + 1)
{
    var RealI = Start + I / NumberOfIntervals * (End - Start);
    …
}

这里的设计是将NumberOfIntervals设置为我们希望迭代的整数间隔。然后对ProxyI使用整数算术,将其递增1以计算间隔。此整数算术没有舍入误差,因此ProxyI可以正确计算间隔。然后,在循环内部,缩放计数器ProxyI并将其转换为从StartEnd的间隔中的相应点。该算法将有一些舍入误差,因此RealI通常不是精确的理想数字,但接近。舍入错误只会影响RealI的值;它们不会影响循环计数器ProxyI。因此,循环计数正确。 (获取精确的数字通常是不可能的,因为它不能以浮点格式表示。)

此设计解决了迭代器中的舍入误差导致其略高于或低于最终值的问题,但是它提供了避免许多舍入误差的附加好处。舍入错误仅限于Start + I / NumberOfIntervals * (End - Start)中的少数操作。

(注意:我几乎从来没有用JavaScript编写过,所以我不能保证上面的代码是正确的JavaScript。还要注意,上面计算得出的RealI的最终值可能不完全是End,因为浮点运算中的End - Start + Start不一定会产生End。)