整数除以浮点数得到成比例的整数

Posted

技术标签:

【中文标题】整数除以浮点数得到成比例的整数【英文标题】:Dividing integers by floats resulting in proportional integers 【发布时间】:2015-02-09 01:33:36 【问题描述】:

最近我在做一个项目时遇到了一个很难解决的问题。我想请你们提供一个解决方案/算法来解决它,因为我真的很难想出一个聪明的主意。

我有任意数量的浮点数:

f1, f2, ..., fn 其中 f1 + f2 + ... + fn = 1

和一个整数:

I 其中 I > 0.

我需要将整数 I 分成浮点数,就好像我在分配不可分割的东西一样。所以基本上这个比例在某种意义上必须保持不变,最大的浮点数必须得到最大的整数。一个很好的比喻就像我在分割无法分割的股票。

如果第一个投资者持有 0.6% 的股票,第二个投资者持有 0.4% 的股票,给定 1 只股票要拆分,我会将其分配给第一个投资者(100% 0%)。如果有 2 只股票,我会给第一个,一个给第二个(50% 50%)。请注意,我始终希望拆分尽可能成比例(接近 60% 和 40%)。

问题本身并没有很明确的定义,但是对于应该发生什么和不应该发生什么有一定的认识。一些容易在我脑海中浮现的例子是:

    如果:f1 = 0.4, f2 = 0.3, f3 = 0.3, I = 1 那么我需要 f1-result = 1, f2-result = 0, f3-结果 = 0,

    如果:f1 = 0.4, f2 = 0.4, f3 = 0.2, I = 1 那么我需要 f1-result = 1, f2-result = 0, f3-结果 = 0 f1-result = 0, f2-result = 1, f3-result = 0

    如果:f1 = 0.6, f2 = 0.25, f3 = 0.15, I = 5 那么我需要 f1-result = 3, f2-result = 2, f3-结果 = 1

【问题讨论】:

看看从大选中的选票到席位,以找到从可理解到搞砸的方法。 【参考方案1】:

这就是我的处理方式,至少一开始是这样。

每个存储桶都有所需的数量。这是基于它们的浮点值,所有浮点值的总和为 1。

所以,将要分发的“对象”一一进行。要确定哪个桶得到它,您需要找到 低于 其所需数量最大差异的桶(如果有多个同样低于其所需水平,则选择第一个)。这是“最不开心的”桶。

然后您将该对象分配到该存储桶,调整数字并继续处理下一个对象。这意味着一个对象总是以这样的方式分布,让最不快乐的桶的生活变得更好一点(天哪,这听起来像我是一名社会工作者)。

作为示例,让我们开始根据上述算法将对象分配到三个存储桶(分别需要 50%、30% 和 20%)。

括号中的第二个数字是每个桶与其期望百分比的偏差,因此,在每个阶段,我们选择最低于期望水平的桶,最不快乐的桶(用*表示):

BucketA (50%)  BucketB (30%)  BucketC (20%)
-------------  -------------  -------------
 0 (0%,-50*)    0 (0%,-30)     0 (0%,-20)
 1 (100%,+50)   0 (0%,-30*)    0 (0%,-20)
 1 (50%,+0)     1 (50%,+20)    0 (0%,-20*)
 1 (33%,-17*)   1 (33%,+3)     1 (33%,+13)
 2 (50%,+0)     1 (25%,-5*)    1 (25%,+5)
 2 (40%,-10*)   2 (40%,+10)    1 (20%,+0)
 3 (50%,+0)     2 (33%,+3)     1 (17%,-3*)
 3 (43%,-7*)    2 (29%,-1)     2 (29%,+9)
 4 (50%,+0)     2 (25%,-5*)    2 (25%,+5)
 4 (44%,-6*)    3 (33%,+3)     2 (22%,+2)
 5 (50%,+0)     3 (30%,+0)     2 (20%,+0)

