Как мне сопоставить числа, линейно, между a и b, чтобы перейти между c и d.
То есть я хочу, чтобы числа от 2 до 6 соответствовали числам от 10 до 20 ... но мне нужен обобщенный случай.
Мой мозг сгорел.





Разделите, чтобы получить соотношение между размерами двух диапазонов, затем вычтите начальное значение вашего начального диапазона, умножьте на соотношение и добавьте начальное значение вашего второго диапазона. Другими словами,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
Это равномерно распределяет числа из первого диапазона во втором диапазоне.
Это не работает. Мой диапазон от 1000000000 до 9999999999, а числа могут быть от 1 до 999999999.
@Odelya Конечно работает. Это достаточно простое математическое преобразование. Вам просто нужно использовать достаточно большой тип числа (bignum или аналогичный). Ваши числа просто слишком велики для 32-битных целых чисел, но, например, 64-битные целые числа будут работать.
Они двухместные. двойной R = (20-10) / (6-2); двойной y = (X - 2) * R + 10;
@Odelya Та же проблема. Вы должны прочитать о точности с плавающей запятой. Фактически, это обязательное чтение: Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой - если вам нужен тип с плавающей запятой с такими большими числами, вам, возможно, придется использовать числовой тип произвольной точности.
Можете ли вы порекомендовать тип java, который я могу сделать?
@Odelya В статье, на которую я ссылаюсь, упоминается соответствующий класс Java…
Если ваше число X находится между A и B, а вы хотите, чтобы Y находился между C и D, вы можете применить следующее линейное преобразование:
Y = (X-A)/(B-A) * (D-C) + C
Это должно дать вам то, что вы хотите, хотя ваш вопрос немного неоднозначен, поскольку вы также можете отобразить интервал в обратном направлении. Просто следите за делением на ноль, и все будет в порядке.
Для наглядности мне нравится new_value = (old_value - old_bottom) / (old_top - old_bottom) * (new_top - new_bottom) + new_bottom;
Есть ли где-нибудь вывод для этого уравнения?
@shaveenk это должно быть уравнение линии с Y=f(X)=m*X+b, где m и b были определены одновременно из следующих двух уравнений ограничений, которые являются результатом подстановки значений X и Y в требуемых конечных точках: C=m*A+b и D=m*B+b
Мне также пришлось использовать X=A+(A-B)*t, чтобы доказать равенство этого подхода и подхода Питера. t по сути является обезразмериванием X. (t=(X-A)/(A-B))
Чтобы изменить направление, формула: ((X-A) / (A-B) * (C-D)) * -1 + D
Каждый единичный интервал в первом диапазоне занимает (d-c) / (b-a) «пространство» во втором диапазоне.
Псевдо:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
Как вы будете обрабатывать округление, зависит от вас.
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);
Конечно, с проверкой деления на ноль.
В стороне, это та же проблема, что и при классическом преобразовании целциуса в фаренгейт, когда вы хотите сопоставить диапазон чисел, который от 0 до 100 (C) до 32-212 (F).
Как это ответ?
Это пример применения вопроса. Многие сталкиваются с этой простой проблемой во вводных классах CS и не считают, что ее решение можно обобщить на другие проблемы. Я пытался добавить контекст к исходному вопросу. На исходный вопрос уже был дан адекватный ответ.
В дополнение к ответу @PeterAllenWebb, если вы хотите отменить результат, используйте следующее:
reverseX = (B-A)*(Y-C)/(D-C) + A
Было бы неплохо иметь эту функциональность в классе 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;
}
Я сам помещаю этот код здесь в качестве справки на будущее, и, возможно, он кому-то поможет.
если ваш диапазон от [a до b] и вы хотите отобразить его в [c to d], где x - значение, которое вы хотите сопоставить используйте эту формулу (линейное отображение)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
https://rosettacode.org/wiki/Map_range
[a1, a2] => [b1, b2]
if s in range of [a1, a2]
then t which will be in range of [b1, b2]
t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)
Где Икс - это число, которое нужно преобразовать из А-B в C-D, а Y - результат:
Возьмем линейную формулу интерполяции, лерп (а, б,
TL; DR: стандартная функция отображения, Y = C + (((Икс-А) / (B-А)) * (D-C), может быть упрощено до R_R_R117 (R_R_R117 (R_R_R116) до R_R117 (R_R_R117 (R_R_R116_R_R_R_116) * C) - (А * D) + (B * C)) / (B-А)
Двухточечная форма. en.wikipedia.org/wiki/Linear_equation#Two-point_form