简体   繁体   English

如何舍入整数除法的结果?

[英]How to round up the result of integer division?

I'm thinking in particular of how to display pagination controls, when using a language such as C# or Java.我特别考虑在使用 C# 或 Java 等语言时如何显示分页控件。

If I have x items which I want to display in chunks of y per page, how many pages will be needed?如果我想在每页y块中显示x 个项目,需要多少页?

Found an elegant solution:找到了一个优雅的解决方案:

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

Source: Number Conversion, Roland Backhouse, 2001资料来源:数字转换,Roland Backhouse,2001

Converting to floating point and back seems like a huge waste of time at the CPU level.在 CPU 级别转换为浮点数并返回似乎是一种巨大的时间浪费。

Ian Nelson's solution:伊恩纳尔逊的解决方案:

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

Can be simplified to:可以简化为:

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

AFAICS, this doesn't have the overflow bug that Brandon DuRette pointed out, and because it only uses it once, you don't need to store the recordsPerPage specially if it comes from an expensive function to fetch the value from a config file or something. AFAICS,这没有 Brandon DuRette 指出的溢出错误,并且因为它只使用一次,所以如果它来自一个昂贵的函数来从配置文件中获取值,则不需要专门存储记录 PerPage 或东西。

Ie this might be inefficient, if config.fetch_value used a database lookup or something:即这可能效率低下,如果 config.fetch_value 使用数据库查找或其他东西:

int pageCount = (records + config.fetch_value('records per page') - 1) / config.fetch_value('records per page');

This creates a variable you don't really need, which probably has (minor) memory implications and is just too much typing:这会创建一个您并不真正需要的变量,它可能具有(轻微的)内存影响,并且键入太多:

int recordsPerPage = config.fetch_value('records per page')
int pageCount = (records + recordsPerPage - 1) / recordsPerPage;

This is all one line, and only fetches the data once:这都是一行,并且只获取一次数据:

int pageCount = (records - 1) / config.fetch_value('records per page') + 1;

For C# the solution is to cast the values to a double (as Math.Ceiling takes a double):对于 C#,解决方案是将值转换为双精度值(因为 Math.Ceiling 采用双精度值):

int nPages = (int)Math.Ceiling((double)nItems / (double)nItemsPerPage);

In java you should do the same with Math.ceil().在 java 中,你应该对 Math.ceil() 做同样的事情。

This should give you what you want.这应该给你你想要的。 You will definitely want x items divided by y items per page, the problem is when uneven numbers come up, so if there is a partial page we also want to add one page.您肯定希望每页将 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);

The integer math solution that Ian provided is nice, but suffers from an integer overflow bug. Ian 提供的整数数学解决方案很好,但存在整数溢出错误。 Assuming the variables are all int , the solution could be rewritten to use long math and avoid the bug:假设变量都是int ,可以重写解决方案以使用long数学并避免错误:

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

If records is a long , the bug remains.如果recordslong ,则错误仍然存​​在。 The modulus solution does not have the bug.模数解没有这个bug。

A variant of Nick Berardi's answer that avoids a branch: Nick Berardi避免分支的答案的一个变体:

int q = records / recordsPerPage, r = records % recordsPerPage;
int pageCount = q - (-r >> (Integer.SIZE - 1));

Note: (-r >> (Integer.SIZE - 1)) consists of the sign bit of r , repeated 32 times (thanks to sign extension of the >> operator.) This evaluates to 0 if r is zero or negative, -1 if r is positive.注意: (-r >> (Integer.SIZE - 1))r的符号位组成,重复 32 次(感谢>>运算符的符号扩展。)如果r为零或负数,则计算结果为 0,- 1 如果r为正。 So subtracting it from q has the effect of adding 1 if records % recordsPerPage > 0 .因此,如果records % recordsPerPage > 0 ,则从q减去它会产生加 1 的效果。

In need of an extension method:需要扩展方法:

    public static int DivideUp(this int dividend, int divisor)
    {
        return (dividend + (divisor - 1)) / divisor;
    }

No checks here (overflow, DivideByZero , etc), feel free to add if you like.这里没有检查(溢出、 DivideByZero等),如果您愿意,可以随意添加。 By the way, for those worried about method invocation overhead, simple functions like this might be inlined by the compiler anyways, so I don't think that's where to be concerned.顺便说一下,对于那些担心方法调用开销的人来说,像这样的简单函数无论如何都可能被编译器内联,所以我认为这不是需要关注的地方。 Cheers.干杯。

PS you might find it useful to be aware of this as well (it gets the remainder): PS,您可能会发现意识到这一点也很有用(它会得到剩余部分):

    int remainder; 
    int result = Math.DivRem(dividend, divisor, out remainder);

HOW TO ROUND UP THE RESULT OF INTEGER DIVISION IN C#如何在 C# 中四舍五入整数除法的结果

