web-dev-qa-db-ja.com

数学-マッピング番号

Cとdの間を移動するために、aとbの間で線形に数値をマッピングする方法を教えてください。

つまり、2〜6の数字を10〜20の数字にマッピングしたいのですが、一般化されたケースが必要です。

私の脳は揚げられています。

87
Sam

数値XがAとBの間にあり、YがCとDの間にあるようにする場合、次の線形変換を適用できます。

Y =(X-A)/(B-A)*(D-C)+ C

間隔を逆方向にマッピングすることもできるため、質問は少しあいまいですが、これで目的がわかります。ゼロによる除算に気をつければ大丈夫です。

185
PeterAllenWebb

分割して2つの範囲のサイズの比率を取得し、初期範囲の開始値を減算し、比率で乗算し、2番目の範囲の開始値を加算します。言い換えると、

R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10

これにより、最初の範囲の数値が2番目の範囲に均等に広がります。

20
Konrad Rudolph

この機能がJava.lang.Mathクラスにあると便利です。これは非常に広く必要な機能であり、他の言語でも利用できるためです。簡単な実装を次に示します。

final static double EPSILON = 1e-12;

public static double map(double valueCoord1,
        double startCoord1, double endCoord1,
        double startCoord2, double endCoord2) {

    if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
        throw new ArithmeticException("/ 0");
    }

    double offset = startCoord2;
    double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
    return ratio * (valueCoord1 - startCoord1) + offset;
}

私はこのコードを将来の参考としてここに置いていますが、誰かの助けになるかもしれません。

6
Sourabh Bhat

余談ですが、これは、0から100(C)から32から212(F)に相当する数値範囲をマッピングする従来のセルシウスからファレンハイトへの変換と同じ問題です。

3
Metro

最初の範囲の各単位間隔は、2番目の範囲で(d-c)/(b-a)「スペース」を占有します。

擬似:

var interval = (d-c)/(b-a)
for n = 0 to (b - a)
    print c + n*interval

丸めの処理方法はユーザー次第です。

1
Chris Cudmore
int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;

int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;

println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
  stepF += rate;
  println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);

もちろん、ゼロ除算のチェック付き。

1
PhiLho

[a to b]の範囲で、[c to d]にマッピングする場合、xはマッピングする値です。この式を使用します(線形マッピング)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
0
Mohamed Ashraf

@PeterAllenWebbの回答に加えて、結果を元に戻したい場合は、次を使用します。

reverseX = (B-A)*(Y-C)/(D-C) + A
0
Dejell