web-dev-qa-db-ja.com

0〜1の任意の数を正規化する関数

私は数を取り、その最小と最大の境界の間で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));
}

私の質問は、これが1次元の値を正規化する最も効率的な方法ですか?この関数をフレームごとに60fpsで数千回呼び出すので、できる限り最適化して計算の負担を軽減したいと思います。正規化の式を探しましたが、見つかったのは2次元または3次元の解だけです。

11
Marquizzo

なぜだけではありません:

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

35
Nathan Berton

同じminmaxの値を持ついくつかの値に対して、事前設定された関数で Nathan Bertons の答えを使用すると、これを使用できます。

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)));
10
Nina Scholz

Nathan Bertons の答えを使用して、max-minがゼロに等しいかどうかを検証する必要があります。そうでない場合、戻り値は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)); }

3
Pedro Diniz

既知の最小値、最大値で2つの範囲の間の値を正規化する場合、この式を使用することを好みます。入力を制約するためにチェックを追加できますが、範囲外の値が入力として与えられた場合、これにより新しい範囲との差が正しく計算されます。

/**
 * 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);
<span id="result"></span>
2

Nina Scholzの答えを完成させます、アンダースコアライブラリを使用して配列の最小値と最大値を見つけ、次のように使用するか、独自の方法を作成できます(単純なループを使用した単純な方法):

nodeJSを使用している場合は、コマンドnpm install underscoreでアンダースコアをインストールし、コマンドvar _ = require('underscore/underscore');で使用するか、ライブラリをHTMLにインポートしてWebで使用する必要があります。



    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));

0
Naim Sulejmani