数値をaとbの間で線形にマッピングして、cとdの間を移動するにはどうすればよいですか。
つまり、2から6までの数値を10から20までの数値にマップしたいのですが、一般化されたケースが必要です。
私の脳は揚げられています。
数値をaとbの間で線形にマッピングして、cとdの間を移動するにはどうすればよいですか。
つまり、2から6までの数値を10から20までの数値にマップしたいのですが、一般化されたケースが必要です。
私の脳は揚げられています。
数値 X が A と B の間にあり、Y が C と D の間にある場合は、次の線形変換を適用できます。
Y = (X-A)/(B-A) * (D-C) + C
逆方向に間隔をマッピングすることもできるため、質問は少しあいまいですが、それはあなたが望むものを与えるはずです。ゼロ除算に注意してください。問題ありません。
除算して 2 つの範囲のサイズ間の比率を取得し、最初の範囲の開始値を引き、その比率を掛けて、2 番目の範囲の開始値を加算します。言い換えると、
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
これにより、最初の範囲の数値が 2 番目の範囲に均等に分散されます。
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;
}
私はこのコードを将来の参考としてここに置いていますが、誰かの助けになるかもしれません。
余談ですが、これは、0 ~ 100 (C) から 32 ~ 212 (F) に相当する数値範囲をマップする従来の摂氏から華氏への変換と同じ問題です。
@PeterAllenWebb の回答に加えて、結果を元に戻したい場合は、次を使用します。
reverseX = (B-A)*(Y-C)/(D-C) + A
最初の範囲の各単位間隔は、2 番目の範囲で (dc)/(ba) の「スペース」を占有します。
擬似:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
丸めをどのように扱うかはあなた次第です。
ここで、 XはA - BからC - Dにマップする数値であり、Yは結果です: 線形補間式 lerp( a , b , m )= a +( m *( b - a )) を使用します。 aとbの代わりにCとDを入れて、 Y = C +( m *( D - C ))を取得します。次に、mの代わりに ( X -A )/( B - A ) Y = C +((( X - A )/( B - A ))*( D - C )) を取得します。これは問題のないマップ関数ですが、単純化することができます。( D - C ) ピースを取り、被除数の中に入れてY = C +((( X - A )*( D - C ))/( B - A )) を取得します。これにより、単純化できる別の部分 ( X - A )*( D ) が得られます。- C )、これは ( X * D )-( X * C )-( A * D )+( A * C )に相当します。それをポップすると、Y = C +((( X * D )-( X * C )-( A * D )+( A * C ))/( B - A )) が得られます。次に行う必要があるのは、+ Cビットを追加することです。これを行うには、 Cに ( B - Aを掛けます。) (( B * C )-( A * C )) を取得し、それを被除数に移動してY =((( X * D )-( X * C )-( A * D )+( A * C )+( B * C )-( A * C ))/( B - A ))。これは冗長で、+( A * C ) と -( A * C ) の両方が含まれており、互いに打ち消し合っています。それらを削除すると、次の最終結果が得られます。Y =(( X * D )-( X * C )-( A * D )+( B * C ))/( B - A )
TL;DR: 標準マップ関数Y = C +((( X - A )/( B - A ))*( D - C )) は、 Y =(( X * D )-(に簡略化できます。X * C )-( A * D )+( B * C ))/( B - A )
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);
もちろん、ゼロ除算のチェック付き。