请注意,初始条件的所有存储桶都位于 0%,即使 技术上 不正确(根据未定义的除法,它可以很容易地被认为是 100% 甚至 3.14159% -按零计算性质)。但是,这是确保初始分配到需要最高百分比的存储桶的好方法,之后百分比变得明确。

您可以从上面的表格中看到,对象的分布最终会导致预期的结果。


而且,如果您想要一些可以玩的代码来查看它的实际效果(让我们面对现实,谁不会想要那个?),请参阅以下 Python 程序:

desiredPct = [50, 30, 20]
bucket = [0, 0, 0]
count = 0

# Allocate first item specially so no concern with div-by-zero.

idx = desiredPct.index(max(desiredPct))
happy_min = -desiredPct[idx]
bucket[idx] += 1
count += 1

actualPct = [x * 100 / count for x in bucket]
print "Unhappiest %6.2f @ %d, want %s%%, have %s (%s%%)" % (happy_min, idx, desiredPct, bucket, actualPct)

# Allocate all others in loop.

for i in range(99):
    # Get most disadvantaged bucket.

    idx = 0
    happy_min = bucket[idx] * 100 / sum(bucket) - desiredPct[idx]
    for j in range(1, len(bucket)):
        happy = bucket[j] * 100 / sum(bucket) - desiredPct[j]
        if happy < happy_min:
            idx = j
            happy_min = happy

    bucket[idx] += 1
    count += 1
    actualPct = [x * 100 / count for x in bucket]
    print "Unhappiest %6.2f @ %d, want %s%%, have %s (%s%%)" % (happy_min, idx, desiredPct, bucket, actualPct)

哪个输出:

