如何确保整数的除法总是四舍五入? [英] How can I ensure that a division of integers is always rounded up?

查看:31
本文介绍了如何确保整数的除法总是四舍五入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果需要,我想确保整数的除法总是四舍五入.还有比这更好的方法吗?有很多演员在进行.:-)

I want to ensure that a division of integers is always rounded up if necessary. Is there a better way than this? There is a lot of casting going on. :-)

(int)Math.Ceiling((double)myInt1 / myInt2)

推荐答案

UPDATE:这个问题是 我 2013 年 1 月博客的主题.谢谢你的好问题!

UPDATE: This question was the subject of my blog in January 2013. Thanks for the great question!

让整数算术正确很难.正如迄今为止充分证明的那样,当你尝试做一个聪明"的把戏时,你犯错的可能性很大.当发现缺陷时,更改代码以修复缺陷而不考虑修复是否破坏其他东西并不是一个好的解决问题的技术.到目前为止,我们已经发布了五种不同的错误整数算术解决方案来解决这个完全不是特别困难的问题.

Getting integer arithmetic correct is hard. As has been demonstrated amply thus far, the moment you try to do a "clever" trick, odds are good that you've made a mistake. And when a flaw is found, changing the code to fix the flaw without considering whether the fix breaks something else is not a good problem-solving technique. So far we've had I think five different incorrect integer arithmetic solutions to this completely not-particularly-difficult problem posted.

处理整数算术问题的正确方法——即增加第一次得到正确答案的可能性的方法——是仔细处理问题,一步一步地解决它,并使用良好的工程这样做的原则.

The right way to approach integer arithmetic problems -- that is, the way that increases the likelihood of getting the answer right the first time - is to approach the problem carefully, solve it one step at a time, and use good engineering principles in doing so.

首先阅读您要替换的内容的规范.整数除法的规范明确指出:

Start by reading the specification for what you're trying to replace. The specification for integer division clearly states:

  1. 除法将结果向零舍入

  1. The division rounds the result towards zero

当两个操作数符号相同时结果为零或正数,当两个操作数符号相反时结果为零或负数

The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs

如果左操作数是可表示的最小整数,右操作数是–1,则发生溢出.[...] 它是实现定义的,关于是否抛出 [an ArithmeticException] 或溢出未报告,结果值是左操作数的值.

If the left operand is the smallest representable int and the right operand is –1, an overflow occurs. [...] it is implementation-defined as to whether [an ArithmeticException] is thrown or the overflow goes unreported with the resulting value being that of the left operand.

如果右操作数的值为零,则抛出 System.DivideByZeroException.

If the value of the right operand is zero, a System.DivideByZeroException is thrown.

我们想要的是一个整数除法函数,它计算商但将结果总是向上舍入,而不是总是向零舍入.

What we want is an integer division function which computes the quotient but rounds the result always upwards, not always towards zero.

所以为那个函数写一个规范.我们的函数int DivRoundUp(int credit, int divisor)必须为每个可能的输入定义行为.这种未定义的行为令人深感担忧,所以让我们消除它.我们会说我们的操作有这个规范:

So write a specification for that function. Our function int DivRoundUp(int dividend, int divisor) must have behaviour defined for every possible input. That undefined behaviour is deeply worrying, so let's eliminate it. We'll say that our operation has this specification:

  1. 如果除数为零则操作抛出

  1. operation throws if divisor is zero

如果被除数为 int.minval 且除数为 -1 则操作抛出

operation throws if dividend is int.minval and divisor is -1

如果没有余数——除法是偶数"——那么返回值就是整商

if there is no remainder -- division is 'even' -- then the return value is the integral quotient

否则它返回最小比商的整数,也就是说,它总是向上取整.

Otherwise it returns the smallest integer that is greater than the quotient, that is, it always rounds up.

现在我们有了一个规范,所以我们知道我们可以想出一个可测试的设计.假设我们添加了一个额外的设计标准,即仅使用整数算术来解决问题,而不是将商计算为双精度,因为在问题陈述中明确拒绝了双精度"解决方案.

Now we have a specification, so we know we can come up with a testable design. Suppose we add an additional design criterion that the problem be solved solely with integer arithmetic, rather than computing the quotient as a double, since the "double" solution has been explicitly rejected in the problem statement.

那么我们必须计算什么?显然,为了满足我们的规范,同时只停留在整数算术上,我们需要知道三个事实.首先,整数商是多少?第二,除法是否没有余数?第三,如果不是,整数商是通过向上还是向下舍入计算的?

So what must we compute? Clearly, to meet our spec while remaining solely in integer arithmetic, we need to know three facts. First, what was the integer quotient? Second, was the division free of remainder? And third, if not, was the integer quotient computed by rounding up or down?

既然我们有了规范和设计,我们就可以开始编写代码了.

Now that we have a specification and a design, we can start writing code.

public static int DivRoundUp(int dividend, int divisor)
{
  if (divisor == 0 ) throw ...
  if (divisor == -1 && dividend == Int32.MinValue) throw ...
  int roundedTowardsZeroQuotient = dividend / divisor;
  bool dividedEvenly = (dividend % divisor) == 0;
  if (dividedEvenly) 
    return roundedTowardsZeroQuotient;

  // At this point we know that divisor was not zero 
  // (because we would have thrown) and we know that 
  // dividend was not zero (because there would have been no remainder)
  // Therefore both are non-zero.  Either they are of the same sign, 
  // or opposite signs. If they're of opposite sign then we rounded 
  // UP towards zero so we're done. If they're of the same sign then 
  // we rounded DOWN towards zero, so we need to add one.

  bool wasRoundedDown = ((divisor > 0) == (dividend > 0));
  if (wasRoundedDown) 
    return roundedTowardsZeroQuotient + 1;
  else
    return roundedTowardsZeroQuotient;
}

这很聪明吗?不,漂亮吗?不.短?否.是否按照规范正确?我相信是这样,但我还没有对其进行全面测试.不过看起来还不错.

Is this clever? No. Beautiful? No. Short? No. Correct according to the specification? I believe so, but I have not fully tested it. It looks pretty good though.

我们是这里的专业人士;使用良好的工程实践.研究您的工具,指定所需的行为,首先考虑错误情况,然后编写代码以强调其明显的正确性.当您发现错误时,请在开始之前考虑您的算法是否存在严重缺陷只是随机开始交换比较的方向并打破已经有效的东西.

We're professionals here; use good engineering practices. Research your tools, specify the desired behaviour, consider error cases first, and write the code to emphasize its obvious correctness. And when you find a bug, consider whether your algorithm is deeply flawed to begin with before you just randomly start swapping the directions of comparisons around and break stuff that already works.

这篇关于如何确保整数的除法总是四舍五入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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