我想规范化一个浮点数的数组,使得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中,但可能没关系。
答案 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