规范化浮点数数组,使得和恰好为1.0

时间:2016-11-20 06:47:12

标签: javascript

我想规范化一个浮点数的数组,使得sum总和为1.0。即使在归一化之后,如果总和不是1.0,则应该最小地调整输入数字,使得总和恰好为1.0。问题是,究竟应该是什么小改变?

我尝试了一种简单的方法,将所有数字相加,然后除以总和。但这并不总是有效。我还尝试将第一个数字的值设置为1.0 - 其他数字的总和,但这也不会一直有效。

使用随机搜索我发现了一些这样的值的例子:

[0.28929993489784822103, 0.31008623188441802876, 0.19065357835268603726, 0.20996025486504751867]
[0.27449260698927169244, 0.26390952678124363073, 0.14345190180088057685, 0.31814596442860426651]
[0.28999999999999998002, 0.28999999999999998002, 0.29999999999999998890, 0.11999999999999999556]
[0.41999999999999998446, 0.14999999999999999445, 0.30999999999999999778, 0.13000000000000000444]
[0.29000000000000003553, 0.29000000000000003553, 0.29999999999999982236, 0.12000000000000000944]
[0.30693069306930698126, 0.28712871287128693965, 0.28712871287128716169, 0.11881188118811883414]

最好是在JavaScript中,但可能没关系。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。我的求和是有问题的,并累积了一个错误,然后导致规范化行为不端。切换到Kahan summation algorithm后,我无法使用随机搜索找到反例。

我现在的完整算法(在CoffeeScript中):

preciseSum: (values...) ->
  values = _.flatten values

  sum = 0.0
  compensation = 0.0
  for value in values
    valueWithCompensation = value - compensation
    temp = sum + valueWithCompensation
    compensation = (temp - sum) - valueWithCompensation
    sum = temp

  sum

normalize: (values) ->
  if values.length is 1
    values[0] = 1.0
  else if values.length
    sum = 0.0
    i = 0
    while sum isnt 1.0
      assert i < 100
      i++

      sum = preciseSum values

      if sum is 0.0
        for value, j in values
          values[j] = 1.0
        continue

      for value, j in values
        values[j] = value / sum

      sum = preciseSum values

      if sum isnt 1.0
        partialSum = preciseSum values[1..]
        values[0] = 1.0 - partialSum

        sum = preciseSum values

  values