I was interested to know what the best way is to do this in C# since I need to do this in a loop up to nearly 100k times.我很想知道在 C# 中执行此操作的最佳方法是什么,因为我需要在循环中执行此操作多达近 10 万次。 Solutions posted by others using Math are ranked high in the answers, but in testing I found them slow.其他人使用Math发布的解决方案在答案中排名靠前,但在测试中我发现它们很慢。 Jarod Elliott proposed a better tactic in checking if mod produces anything. Jarod Elliott 提出了一种更好的策略来检查 mod 是否产生任何东西。

int result = (int1 / int2);
if (int1 % int2 != 0) { result++; }

I ran this in a loop 1 million times and it took 8ms.我在循环中运行了 100 万次,花了 8 毫秒。 Here is the code using Math :这是使用Math的代码:

int result = (int)Math.Ceiling((double)int1 / (double)int2);

Which ran at 14ms in my testing, considerably longer.在我的测试中运行时间为 14 毫秒,相当长。

For records == 0, rjmunro's solution gives 1. The correct solution is 0. That said, if you know that records > 0 (and I'm sure we've all assumed recordsPerPage > 0), then rjmunro solution gives correct results and does not have any of the overflow issues.对于记录 == 0,rjmunro 的解决方案给出了 1。正确的解决方案是 0。也就是说,如果您知道记录 > 0(并且我确定我们都假设 recordPerPage > 0),那么 rjmunro 解决方案会给出正确的结果并且没有任何溢出问题。

int pageCount = 0;
if (records > 0)
{
    pageCount = (((records - 1) / recordsPerPage) + 1);
}
// no else required

All the integer math solutions are going to be more efficient than any of the floating point solutions.所有整数数学解决方案都将比任何浮点解决方案更有效。

Another alternative is to use the mod() function (or '%').另一种选择是使用 mod() 函数(或“%”)。 If there is a non-zero remainder then increment the integer result of the division.如果存在非零余数,则增加除法的整数结果。

I do the following, handles any overflows:我执行以下操作,处理任何溢出:

var totalPages = totalResults.IsDivisble(recordsperpage) ? totalResults/(recordsperpage) : totalResults/(recordsperpage) + 1;

And use this extension for if there's 0 results:如果有 0 个结果,请使用此扩展名:

public static bool IsDivisble(this int x, int n)
{
           return (x%n) == 0;
}

Also, for the current page number (wasn't asked but could be useful):此外,对于当前页码(没有被询问但可能有用):

var currentPage = (int) Math.Ceiling(recordsperpage/(double) recordsperpage) + 1;

您可以使用

(int)Math.Ceiling(((decimal)model.RecordCount )/ ((decimal)4));

Alternative to remove branching in testing for zero:在零测试中删除分支的替代方法:

int pageCount = (records + recordsPerPage - 1) / recordsPerPage * (records != 0);

Not sure if this will work in C#, should do in C/C++.不确定这是否适用于 C#,应该适用于 C/C++。

int result = (value - (value % divider) + divider) / divider;

A generic method, whose result you can iterate over may be of interest:您可以迭代其结果的通用方法可能会引起您的兴趣:

public static Object[][] chunk(Object[] src, int chunkSize) {

    int overflow = src.length%chunkSize;
    int numChunks = (src.length/chunkSize) + (overflow>0?1:0);
    Object[][] dest = new Object[numChunks][];      
    for (int i=0; i<numChunks; i++) {
        dest[i] = new Object[ (i<numChunks-1 || overflow==0) ? chunkSize : overflow ];
        System.arraycopy(src, i*chunkSize, dest[i], 0, dest[i].length); 
    }
    return dest;
}

The following should do rounding better than the above solutions, but at the expense of performance (due to floating point calculation of 0.5*rctDenominator):以下应该比上述解决方案更好地进行舍入,但以牺牲性能为代价(由于 0.5*rctDenominator 的浮点计算):

uint64_t integerDivide( const uint64_t& rctNumerator, const uint64_t& rctDenominator )
{
  // Ensure .5 upwards is rounded up (otherwise integer division just truncates - ie gives no remainder)
  return (rctDenominator == 0) ? 0 : (rctNumerator + (int)(0.5*rctDenominator)) / rctDenominator;
}

I had a similar need where I needed to convert Minutes to hours & minutes.我有一个类似的需求,我需要将分钟转换为小时和分钟。 What I used was:我用的是:

int hrs = 0; int mins = 0;

float tm = totalmins;

if ( tm > 60 ) ( hrs = (int) (tm / 60);

mins = (int) (tm - (hrs * 60));

System.out.println("Total time in Hours & Minutes = " + hrs + ":" + mins);

您需要进行浮点除法,然后使用天花板函数将值向上舍入为下一个整数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM