Числа масштаба, чтобы быть <= 255?

Я когда-то реализовал его (даже не зная, что это было действительно двоичным поиском) для управления GUI, показывающего двумерные данные в графике. Нажатие с мышью должно установить курсор данных на точку с самым близким значением x. При контакте с большими количествами точек (несколько 1000, это было путем назад, когда x86 только начинал преобладать над частотой ЦП на 100 МГц) это не было действительно применимо в интерактивном режиме - я делал линейный поиск от запуска. После некоторых взглядов мне пришло в голову, что я мог приблизиться к этому в делении и завоевать вид. Взял меня некоторое время для получения его работающий под всеми пограничными случаями.

Это было только некоторое время спустя, что я узнал, что это - действительно фундаментальный алгоритм CS...

12
задан Bob Aman 13 October 2009 в 14:36
поделиться

12 ответов

Я подумал, что для этого подойдет лог-подгонка, но, глядя на результаты, я не уверен.

Однако Wolfram | Alpha отлично для экспериментов с подобными вещами :

Я начал с этого и закончил:

r(x) = floor(((11.5553 * log(14.4266 * (x + 1.0))) - 30.8419) / 0.9687)

Интересно, что оказывается, что это дает почти те же результаты, что и ответ Артелиуса:

r(x) = floor(255 * log(x + 1) / log(2^31 + 1)

ИМХО , вам лучше всего подойдет функция разделения для 0–10000 и 10000–2 ^ 31.

5
ответ дан 2 December 2019 в 04:43
поделиться

В общем (поскольку мне непонятно, относится ли это к вопросу Java или языковой независимости), вы должны разделить имеющееся у вас значение на Integer.MAX_VALUE , умножить на 255 и преобразовать в целое число.

2
ответ дан 2 December 2019 в 04:43
поделиться

Для линейного отображения диапазона 0-2 ^ 32 в 0-255 просто возьмите старший байт. Вот как это будет выглядеть с использованием двоичных и и битового сдвига:

r = value & 0xff000000 >> 24

Использование mod 256 определенно вернет значение 0-255, но вы не сможете извлечь какой-либо смысл группировки из результатов - 1 , 257, 513, 1025 все будут отображаться на масштабированное значение 1, даже если они находятся далеко друг от друга.

Если вы хотите быть более разборчивым среди низких значений и объединить вместе намного больше больших значений, тогда логарифмическое выражение будет работать:

r = log(value)/log(pow(2,32))*256

РЕДАКТИРОВАТЬ : Ура, моя учительница алгебры в средней школе миссис Бакенмейер упала в обморок! log (pow (2,32)) то же самое, что 32 * log (2) , и намного дешевле для оценки. И теперь мы можем лучше разложить это на множители, поскольку 256/32 - это хорошее даже 8:

3
ответ дан 2 December 2019 в 04:43
поделиться

The "fairest" linear scaling is actually done like this:

floor(256 * value / (Integer.MAX_VALUE + 1))

Note that this is just pseudocode and assumes floating-point calculations.

If we assume that Integer.MAX_VALUE + 1 is 2^31, and that / will give us integer division, then it simplifies to

value / 8388608

Why other answers are wrong

Some answers (as well as the question itself) suggsted a variation of (255 * value / Integer.MAX_VALUE). Presumably this has to be converted to an integer, either using round() or floor().

If using floor(), the only value that produces 255 is Integer.MAX_VALUE itself. This distribution is uneven.

If using round(), 0 and 255 will each get hit half as many times as 1-254. Also uneven.

Using the scaling method I mention above, no such problem occurs.

Non-linear methods

If you want to use logs, try this:

255 * log(value + 1) / log(Integer.MAX_VALUE + 1)

You could also just take the square root of the value (this wouldn't go all the way to 255, but you could scale it up if you wanted to).

16
ответ дан 2 December 2019 в 04:43
поделиться

Я мог бы просто сделать (value / (Integer.MAX_VALUE / 255)), но это приведет к тому, что многие низкие значения будут нулевыми.

Один из возможных подходов - использовать оператор по модулю ( r = value% 256; ). Хотя это не гарантирует, что Integer.MAX_VALUE окажется равным 255, это гарантирует число от 0 до 255. Это также позволит распределить низкие числа по 0 -255 диапазон.

РЕДАКТИРОВАТЬ:

Как ни странно, когда я это тестирую, Integer.MAX_VALUE% 256 действительно приводит к 255 (изначально я ошибочно тестировал % 255 , что дало неверные результаты). Это кажется довольно простым решением.

-1
ответ дан 2 December 2019 в 04:43
поделиться

Если вы жалуетесь на то, что младшие числа становятся равными нулю, вы можете нормализовать значения до 255, а не всего диапазона значений.

Формула будет выглядеть так:

currentValue / (максимальное значение набора)

0
ответ дан 2 December 2019 в 04:43
поделиться

The best answer really depends on the behavior you want.

If you want each cell just to generally have a color different than the neighbor, go with what akf said in the second paragraph and use a modulo (x % 256).

If you want the color to have some bearing on the actual value (like "blue means smaller values" all the way to "red means huge values"), you would have to post something about your expected distribution of values. Since you worry about many low values being zero I might guess that you have lots of them, but that would only be a guess.

In this second scenario, you really want to distribute your likely responses into 256 "percentiles" and assign a color to each one (where an equal number of likely responses fall into each percentile).

0
ответ дан 2 December 2019 в 04:43
поделиться

Ask yourself the question, "What value should map to 128?" Если ответ - около миллиарда (я сомневаюсь, что это так), используйте линейный. Если ответ находится в диапазоне 10–100 тысяч, тогда рассмотрите квадратный корень или логарифм.

Другой ответ предложил это (я пока не могу комментировать или голосовать). Я согласен.

r = log (значение) / log (pow (2,32)) * 256

1
ответ дан 2 December 2019 в 04:43
поделиться

The linear implementation is discussed in most of these answers, and Artelius' answer seems to be the best. But the best formula would depend on what you are trying to achieve and the distribution of your values. Without knowing that it is difficult to give an ideal answer.

But just to illustrate, any of these might be the best for you:

  • Linear distribution, each mapping onto a range which is 1/266th of the overall range.
  • Logarithmic distribution (skewed towards low values) which will highlight the differences in the lower magnitudes and diminish differences in the higher magnitudes
  • Reverse logarithmic distribution (skewed towards high values) which will highlight differences in the higher magnitudes and diminish differences in the lower magnitudes.
  • Normal distribution of incidence of colours, where each colour appears the same number of times as every other colour.

Again, you need to determine what you are trying to achieve & what the data will be used for. If you have been tasked to build this then I would strongly recommend you get this clarified to ensure that it is as useful as possible - and to avoid having to redevelop it later on.

1
ответ дан 2 December 2019 в 04:43
поделиться

Значение, которое вы ищете: r = 255 * (value / Integer.MAX_VALUE). Таким образом, вам придется превратить это в двойное, а затем вернуть в int.

1
ответ дан 2 December 2019 в 04:43
поделиться

Это работает! r = значение / 8421504;

8421504 на самом деле является «магическим» числом, равным MAX_VALUE / 255. Таким образом, MAX_VALUE / 8421504 = 255 (и некоторые изменения, но достаточно мелкие целочисленные математические вычисления избавят от него.

если вам нужен тот, в котором нет магических чисел, это должно сработать (и с такой же производительностью, поскольку любой хороший компилятор заменит его фактическим значением:

r = value / (Integer.MAX_VALUE / 255);

Хорошая деталь в том, что это не потребует никаких значений с плавающей запятой.

2
ответ дан 2 December 2019 в 04:43
поделиться

Note that if you want brighter and brighter, that luminosity is not linear so a straight mapping from value to color will not give a good result.

The Color class has a method to make a brighter color. Have a look at that.

1
ответ дан 2 December 2019 в 04:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: