如何整理整数除法的结果?

Ian*_*son 317 c# java math

在使用C#或Java等语言时,我正在考虑如何显示分页控件.

如果我想要以每页y块的形式显示x项,那么需要多少页?

Ian*_*son 454

找到优雅的解决方案:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Run Code Online (Sandbox Code Playgroud)

资料来源:编号转换,Roland Backhouse,2001年

  • Obvious先生说:记住要确保recordsPerPage不为零 (27认同)
  • -1因为[Brandon DuRette]指出的溢出错误(http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division/96921#96921) (11认同)
  • 干得好,我不敢相信C#没有整数上限. (5认同)
  • 是的,在这里,我在2017年中期在尝试了几个更复杂的方法后遇到了这个伟大的答案. (2认同)
  • 对于具有适当欧几里得除法运算符的语言(例如 Python),更简单的方法是 `pageCount = -((-records) // recordsPerPage)`。 (2认同)

rjm*_*nro 185

转换为浮点和返回似乎是CPU级别的大量浪费时间.

伊恩·尼尔森的解决方案:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Run Code Online (Sandbox Code Playgroud)

可以简化为:

int pageCount = (records - 1) / recordsPerPage + 1;
Run Code Online (Sandbox Code Playgroud)

AFAICS,这没有Brandon DuRette指出的溢出错误,并且因为它只使用它一次,如果它来自一个昂贵的函数来从配置文件中获取值,则不需要特别存储recordsPerPage或一些东西.

即如果config.fetch_value使用数据库查找或其他东西,这可能效率低下:

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');
Run Code Online (Sandbox Code Playgroud)

这会创建一个你并不真正需要的变量,它可能具有(次要)内存含义并且输入太多:

int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;
Run Code Online (Sandbox Code Playgroud)

这是一行,只获取一次数据:

int pageCount = (records - 1) / config.fetch_value('records per page') + 1;
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这两个解决方案不会为零记录返回相同的pageCount.此简化版本将返回1 pageCount为零记录,而Roland Backhouse版本返回0 pageCount.如果这是你想要的,那很好,但是当用C#/ Java样式整数除法执行时,这两个等式不相等. (25认同)
  • 从Nelson解决方案改为简化时,人们扫描它和丢失的bodmas的清晰度很小(就像我第一次做的那样!),括号的简化是... int pageCount =((records-1)/ recordsPerPage) + 1; (9认同)
  • +1,零记录仍然返回1 pageCount的问题实际上很方便,因为我仍然想要1页,显示"没有记录符合你的标准"的占位符/假行,有助于避免任何"0页计数"问题你使用的分页控制. (5认同)
  • @Ian,这个答案并不总是返回 1。如果您的记录每页为“1”并且有 0 条记录,它可以返回 0:`-1 / 1 + 1 = 0`。虽然这不是非常常见的情况,但如果您允许用户调整页面大小,请务必记住。因此,要么不允许用户将页面大小设置为 1,要么检查页面大小,要么两者兼而有之(可能最好避免意外行为)。 (2认同)

Hup*_*pie 73

对于C#,解决方案是将值转换为double(因为Math.Ceiling需要一个double):

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);
Run Code Online (Sandbox Code Playgroud)

在java中,您应该对Math.ceil()执行相同的操作.

  • 因为效率极低 (12认同)
  • 它可能效率低下但很容易理解.鉴于计算页数通常每次请求一次,任何性能损失都无法衡量. (6认同)
  • 除非是快速循环,否则我会快速阅读. (6认同)
  • 当op明确要求C#时,为什么这个答案到目前为止呢? (3认同)
  • 它的可读性几乎不比这个“(dividend + (divisor - 1)) / divisor;” 而且它很慢并且需要数学库。 (3认同)
  • 你还需要将输出转换为`int`,因为`Math.Ceiling`返回一个`double`或`decimal`,具体取决于输入类型. (2认同)

Nic*_*rdi 67

这应该给你你想要的.您肯定希望x项目除以每页y项目,问题是当出现不均匀的数字时,所以如果有部分页面,我们还想添加一个页面.

int x = number_of_items;
int y = items_per_page;

// with out library
int pages = x/y + (x % y > 0 ? 1 : 0)

