【问题标题】:Scale numbers to be <= 255?比例数字 <= 255?
【发布时间】:2010-12-05 16:52:45
【问题描述】:

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

如果值 = 0,则 r = 0。如果值为 Integer.MAX_VALUE,则 r = 255。但是介于两者之间的值呢?

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

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

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

【问题讨论】:

  • 不确定投票结束的原因。对我来说,这似乎是一个真实(而且很好)的问题。
  • 如何将其标记为 java 和语言不可知论?
  • 我认为您可以将其标记为两者,因为可能存在通用解决方案(更好)和特定于 java 的解决方案(最佳)
  • 它与语言无关,因为有一个通用的解决方案,但我碰巧使用的语言是 Java。

标签: java language-agnostic math distribution


【解决方案1】:

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

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,但如果您愿意,可以按比例放大)。

【讨论】:

  • 当它是log(Integer.MAX_VALUE) 而不是log(Integer.MAX_VALUE + 1) 时效果更好。否则,每个结果都是 0,因为 log(Integer.MAX_VALUE) 是 NaN。
  • 也许批评者现在可以看到它是如何与语言无关的,即使编码器使用的是一种真正的语言
  • @Rosarch:好点。我可能在发布之前已经测试了我的代码,但是为什么我会因为如此微不足道的事情而打破我永远不会使用 Java 的誓言呢? ;) 不过,作为一名 C 程序员,我应该知道的更多...
  • Java 可以以任何方式被解释为唯一真正的语言的声明必须是故意的诱饵。这是如何获得投票的?
【解决方案2】:

我认为对数拟合会对此有好处,但看看结果,我不太确定。

但是,Wolfram|Alpha 非常适合 experimenting with this sort of thing:

我从那个开始,最后是:

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

有趣的是,事实证明这与 Artelius 的回答几乎相同:

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

恕我直言,最好使用 0-10000 和 10000-2^31 的拆分函数。

【讨论】:

  • 按照我下面的代数简化,我认为这可能对你有用:r(x) = floor((256./31) * log(x)/log(2))
  • 是的,这当然更简单,尽管与所需值相比,它仍然存在不合适的问题。
【解决方案3】:

对于 0-2^32 到 0-255 范围的线性映射,只需取高位字节即可。下面是使用二进制 &amp; 和位移的样子:

r = value & 0xff000000 >> 24

使用 mod 256 肯定会返回一个 0-255 的值,但您将无法从结果中得出任何分组意义 - 1、257、513、1025 都将映射到缩放后的值 1,即使它们相距甚远从彼此。

如果您想更好地区分低值,并将更多大值合并在一起,那么日志表达式将起作用:

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

编辑:哎呀,我的高中代数老师 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 夫人 - 您的努力并没有完全白费!

【讨论】:

  • 糟糕,抱歉,我在那里滑入了 Python。 java.math.log 不需要第二个参数,所以你被 log(value)/log(2) 卡住了。
【解决方案4】:

一般来说(因为我不清楚这是一个 Java 还是与语言无关的问题)你会将你拥有的值除以 Integer.MAX_VALUE,乘以 255 并转换为一个整数。

【讨论】:

  • 唯一的方法是在某一点强制转换为双精度,反之则更有效。
  • @Erich,但是你可能会溢出。
  • 先除法不会溢出!
  • 我就是这么做的。你说的“反其道而行之”是什么意思?
【解决方案5】:

这行得通! r= value /8421504;

8421504 实际上是“幻数”,等于 MAX_VALUE/255。因此,MAX_VALUE/8421504 = 255(还有一些变化,但足够小的整数数学会摆脱它。

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

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

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

【讨论】:

  • 怎么样? 0-Int.Max 的值将均匀分布在 0-255 之间,不是吗?
【解决方案6】:

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

【讨论】:

  • 呃,你说得对,我打字太快了。你本可以指定更正,但我抓住了你的微妙线索并照做了。
  • @Artelius:是的,你可以。再次单击否决票(而不是向上投票箭头)
  • 我已经编辑了帖子,你现在应该可以撤销你的投票了。
  • 哈哈,没关系,这就是我在不阅读我输入的内容的情况下单击添加评论得到的结果。
【解决方案7】:

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

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

【讨论】:

    【解决方案8】:

    这些答案中的大多数都讨论了线性实现,而 Artelius 的答案似乎是最好的。但最好的公式取决于你想要达到的目标以及你的价值观的分布。不知道很难给出一个理想的答案。

    但只是为了说明,以下任何一种都可能最适合您:

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

    同样,您需要确定您想要实现的目标以及数据的用途。如果您的任务是构建它,那么我强烈建议您澄清它,以确保它尽可能有用 - 并避免以后重新开发它。

    【讨论】:

      【解决方案9】:

      问自己一个问题,“什么值应该映射到 128?” 如果答案大约是十亿(我怀疑是这样),那么使用线性。 如果答案在 10-10 万范围内,则考虑平方根或对数。

      另一个答案建议了这一点(我还不能评论或投票)。我同意。

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

      【讨论】:

        【解决方案10】:

        这里有一堆算法,用于在 C# 中使用扩展方法对数字进行缩放、规范化、排名等,尽管您可以将它们调整为其他语言:

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

        有一些说明和图形说明您何时可能想要使用一种或另一种方法。

        【讨论】:

          【解决方案11】:

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

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

          如果您希望颜色对实际值有一定影响(例如“蓝色表示较小的值”一直到“红色表示较大的值”),您必须发布一些有关您预期的值分布的信息。由于您担心许多低值为零,我可能会猜测您有很多它们,但这只是一个猜测。

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

          【讨论】:

            【解决方案12】:

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

            公式将变为:

            currentValue /(集合的最大值)

            【讨论】:

              【解决方案13】:

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

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

              编辑:

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

              【讨论】:

              • 它没有明确说明,但似乎暗示颜色应该对相似的值进行分组 - 即如果两个单元格共享一种颜色,那么它们的值将大致相等。在您的回答中,颜色与值的大小无关。
              • Kirk,我同意将相似值分配到桶中的想法是一个的想法。 OP似乎也对其他解决方案持开放态度。然而,似乎大多数回答者都将相似值的分组作为唯一的解决方案。
              猜你喜欢
              • 2014-05-01
              • 2021-03-28
              • 1970-01-01
              • 2014-10-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-12-15
              相关资源
              最近更新 更多