当前位置:  开发笔记 > 编程语言 > 正文

如何在保留总和的同时将浮点数舍入为整数?

如何解决《如何在保留总和的同时将浮点数舍入为整数?》经验,为你挑选了3个好方法。

假设我有一个浮点数数组,按排序(让我们说升序)排序,其总和已知是一个整数N.我希望将这些数字"舍入"为整数,同时保持其总和不变.换句话说,我正在寻找一种算法,将浮点数数组(称之为 fn)转换为整数数组(称之为in),这样:

    两个数组的长度相同

    整数数组的总和是 N

    每个浮点数fn[i]与其对应的整数之间的差值in[i]小于1(或者如果你真的必须等于1)

    假设浮点数按排序顺序(fn[i] <= fn[i+1]),整数也将按排序顺序(in[i] <= in[i+1])

鉴于满足这四个条件,sum((in[i] - fn[i])^2)最好将舍入方差()最小化的算法,但这并不是什么大问题.

例子:

[0.02, 0.03, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14]
    => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0.1, 0.3, 0.4, 0.4, 0.8]
    => [0, 0, 0, 1, 1]
[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
    => [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0.4, 0.4, 0.4, 0.4, 9.2, 9.2]
    => [0, 0, 1, 1, 9, 9] is preferable
    => [0, 0, 0, 0, 10, 10] is acceptable
[0.5, 0.5, 11]
    => [0, 1, 11] is fine
    => [0, 0, 12] is technically not allowed but I'd take it in a pinch

回答评论中提出的一些优秀问题:

两个数组都允许重复的元素(虽然我也有兴趣听说只有当浮点数不包含重复时才有效的算法)

没有一个正确的答案 - 对于给定的浮点数输入数组,通常有多个int数组满足这四个条件.

我想到的应用程序是 - 这有点奇怪 - 在MarioKart游戏中向顶级终结者分发点数;-)从来没有真正玩过这个游戏,但在看别人的时候我注意到有24个点分布在前4名选手,我想知道如何根据完成时间来分配积分(所以如果有人以较大的领先优势完成积分,他们会得到更多的积分).游戏将点总数跟踪为整数,因此需要进行这种舍入.


对于好奇,这是我用来确定哪些算法有效的测试脚本.



1> James Anders..:

您可以尝试的一个选项是"级联舍入".

对于此算法,您可以跟踪两个运行总计:到目前为止的一个浮点数,以及到目前为止的一个整数.要获得下一个整数,请将下一个fp编号添加到运行总计中,舍入运行总计,然后从舍入的运行总计中减去整数运行总计: -

number  running total   integer integer running total
   1.3       1.3          1           1
   1.7       3.0          2           3
   1.9       4.9          2           5
   2.2       8.1          3           8
   2.8      10.9          3          11
   3.1      14.0          3          14



2> Mikko Rantan..:

这是一个应该完成任务的算法.与其他算法的主要区别在于,这个算法总是以正确的顺序对数字进行舍入.最小化舍入误差.

该语言是一些伪语言,可能源自JavaScript或Lua.应该解释一下.注意一个基于索引(对于循环,x和y更好.:p)

// Temp array with same length as fn.
tempArr = Array(fn.length)

// Calculate the expected sum.
arraySum = sum(fn)

lowerSum = 0
-- Populate temp array.
for i = 1 to fn.lengthf
    tempArr[i] = { result: floor(fn[i]),              // Lower bound
                   difference: fn[i] - floor(fn[i]),  // Roundoff error
                   index: i }                         // Original index

    // Calculate the lower sum
    lowerSum = lowerSum + tempArr[i].result
end for

// Sort the temp array on the roundoff error
sort(tempArr, "difference")

// Now arraySum - lowerSum gives us the difference between sums of these
// arrays. tempArr is ordered in such a way that the numbers closest to the
// next one are at the top.
difference = arraySum - lowerSum

// Add 1 to those most likely to round up to the next number so that
// the difference is nullified.
for i = (tempArr.length - difference + 1) to tempArr.length
    tempArr.result = tempArr.result + 1
end for

// Optionally sort the array based on the original index.
array(sort, "index")



3> ojblass..:

一个非常简单的方法是采用所有小数部分并总结它们.根据您的问题定义,该数字必须是整数.从最大的数字开始均匀地分配整数.然后给一个第二大数字......等等,直到你用完了要分发的东西.

请注意,这是伪代码...并且可能在索引中被一个人关闭......它已经晚了,我很困.

float accumulator = 0;

for (i = 0; i < num_elements; i++)  /* assumes 0 based array */
{
   accumulator += (fn[i] - floor(fn[i])); 
   fn[i] =  (fn[i] - floor(fn[i]);
}

i = num_elements;

while ((accumulator > 0) && (i>=0))
{
    fn[i-1] += 1;   /* assumes 0 based array */
    accumulator -= 1;
    i--;
}

更新:根据对每个值执行了多少截断,还有其他分配累积值的方法.这需要保留一个名为loss [i] = fn [i] - floor(fn [i])的单独列表.然后,您可以重复fn [i]列表并重复给出最大损失项1(之后将损失[i]设置为0).它很复杂,但我猜它有效.


嗯,我认为从最大的下降你会按照定义保持排序顺序...我错过了什么?例?
推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有