【问题标题】:Evenly divide a dollar amount (decimal) by an integer将美元金额(十进制)除以整数
【发布时间】:2011-01-03 14:36:13
【问题描述】:

我需要为我正在构建的程序编写一个会计例程,它可以将小数除以整数。例如:

$143.13 / 5 =

28.62
28.62
28.63
28.63
28.63

我在这里看过这篇文章:Evenly divide in c#,但它似乎只适用于整数除法。对这个问题的优雅解决方案有任何想法吗?

【问题讨论】:

  • 只需要整数除法。你不应该用花车来赚钱。
  • 十进制是此处使用的正确类型(不同于浮点数)
  • 阅读这个问题的答案:stackoverflow.com/questions/61872/…
  • 他可能的意思是:将 141.13 存储为 14113 (int),只是为了显示目的而对其进行不同的格式化,或者在最后转换为浮点数。 C# 中有 Money 类吗?
  • 处理金钱并使用浮点数进行除法?你应该看Office Space

标签: c# division accounting


【解决方案1】:

一次计算一个金额,然后从总数中减去每个金额,以确保您始终拥有正确的总数:

decimal total = 143.13m;
int divider = 5;
while (divider > 0) {
  decimal amount = Math.Round(total / divider, 2);
  Console.WriteLine(amount);
  total -= amount;
  divider--;
}

结果:

28,63
28,62
28,63
28,62
28,63

【讨论】:

  • 非常酷!当然,在 Contract.Requires(total > = 0), ... divider > 0 或任何语法上打一巴掌,以使其更加整洁。然后我会对这个东西进行单元测试到死……没有伤害。单元测试不需要跑得很快,所以得到一个答案,然后对其进行排序,并与预期的结果进行比较。另外,我会在实际实现中返回金额而不是打印它。我想我会添加另一个函数,它将结果作为...小数的数组返回。由于您知道分隔符,因此您可以分配所需的确切大小的数组。
  • 简单但对大分隔线无效。
  • @Immortal: 是的,仅仅为了获取值,循环执行它是无效的,但是如果你要循环遍历它们,它是非常有效的。
【解决方案2】:

你可以在不构造数组的情况下解决这个问题(以美分为单位):

int a = 100 * amount;
int low_value = a / n;
int high_value = low_value + 1;
int num_highs = a % n;
int num_lows = n - num_highs;

【讨论】:

  • 不知道为什么我是第一个投票的人。我认为这是最直观、最有效的方法。
  • +1。这在数据库功能中对我来说非常有效,而其他基于循环的解决方案将成为性能问题。
【解决方案3】:

处理美分更容易。我建议您将 14313 分成 5 个相等的部分,而不是 143.13。这给了你 2862 和 3 的余数。你可以将这个余数分配给前三个部分或任何你喜欢的方式。最后,将美分换回美元。

还要注意,您得到的余数总是少于您想要的零件数。

【讨论】:

    【解决方案4】:

    首先,请确保您不使用浮点数来表示美元和美分(请参阅其他帖子了解原因,但简单的原因是并非所有十进制数都可以表示为浮点数,例如 $1.79) .

    这是一种方法:

    decimal total = 143.13m;
    int numberOfEntries = 5;
    decimal unadjustedEntryAmount = total / numberOfEntries;
    decimal leftoverAmount = total - (unadjustedEntryAmount * numberOfEntries);
    int numberOfPenniesToDistribute = leftoverAmount * 100;
    int numberOfUnadjustedEntries = numberOfEntries - numberOfPenniesToDistribute;
    

    所以现在你有 28.62 的未调整数量,然后你必须决定如何分配剩余部分。您可以从顶部或底部开始向每个人分配额外的一分钱(看起来像您想要的从底部开始)。

    for (int i = 0; i < numberOfUnadjustedEntries; i++) {
      Console.WriteLine(unadjustedEntryAmount);
    }
    
    for (int i = 0; i < numberOfPenniesToDistribute; i++) {
      Console.WriteLine(unadjustedEntryAmount + 0.01m);
    }
    

    您还可以将整个余数添加到第一个或最后一个条目中。最后,根据会计需要,您还可以为剩余部分创建单独的交易。

    【讨论】:

      【解决方案5】:

      如果你有一个浮点数可以保证精确到两位数的精度,那么这个(伪代码)呢:

      amount = amount * 100 (convert to cents)
      int[] amounts = new int[divisor]
      for (i = 0; i < divisor; i++) amounts[i] = amount / divisor
      extra = amount % divisor
      for (i = 0; i < extra; i++) amounts[i]++
      

      然后用 amounts 做任何你想做的事情,单位是美分 - 如果你绝对需要的话,你可以转换回浮点数,或者格式化为美元和美分。

      如果不清楚,那么所有这些的重点不仅仅是平均分配浮动价值,而是尽可能平均分配货币金额,因为美分是美元的不可分割单位。致 OP:如果这不是您想要的,请告诉我。

      【讨论】:

      • float is bad bad bad... 永远不应该为了钱而推荐浮动
      • OP 说他从花车开始不是我的错。如果您费心阅读我的回复,而不是盲目地修改,您会看到我立即转换为 int。
      【解决方案6】:

      您可以通过乘以 100,使用整数除法函数,然后将每个结果除以 100 来使用您所引用的问题中的算法(假设您只想处理 2 dp,如果您想要 3dp乘以 1000 等)

      【讨论】:

      • 与尼克的回应一样,这将损失几美分(在给定的示例中)
      【解决方案7】:

      也可以使用C#迭代器生成,让Guffa's answer更方便:

      public static IEnumerable<decimal> Divide(decimal amount, int numBuckets)
      {
          while(numBuckets > 0)
          {
              // determine the next amount to return...
              var partialAmount = Math.Round(amount / numBuckets, 2);
              yield return partialAmount;
              // reduce th remaining amount and #buckets
              // to account for previously yielded values
              amount -= partialAmount;
              numBuckets--;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-17
        • 1970-01-01
        相关资源
        最近更新 更多