比例数<= 255?

我有一些单元格,其数值可以是介于0和Integer.MAX_VALUE之间的任何值。 我想相应地对这些单元格进行颜色编码。

如果值= 0,那么r = 0.如果值是Integer.MAX_VALUE ,则r = 255.但是它们之间的值怎么样?

我想我需要一个函数,其限制为x => Integer.MAX_VALUE为255.这个函数是什么? 或者有更好的方法吗?

我可以这样做(value / (Integer.MAX_VALUE / 255))但这将导致许多低值为零。 所以也许我应该用日志function来做。

我的大多数值都在[0,10,000]范围内。 所以我想强调那里的差异。

我认为日志适合对此有好处,但看结果,我不太确定。

但是, Wolfram | Alpha非常适合尝试这类事情 :

我从那开始,结果是:

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

有趣的是,事实certificate,这给Artelius的答案提供了几乎相同的结果:

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

恕我直言,你最好配备0-10000和10000-2 ^ 31的分割function。

“最公平”的线性缩放实际上是这样完成的:

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

请注意,这只是伪代码并假设浮点计算。

如果我们假设Integer.MAX_VALUE + 1是2 ^ 31,那个/将给我们整数除法,那么它简化为

 value / 8388608 

为什么其他答案是错误的

一些答案(以及问题本身)表明(255 * value / Integer.MAX_VALUE) 。 据推测,这必须使用round()floor()转换为整数。

如果使用floor() ,则产生255的唯一value是Integer.MAX_VALUE本身。 这种分布不均匀。

如果使用round() ,0和255将每次击中的次数是1-254的一半。 也不均匀。

使用上面提到的缩放方法,不会出现这样的问题。

非线性方法

如果要使用日志,请尝试以下操作:

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

你也可以只取值的平方根(这不会一直到255,但你可以根据需要扩展它)。

对于范围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 

编辑 :Yikes,我的高中代数老师Buckenmeyer夫人会晕倒! log(pow(2,32))32*log(2) ,评估便宜得多。 现在我们也可以更好地考虑这个因素,因为256/32甚至是8:

 r = 8 * log(value)/log(2) 

log(value)/log(2)实际上是log-base-2 of value ,这个日志非常巧妙地为我们做了:

 r = 8 * log(value,2) 

Buckenmeyer夫人 – 你的努力并没有完全浪费!

一般情况下(因为我不清楚这是一个Java还是语言不可知的问题),你可以将你的值除以Integer.MAX_VALUE ,乘以255并转换为整数。

这有效! r= value /8421504;

8421504实际上是’魔术’数字,等于MAX_VALUE / 255。 因此,MAX_VALUE / 8421504 = 255(和一些变化,但足够小的整数数学将摆脱它。

如果你想要一个没有幻数的那个,这应该有效(并且具有相同的性能,因为任何好的编译器都会用实际值替换它:

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

好的部分是,这不需要任何浮点值。

您要查找的值是:r = 255 *(value / Integer.MAX_VALUE)。 所以你必须把它变成一个double,然后再转换成int。

请注意,如果您想要更亮更明亮,那么该亮度不是线性的,因此从值到颜色的直线映射不会产生良好的结果。

Color类有一种方法可以使颜色更亮。 看看那个。

大多数答案都讨论了线性实现,Artelius的答案似乎是最好的。 但最好的公式将取决于您要实现的目标和价值的分配。 不知道很难给出理想的答案。

但只是为了说明,其中任何一个可能是最适合你的:

  • 线性分布,每个映射到整个范围的1/265的范围。
  • 对数分布(倾向于低值),这将突出较低幅度的差异并减少较高幅度的差异
  • 反向对数分布(偏向高值),这将突出较高幅度的差异并减少较低幅度的差异。
  • 颜色入射的正态分布,其中每种颜色与每种其他颜色出现的次数相同。

同样,您需要确定您要实现的目标以及将使用的数据。 如果你的任务是建立这个,那么我强烈建议你澄清它,以确保它尽可能有用 – 并避免以后必须重新开发。

问自己一个问题,“应该映射到128的什么值?” 如果答案是大约十亿(我怀疑它是),那么使用线性。 如果答案在10-100万之间,则考虑平方根或日志。

另一个答案表明了这一点(我无法评论或投票)。 我同意。

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

以下是使用C#中的扩展方法进行缩放,规范化,排序等数字的一系列算法,尽管您可以将它们调整为其他语言:

http://www.redowlconsulting.com/Blog/post/2011/07/28/StatisticalTricksForLists.aspx

有解释和图形可以解释您何时可能想要使用一种方法或另一种方法。

最佳答案实际上取决于您想要的行为。

如果您希望每个单元格的颜色通常与邻居不同,请使用akf第二段中所述的内容并使用模数(x%256)。

如果你想让颜色与实际值有一些关系(比如“蓝色意味着较小的值”,一直到“红色意味着巨大的价值”),你就必须发布一些关于你预期的价值分布的东西。 既然你担心许多低值为零,我可能会猜到你有很多这些值,但这只是猜测。

在第二种情况下,您确实希望将可能的响应分配到256“百分位数”并为每个响应分配一种颜色(其中相同数量的可能响应落入每个百分位数)。

如果您抱怨低数字变为零,那么您可能希望将值标准化为255而不是整个值范围。

该公式将成为:

currentValue /(集合的最大值)

我可以这样做(值/(Integer.MAX_VALUE / 255)),但这将导致许多低值为零。

您可以采用的一种方法是使用模运算符( r = value%256; )。 虽然这不能确保Integer.MAX_VALUE结果为255,但它可以保证0到255之间的数字。它还允许在0-255范围内分配低数字。

编辑:

有趣的是,当我测试它时, Integer.MAX_VALUE % 256确实导致了255 (我最初错误地测试了%255 ,这产生了错误的结果)。 这似乎是一个非常直接的解决方案。