Unhappiest -50.00 @ 0, want [50, 30, 20]%, have [1, 0, 0] ([100, 0, 0]%)
Unhappiest -30.00 @ 1, want [50, 30, 20]%, have [1, 1, 0] ([50, 50, 0]%)
Unhappiest -20.00 @ 2, want [50, 30, 20]%, have [1, 1, 1] ([33, 33, 33]%)
Unhappiest -17.00 @ 0, want [50, 30, 20]%, have [2, 1, 1] ([50, 25, 25]%)
Unhappiest  -5.00 @ 1, want [50, 30, 20]%, have [2, 2, 1] ([40, 40, 20]%)
Unhappiest -10.00 @ 0, want [50, 30, 20]%, have [3, 2, 1] ([50, 33, 16]%)
Unhappiest  -4.00 @ 2, want [50, 30, 20]%, have [3, 2, 2] ([42, 28, 28]%)
Unhappiest  -8.00 @ 0, want [50, 30, 20]%, have [4, 2, 2] ([50, 25, 25]%)
Unhappiest  -5.00 @ 1, want [50, 30, 20]%, have [4, 3, 2] ([44, 33, 22]%)
Unhappiest  -6.00 @ 0, want [50, 30, 20]%, have [5, 3, 2] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [6, 3, 2] ([54, 27, 18]%)
Unhappiest  -3.00 @ 1, want [50, 30, 20]%, have [6, 4, 2] ([50, 33, 16]%)
Unhappiest  -4.00 @ 2, want [50, 30, 20]%, have [6, 4, 3] ([46, 30, 23]%)
Unhappiest  -4.00 @ 0, want [50, 30, 20]%, have [7, 4, 3] ([50, 28, 21]%)
Unhappiest  -2.00 @ 1, want [50, 30, 20]%, have [7, 5, 3] ([46, 33, 20]%)
Unhappiest  -4.00 @ 0, want [50, 30, 20]%, have [8, 5, 3] ([50, 31, 18]%)
Unhappiest  -2.00 @ 2, want [50, 30, 20]%, have [8, 5, 4] ([47, 29, 23]%)
Unhappiest  -3.00 @ 0, want [50, 30, 20]%, have [9, 5, 4] ([50, 27, 22]%)
Unhappiest  -3.00 @ 1, want [50, 30, 20]%, have [9, 6, 4] ([47, 31, 21]%)
Unhappiest  -3.00 @ 0, want [50, 30, 20]%, have [10, 6, 4] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [11, 6, 4] ([52, 28, 19]%)
Unhappiest  -2.00 @ 1, want [50, 30, 20]%, have [11, 7, 4] ([50, 31, 18]%)
Unhappiest  -2.00 @ 2, want [50, 30, 20]%, have [11, 7, 5] ([47, 30, 21]%)
Unhappiest  -3.00 @ 0, want [50, 30, 20]%, have [12, 7, 5] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [12, 8, 5] ([48, 32, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [13, 8, 5] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [13, 8, 6] ([48, 29, 22]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [14, 8, 6] ([50, 28, 21]%)
Unhappiest  -2.00 @ 1, want [50, 30, 20]%, have [14, 9, 6] ([48, 31, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [15, 9, 6] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [16, 9, 6] ([51, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [16, 10, 6] ([50, 31, 18]%)
Unhappiest  -2.00 @ 2, want [50, 30, 20]%, have [16, 10, 7] ([48, 30, 21]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [17, 10, 7] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [17, 11, 7] ([48, 31, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [18, 11, 7] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [18, 11, 8] ([48, 29, 21]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [19, 11, 8] ([50, 28, 21]%)
Unhappiest  -2.00 @ 1, want [50, 30, 20]%, have [19, 12, 8] ([48, 30, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [20, 12, 8] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [21, 12, 8] ([51, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [21, 13, 8] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [21, 13, 9] ([48, 30, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [22, 13, 9] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [22, 14, 9] ([48, 31, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [23, 14, 9] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [23, 14, 10] ([48, 29, 21]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [24, 14, 10] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [24, 15, 10] ([48, 30, 20]%)
Unhappiest  -2.00 @ 0, want [50, 30, 20]%, have [25, 15, 10] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [26, 15, 10] ([50, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [26, 16, 10] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [26, 16, 11] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [27, 16, 11] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [27, 17, 11] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [28, 17, 11] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [28, 17, 12] ([49, 29, 21]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [29, 17, 12] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [29, 18, 12] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [30, 18, 12] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [31, 18, 12] ([50, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [31, 19, 12] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [31, 19, 13] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [32, 19, 13] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [32, 20, 13] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [33, 20, 13] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [33, 20, 14] ([49, 29, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [34, 20, 14] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [34, 21, 14] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [35, 21, 14] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [36, 21, 14] ([50, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [36, 22, 14] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [36, 22, 15] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [37, 22, 15] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [37, 23, 15] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [38, 23, 15] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [38, 23, 16] ([49, 29, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [39, 23, 16] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [39, 24, 16] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [40, 24, 16] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [41, 24, 16] ([50, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [41, 25, 16] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [41, 25, 17] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [42, 25, 17] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [42, 26, 17] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [43, 26, 17] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [43, 26, 18] ([49, 29, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [44, 26, 18] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [44, 27, 18] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [45, 27, 18] ([50, 30, 20]%)
Unhappiest   0.00 @ 0, want [50, 30, 20]%, have [46, 27, 18] ([50, 29, 19]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [46, 28, 18] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [46, 28, 19] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [47, 28, 19] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [47, 29, 19] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [48, 29, 19] ([50, 30, 19]%)
Unhappiest  -1.00 @ 2, want [50, 30, 20]%, have [48, 29, 20] ([49, 29, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [49, 29, 20] ([50, 29, 20]%)
Unhappiest  -1.00 @ 1, want [50, 30, 20]%, have [49, 30, 20] ([49, 30, 20]%)
Unhappiest  -1.00 @ 0, want [50, 30, 20]%, have [50, 30, 20] ([50, 30, 20]%)

这也表明,一旦你第一次得到想要的结果,对象的分布往往会接近你想要的。

【讨论】:

【参考方案2】:

投资者j 应至少获得floor(fj*I) 股份。要分配多余的份额,首先确定它们的数量 (x = I - sum(floor(fj*I) for all j)),然后选择分数数组 fj*I - floor(fj*I) 中最大的 xth 元素。比这大一点的每个人都获得了更多的份额;正好有这个分数的人会根据需要得到 1 或 0,以使总数起作用。

运行时间为O(n),其中n为投资者数量。

【讨论】:

这将无法正常工作。假设您有 0.2 0.4 和 0.6,并且您必须拆分 3 只股票,然后您必须将 2 股股票分配给投资者,0.6 一只股票分配给 0.4 一只股票,0.3 一只股票分配给 0 股。您的分布 (33.3% 33.3% 33.3%) 与原始分布 (20% 40% 60%) 的距离为 (13.3 + 6.7 + 16.7 = 36.7),而遵循最佳分布则为 (0% 33.3% + 66.6 % ),其中距离为 (20 + 6.7 + 6.6 = 33.3)。 @ManoelRibeiro 不,这个算法不会平均分配份额。【参考方案3】:

您以 f1+f2+....+fn=1 开始问题,但最后只引用了三个浮点数。 解决这个问题的简单方法是将最小的 fi 乘以十的幂 (10^p) 以获得整数值。您从整数 (10^p) 中减去要分配的金额,以计算出您必须从每个浮点数中取回多少才能达到分配的金额,假设您将额外金额增加到 (10^p) 为每个人都有自己的分享时间(10^p)。 你通过一个重复的计划来做到这一点,首先你从每个浮动中收回超过分配金额的金额。在下一次迭代中,您从按升序排序的每个浮点数中收集一个单位,但您应该考虑不要变成负数。测试您是否在每次扣除后退还全部金额。

所以举个例子 f1=0.6,f2=0.25,f3=015,I=5。 用 f(i,j) 声明一个浮点矩阵 f,其中 i=3 和 j=2,它是一个两列三行的矩阵。将浮点数存储在第一列中并对矩阵升序排序。访问矩阵 f(1,1) 的第一个元素,我们得到 0.15。 将其转换为整数 It = f(1,1)* (10^(number of decimals(f(1,1))),我们得到 It=0.15*(10^2)。即 It=15。填充具有整数的矩阵第二列

f(1,2)=15
f(2,2)=25
f(3,2)=60

现在我必须取回 10^2-5=95 的数量。设置它 = 95。第一轮拥有超过 5 的每个人都会返还多余的部分。所以我得到以下(为了简化示例,我跳过了 f(i,2) > 5 的测试)

10 = f(1,2)-5; f(1,2)=f(1,2)-10
20 = f(2,2)-5; f(2,2)=f(2,2)-20 
55 = f(3,2)-5; f(3,2)=f(3,2)-55

直到知道我收回了 10+20+55=85。我得再买一个。现在每个人有五个。这是在三个迭代中完成的。循环的第一次第二次和第三次运行将得到一个单位,每个单位是 9 个单位。 现在我找回了 94 我仍然需要返回 一个单位,这将被 从 f(2,1) 和循环中收回当我达到我的 95 个单位时将退出。经过三次迭代和第四次迭代的一步后,我的最终矩阵是

  f(1,2)=1, 
  f(2,2)=2, 
  f(2,3)=2.

出于显而易见的原因,总和为 5 迭代算法很简单。它迭代 f(i,2)。测试是否f(i,s)>0,然后从f(i,2)中减去一个单位;将这一单位添加到到目前为止已索回的金额中,并测试该金额是否等于要退还的总金额。如果为真,它会打破循环。

【讨论】:

以上是关于整数除以浮点数得到成比例的整数的主要内容,如果未能解决你的问题,请参考以下文章

python浮点数陷阱

整数与浮点除法 -> 谁负责提供结果?

Java中怎么把浮点数转变成整数只保留整数部分

浮点型数据在内存中的存储

“/”在c语言中,若是小数除以整数,答案最后是取整,还是有小数呀😄?

解决浮点型数值计算精度丢失的一种实现