将数字向量舍入为整数,同时保留它们的总和 [英] Round vector of numerics to integer while preserving their sum

查看:42
本文介绍了将数字向量舍入为整数,同时保留它们的总和的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在保留其总和的同时将浮点数四舍五入为整数?有以下 answer 用伪代码编写,它将向量四舍五入为整数值,从而使元素的总和不变,并且舍入误差最小.我想在 R 中有效地实现这一点(即,如果可能的话,进行矢量化).

How to round floats to integers while preserving their sum? has the below answer written in pseudocode, which rounds a vector to integer values such that the sum of the elements in unchanged and the roundoff error is minimized. I'd like to implement this efficiently (i.e. vectorized if possible) in R.

例如,四舍五入这些数字会产生不同的总数:

For example, rounding these numbers yields a different total:

set.seed(1)
(v <- 10 * runif(4))
# [1] 2.655087 3.721239 5.728534 9.082078
(v <- c(v, 25 - sum(v)))
# [1] 2.655087 3.721239 5.728534 9.082078 3.813063
sum(v)
# [1] 25
sum(round(v))
# [1] 26

答案中复制伪代码以供参考

Copying pseudocode from answer for reference

// 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] + lowerBound
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")

推荐答案

用更简单的形式,我会说这个算法是:

In an even simpler form, I would say this algorithm is:

  1. 从四舍五入开始
  2. 将具有最高小数部分的数字四舍五入,直到达到所需的总和.

这可以通过以下方式在 R 中以矢量化方式实现:

This can be implemented in a vectorized way in R by:

  1. floor
  2. 向下舍入
  3. 按小数部分对数字进行排序(使用 order)
  4. 使用 tail 获取小数部分最大的 k 个元素的索引,其中 k 是我们需要增加总和以达到我们的目标值的数量
  5. 将每个索引中的输出值增加 1
  1. Round down with floor
  2. Order numbers by their fractional parts (using order)
  3. Use tail to grab the indices of the elements with the k largest fractional parts, where k is the amount that we need to increase the sum to reach our target value
  4. Increment the output value in each of these indices by 1

在代码中:

smart.round <- function(x) {
  y <- floor(x)
  indices <- tail(order(x-y), round(sum(x)) - sum(y))
  y[indices] <- y[indices] + 1
  y
}
v
# [1] 2.655087 3.721239 5.728534 9.082078 3.813063
sum(v)
# [1] 25
smart.round(v)
# [1] 2 4 6 9 4
sum(smart.round(v))
# [1] 25

这篇关于将数字向量舍入为整数,同时保留它们的总和的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