Math - отображение чисел - PullRequest
       41

Math - отображение чисел

86 голосов
/ 06 декабря 2008

Как мне линейно отобразить числа между a и b, чтобы перейти между c и d.

То есть я хочу, чтобы числа от 2 до 6 отображались на числа от 10 до 20 ... но мне нужен обобщенный случай.

Мой мозг жарен.

Ответы [ 8 ]

177 голосов
/ 06 декабря 2008

Если ваше число X находится между A и B, и вы хотите, чтобы Y находилось между C и D, вы можете применить следующее линейное преобразование:

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

Это должно дать вам то, что вы хотите, хотя ваш вопрос немного двусмысленный, поскольку вы также можете отобразить интервал в обратном направлении. Просто следите за делением на ноль, и вы должны быть в порядке.

19 голосов
/ 06 декабря 2008

Разделите, чтобы получить соотношение между размерами двух диапазонов, затем вычтите начальное значение вашего начального диапазона, умножьте на коэффициент и добавьте начальное значение вашего второго диапазона. Другими словами,

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

Равномерно распределяет числа из первого диапазона во второй диапазон.

6 голосов
/ 11 декабря 2016

Было бы неплохо иметь эту функциональность в классе 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;
}

Я сам помещаю этот код в качестве ссылки на будущее и, возможно, он кому-нибудь поможет.

3 голосов
/ 06 декабря 2008

Кроме того, это та же проблема, что и при классическом преобразовании в градусах Цельсия в фаренгейт, где вы хотите отобразить диапазон чисел, который равен от 0-100 (C) до 32-212 (F).

1 голос
/ 06 декабря 2008
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 голос
/ 06 декабря 2008

Каждый интервал единиц в первом диапазоне занимает (d-c) / (b-a) «пробел» во втором диапазоне.

Псевдо:

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

Как вы справляетесь с округлением, зависит от вас.

0 голосов
/ 09 января 2019

если ваш диапазон от [a до b] и вы хотите отобразить его в [c to d], где x - это значение, которое вы хотите отобразить используйте эту формулу (линейное отображение)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
0 голосов
/ 19 февраля 2013

В дополнение к ответу @PeterAllenWebb, если вы хотите отменить результат, используйте следующее:

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