2008-12-05 8 views
65

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

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

Мой мозг жарится.

+3

Двухточечная форма. http://en.wikipedia.org/wiki/Linear_equation#Two-point_form – kennytm 2010-03-06 18:53:49

ответ

16

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

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

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

+0

Это не работает. Мой диапазон от 1000000000 до 9999999999, и цифры могут быть от 1 до 999999999. – Dejell 2013-02-19 09:39:27

+0

@Odelya Конечно, это работает. Это достаточно простая математическая трансформация. Вам просто нужно использовать достаточно большой тип номера (bignum или аналогичный). Ваши номера просто слишком велики для 32-битных целых чисел, но, например, будут работать 64-битные целые числа. – 2013-02-19 11:40:01

+0

Они типа двойные. двойной R = (20 - 10)/(6 - 2); \t \t double y = (X - 2) * R + 10; – Dejell 2013-02-19 11:43:23

137

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

Y = (XA)/(BA) * (DC) + C

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

1

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

Псевдо:

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); 

С проверкой на деление на ноль, конечно.

2

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

0

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

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

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

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