数学-数値のマッピング


98

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

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

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


回答:


210

数値XがAとBの間にあり、YをCとDの間に収めたい場合は、次の線形変換を適用できます。

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

間隔を逆方向にマッピングすることもできるので、質問は少しあいまいですが、これで必要なものが得られます。ゼロによる除算に注意してください。大丈夫です。


47
次に、横にあるチェックマークをクリックして、この回答を「承認済み」としてマークします。
Konrad Rudolph、

16
わかりやすくするために、私はnew_value =(old_value-old_bottom)/(old_top-old_bottom)*(new_top-new_bottom)+ new_bottom;が好きです。
ftrotter 2014年

1
どこかにこの方程式の派生がありますか?
shaveenk

それは、行の式でなければなら@shaveenk Y=f(X)=m*X+bmおよびBは、以下の2つの制約式から同時に決定されている場合、必要なエンドポイントでXとYの値を代入した結果、その:C=m*A+bおよびD=m*B+b
クリスChiasson

私はまたX=A+(A-B)*t、このアプローチとピーターの平等を証明するために使用する必要がありました。tは本質的にXの無次元化です。(t=(X-A)/(A-B)
Chris Chiasson

21

2つの範囲のサイズ間の比率を得るために除算してから、初期範囲の開始値を減算し、比率を掛けて、2番目の範囲の開始値を追加します。言い換えると、

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

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


これは機能しません。私の範囲は9999999999から1000000000で、番号は1から999999999まで可能性
Dejell

@Odelyaもちろん動作します。これは十分に単純な数学的変換です。必要なのは、十分に大きな数値タイプ(bignumまたは類似のもの)を使用することだけです。あなたの数値は単に32ビット整数には大きすぎますが、たとえば64ビット整数は機能します。
Konrad Rudolph、

タイプはダブルです。double R =(20-10)/(6-2); double y =(X-2)* R + 10;
Dejell 2013

@Odelya同じ問題でも。浮動小数点の精度について読む必要があります。実際、これは必読です:浮動小数点演算についてすべてのコンピュータサイエンティストが知っておくべきこと –このような大きな数値を含む浮動小数点型が必要な場合は、任意精度の数値型を使用する必要があります。
Konrad Rudolph、

私ができるJavaタイプをお勧めできますか?
デジェル2013

7

これは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;
}

私はこのコードを将来のための参照としてここに入れており、誰かを助けるかもしれません。


4

余談ですが、これは、0から100(C)から32から212(F)に相当する数値範囲をマップしたい場合に、古典的な摂氏から華氏に変換するのと同じ問題です。


これはどのように答えますか?
しんぞう2017年

質問の応用例です。多くは導入CSクラスでこの単純な問題を抱えており、ソリューションを他の問題に一般化できるとは考えていません。元の質問にコンテキストを追加しようとしていました。元の質問はすでに適切に回答されていました。
Metro

1

最初の範囲の各単位間隔は、2番目の範囲の(dc)/(ba) "スペース"を占めます。

擬似:

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

丸めの処理方法はあなた次第です。


1
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

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

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


0

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

reverseX = (B-A)*(Y-C)/(D-C) + A
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.