标准化从 0 - 1 的任何数字的函数

Posted

技术标签:

【中文标题】标准化从 0 - 1 的任何数字的函数【英文标题】:Function to normalize any number from 0 - 1 【发布时间】:2017-02-08 03:56:25 【问题描述】:

我正在尝试创建一个函数,该函数接受一个数字并将其从 0 到 1 标准化,介于其最小和最大范围之间。例如:

如果我想在 5 到 15 之间标准化 10 的值,我称之为:

val = 10; normalize(val, 5, 15); 返回 0.5

在 -10 和 5 之间标准化一个值 0

val = 0; normalize(val, -10, 5); 返回 0.666

这是我想出的功能:

function normalize(val, min, max)
  // Shift to positive to avoid issues when crossing the 0 line
  if(min < 0)
    max += 0 - min;
    val += 0 - min;
    min = 0;
  
  // Shift values from 0 - max
  val = val - min;
  max = max - min;
  return Math.max(0, Math.min(1, val / max));

我的问题是:这是标准化一维值的最有效方法吗?我将以 60fps 每帧调用这个函数几千次,所以我希望尽可能优化它以减少计算负担。我一直在寻找归一化公式,但我找到的都是 2 维或 3 维解决方案。

【问题讨论】:

我看不出你为什么要单独处理负分钟数, 数组的最小值和最大值是否始终相同? @redneb 哇,你是对的!我是在没有真正测试的情况下先发制人地这样做的。它可以在不切换到 > 0 的情况下工作 @NinaScholz min 和 max 会根据我调用它的位置而改变。有时是-100, 0,有时是-3, 781,等等。 @MarcoDelValle 所以只要去掉负最小值的特殊处理就可以了。 【参考方案1】:

为什么不只是:

function(val, max, min)  return (val - min) / (max - min); 

【讨论】:

太好了,谢谢!这似乎是最简单的方法。我用 if 语句把事情复杂化了。但是,我仍然想将值限制在 0 和 1 之间,所以我正在考虑做 return Math.max(0, Math.min(1, val-min / max-min)) @MarcoDelValle 只要val 实际上介于minmax 之间,结果将始终介于0 和1 之间。 @Keiwan 我知道。问题是val 并不总是介于minmax 之间,所以我需要一种方法来防止它返回负数或任何大于 1 的值 @MarcoDelValle:不要忘记在(max-min) 周围加上括号。 @Keiwan 如果我想要介于 -1, 1 之间的值怎么办【参考方案2】:

将Nathan Bertons 的答案与预配置函数一起用于具有相同minmax 值的某些值,您可以使用它。

function normalize(min, max) 
    var delta = max - min;
    return function (val) 
        return (val - min) / delta;
    ;


console.log([5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].map(normalize(5, 15)));

【讨论】:

【参考方案3】:

当我想用已知的最小值、最大值对两个范围之间的值进行归一化时,我更喜欢使用这个公式。您可以添加检查来约束输入,但如果输入超出范围的值,这将正确计算与新范围的差异。

/**
 * Normalizes a value from one range (current) to another (new).
 *
 * @param   Number  val    //the current value (part of the current range).
 * @param   Number  minVal //the min value of the current value range.
 * @param   Number  maxVal //the max value of the current value range.
 * @param   Number  newMin //the min value of the new value range.
 * @param   Number  newMax //the max value of the new value range.
 *
 * @returns  Number  the normalized value.
 */
const normalizeBetweenTwoRanges = (val, minVal, maxVal, newMin, newMax) => 
  return newMin + (val - minVal) * (newMax - newMin) / (maxVal - minVal);
;

const e = document.getElementById('result');
e.innerhtml = normalizeBetweenTwoRanges(10, 5, 15, 0, 1);
&lt;span id="result"&gt;&lt;/span&gt;

【讨论】:

请小心,因为这不支持负范围,这里有一个实现:***.com/a/51161208/930675 抱歉,它在 C# 中。【参考方案4】:

使用Nathan Bertons的回答,你必须验证max-min是否等于0,否则返回NaN:

function (val, max, min)  
    if(max - min === 0) return 1; // or 0, it's up to you
    return (val - min) / (max - min); 

您可以使用generalization 来限制数据集中任意点 a 和 b 之间的值范围:

function (val, max, min) 
    if(max - min === 0) return a; // or b, it's up to you
    return a + (((val - min) * (b-a)) / (max - min));

【讨论】:

如果 max - min 具有相同的值,则它们将等于零,你不可能给 max = 5min = 5【参考方案5】:

我将完成 Nina Scholz 的答案,您可以使用下划线库来查找数组的最小值和最大值,您可以使用如下,或者创建自己的(简单的方法和简单的循环):

如果您使用的是 nodeJS,您需要使用命令 npm install underscore 安装下划线并使用命令 var _ = require('underscore/underscore'); 或者您可以在 html 上导入库并在您的网络上使用

function min(arr) if (!arr.length) return null; var minValue = arr[0]; for (var item of arr) if (item maxValue) maxValue = item; return maxValue; var array = [1, 2, 3, 4, 5, 6, 7, 8, 9]; function normalize(min, max) var delta = max - min; return function (val) return (val - min) / delta; ; function normalizeArray(array) var minValue = min(array); //if you use underscore _.min(array) var maxValue = max(array);//if you use underscore _.max(array) return array.map(normalize(minValue, maxValue)); console.log(normalizeArray(array));

【讨论】:

抱歉在这里你也找到了 max 函数 :) function max(arr) if (!arr.length) return null; var maxValue = arr[0]; for (var item of arr) if (item > maxValue) maxValue = item; 返回最大值; 【参考方案6】:

最大-最小限制

function normalize(min, max) 
   const delta = max - min;
   return val => ( (val < min? min: (val > max? max : val)) - min ) / delta;

console.log([-2,3,5, 6, 7, 8, 9, 10,11,23].map(normalize(0, 10)));
// [

输出:[0, 0.3, 0.5, 0.6, 0.7, 0.8, 0.9, 1、 1、 1 ]

【讨论】:

更简单:return Math.max(0, Math.min(1, val-min / max-min))【参考方案7】:

如果您想要一种更动态的方法,您可以在其中指定最大范围,那么这可以是这里的解决方案,在这个示例中,我们将我们的数据标准化在 0 到 100 的范围内

    let a = [500, 2000, 3000, 10000];

    function normalize(data, arr_max, arr_min, newMax)
        return data.map(d => 
            return newMax * ((d - arr_min)/(arr_max - arr_min))
        )
    


console.log(normalize(a, 10000, 500, 100))

【讨论】:

我觉得这只会使接受的答案过于复杂。我从来没有要求数组映射,也没有乘以 newMax 值。

以上是关于标准化从 0 - 1 的任何数字的函数的主要内容,如果未能解决你的问题,请参考以下文章

将数字从标准输入获取到 C 中的数组

是否有任何函数可以从标准输入中获取无限的输入字符串

Matlab中处理日期与时间的函数

如何标准化 0 和 1 之间的 Pearson 相关性?

从标准输入将数字读入寄存器?加载 scanf 结果

c语言编程。从标准输入设备上输入一个字符串,分别统计其中每个数字,空格,字母及其他字符出现的次数。