// with library
int pages = (int)Math.Ceiling((double)x / (double)y);
Run Code Online (Sandbox Code Playgroud)

  • x/y + !!(x%y)避免了类C语言的分支.可能性很好,但是,无论如何,你的编译器正在这样做. (5认同)
  • 像上面的答案一样没有溢出的+1 ...尽管将ints转换为仅为Math.ceiling而再返回的双打在性能敏感代码中是一个坏主意. (2认同)
  • @RhysUlerich在c#中不起作用(不能直接将int转换为bool).rjmunro的解决方案是我认为避免分支的唯一方法. (2认同)

Bra*_*tte 18

Ian提供的整数数学解决方案很好,但是遇到整数溢出错误.假设变量都是变量int,可以重写解决方案以使用long数学并避免错误:

int pageCount = (-1L + records + recordsPerPage) / recordsPerPage;

如果recordslong,则错误仍然存​​在.模数解决方案没有错误.

  • @rjmunro,[这里的真实示例](http://code.google.com/p/guava-libraries/issues/detail?id=616) (6认同)
  • 是的,我在指出这个错误时很迂腐.许多错误可以永久存在而不会造成任何问题.在有人报告它之前,JDK实现binarySearch已存在相同形式的错误九年(http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly的.html).我想问题是,不管你遇到这个bug的可能性有多大,为什么不预先修好呢? (5认同)
  • 我不认为你在实际情况中会遇到这个错误.2 ^ 31条记录需要翻页. (4认同)
  • 此外,应该注意的是,不仅仅是分页的元素数量,它也是页面大小.因此,如果您正在构建库并且有人选择不通过传递2 ^ 31-1(Integer.MAX_VALUE)作为页面大小来进行分页,则会触发该错误. (4认同)

fin*_*nnw 7

尼克·贝拉尔迪(Nick Berardi)回答的一个变种,它避免了一个分支:

int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));
Run Code Online (Sandbox Code Playgroud)

注意:(-r >> (Integer.SIZE - 1))由符号位组成r,重复32次(由于>>运算符的符号扩展.)如果r为零或负,则计算结果为0 ,如果r为正,则计算结果为-1 .所以从中减去它会q增加1 if的效果records % recordsPerPage > 0.


Nic*_*sen 5

需要扩展方法:

    public static int DivideUp(this int dividend, int divisor)
    {
        return (dividend + (divisor - 1)) / divisor;
    }
Run Code Online (Sandbox Code Playgroud)

这里没有检查(溢出DivideByZero等),如果您愿意,可以随意添加。顺便说一下,对于那些担心方法调用开销的人来说,像这样的简单函数无论如何都可能被编译器内联,所以我认为这不是需要关注的地方。干杯。

PS,您可能会发现意识到这一点也很有用(它会得到剩余部分):

    int remainder; 
    int result = Math.DivRem(dividend, divisor, out remainder);
Run Code Online (Sandbox Code Playgroud)

  • Thash,你为什么不做一些有用的事情,比如添加一些额外的检查,然后如果数字是负数,而不是投票否决我的答案,并错误地做出一揽子声明:“这是不正确的”,而实际上这只是一个优势案件。我已经明确表示你应该先做其他检查:“这里没有检查(溢出、除零等),**如果你愿意,可以随意添加**。” (6认同)
  • 该问题提到“我正在特别考虑如何显示**分页控件**”,因此无论如何负数都会超出范围。再一次,做一些有用的事情,如果你愿意的话,建议额外的检查,这是一个团队合作的人。 (2认同)

tec*_*n23 5

如何在 C# 中四舍五入整数除法的结果

我很想知道在 C# 中执行此操作的最佳方法是什么,因为我需要在循环中执行此操作多达近 10 万次。其他人使用Math发布的解决方案在答案中排名靠前,但在测试中我发现它们很慢。Jarod Elliott 提出了一种更好的策略来检查 mod 是否产生任何东西。

int result = (int1 / int2);
if (int1 % int2 != 0) { result++; }
Run Code Online (Sandbox Code Playgroud)

我在循环中运行了 100 万次,花了 8 毫秒。这是使用Math的代码:

int result = (int)Math.Ceiling((double)int1 / (double)int2);
Run Code Online (Sandbox Code Playgroud)

在我的测试中运行时间为 14 毫秒,相当长。