【问题标题】:how to always round up to the next integer [duplicate]如何始终向上舍入到下一个整数[重复]
【发布时间】:2011-01-31 00:05:44
【问题描述】:

我正在尝试查找在网站上构建寻呼机的总页数(所以我希望结果是一个整数。我得到一个记录列表,我想分成每页 10 个(页数)

当我这样做时:

list.Count() / 10

list.Count() / (decimal)10

list.Count() =12,我得到1 的结果。

我将如何编码,以便在这种情况下得到2(其余部分应始终添加1

【问题讨论】:

  • (list.Count()+9)/10 - 这是最好的:)
  • Math.Round(8.28, 0, MidpointRounding.AwayFromZero)

标签: c# language-agnostic rounding


【解决方案1】:
Math.Ceiling((double)list.Count() / 10);

【讨论】:

  • 对于这样一个简单的操作来说,将 int 转换为浮点是很糟糕的(而且很慢)
  • @Rob,你做......两次,int->floating point(double)->int。它需要对 CPU 进行两次刷新,解决方案是最坏的可能正确(对于 int 但不是 long)一个
  • 100万个周期的执行时间相差0.01ms。我认为处理时间增加如此微不足道的额外可读性是值得的。
  • @Rob - 不同之处不仅在于浮点转换,还有调用 Ceiling() 的额外函数调用开销。这不是“额外的可读性”,而是“额外的工作”,并且不是正确的方法。这个问题在 SO 上一遍又一遍地被问到,有一个更好的解决方案,它不涉及类型转换和额外的功能调用。新程序员需要学会以正确的方式去做。事实证明,正确地做是非常易读的,看到有人做错了,他们的所有代码都会受到质疑。
  • 这些人抱怨分页公式的基准... Rob 的回答是伴郎。它干净而简单,您不会在某些迭代中处理数百次...一旦您有了一个列表,您只需要知道页数,这种从 int 到 double 到 int 的类型转换大惊小怪是纳秒的时间总有一天,这可能会增加一秒钟的时间。甚至不值得花时间诚实地写下这条评论。有时甚至在此处或此处添加毫秒也是值得的。
【解决方案2】:

(list.Count() + 9) / 10

这里的所有其他内容要么是矫枉过正,要么就是错误的(bestsss' answer 除外,这太棒了)。我们确实想要函数调用的开销(Math.Truncate()Math.Ceiling() 等),只要简单的数学就足够了。


OP 的问题将 (pigeonhole principle) 概括为:

如果每个盒子里只有 y 对象,我需要多少个盒子来存储 x 对象?

解决办法:

  1. 源于最后一个框可能部分为空,并且
  2. (x + y - 1) ÷ y 使用integer division

你会记得在三年级数学中,当我们说5 ÷ 2 = 2 时,整数除法就是我们正在做的事情。

浮点除法是当我们说5 ÷ 2 = 2.5时,但我们在这里想要。

许多编程语言都支持整数除法。在从 C 派生的语言中,当您划分 int 类型(shortintlong 等)时,您会自动得到它。任何除法运算的余数/小数部分都被简单地删除,因此:

5 / 2 == 2

x = 5y = 2 替换我们原来的问题:

如果每个盒子里只有 2 个对象,我需要多少个盒子来存储 5 个对象?

现在答案应该很明显了:3 boxes -- 前两个盒子各装两个对象,最后一个盒子装一个。

(x + y - 1) ÷ y =
(5 + 2 - 1) ÷ 2 =
6 ÷ 2 =
3

所以对于原始问题,x = list.Count()y = 10,它给出了不使用额外函数调用的解决方案:

(list.Count() + 9) / 10

【讨论】:

  • 要么这是错误的,要么下面的陈述是错误的:113 + 4 / 5 = 23,4
  • 您的说法是错误的(实际上是 23,这正是我们想要的)。请参阅我修改后的答案。
  • 很好的解释
  • 为什么这个答案没有得到更多的认可,这超出了我的理解。这是迄今为止最优雅的解决方案。
  • 113 + 4 / 5 实际上是 113.8 或 114
【解决方案3】:

适当的基准或数字可能存在的方式

在关于Math.ceil(value/10d)(value+9)/10 的争论之后,我最终编写了一个正确的非死代码、非解释模式基准测试。 我一直在说编写微基准测试并不是一件容易的事。下面的代码说明了这一点:

00:21:40.109 starting up....
00:21:40.140 doubleCeil: 19444599
00:21:40.140 integerCeil: 19444599
00:21:40.140 warming up...
00:21:44.375 warmup doubleCeil: 194445990000
00:21:44.625 warmup integerCeil: 194445990000
00:22:27.437 exec doubleCeil: 1944459900000, elapsed: 42.806s
00:22:29.796 exec integerCeil: 1944459900000, elapsed: 2.363s

基准测试使用 Java,因为我非常了解 Hotspot 如何优化并确保它是一个公平的结果。有了这样的结果,没有任何统计数据、噪音或任何东西可以污染它。

Integer ceil 速度快得惊人。

代码

package t1;

import java.math.BigDecimal;

import java.util.Random;

public class Div {
    static int[] vals;

    static long doubleCeil(){
        int[] v= vals;
        long sum = 0;
        for (int i=0;i<v.length;i++){
            int value = v[i];
            sum+=Math.ceil(value/10d);
        }
        return sum;
    }

    static long integerCeil(){      
        int[] v= vals;
        long sum = 0;
        for (int i=0;i<v.length;i++){
            int value = v[i];
            sum+=(value+9)/10;
        }
        return sum;     
    }

    public static void main(String[] args) {
        vals = new  int[7000];
        Random r= new Random(77);
        for (int i = 0; i < vals.length; i++) {
            vals[i] = r.nextInt(55555);
        }
        log("starting up....");

        log("doubleCeil: %d", doubleCeil());
        log("integerCeil: %d", integerCeil());
        log("warming up...");       

        final int warmupCount = (int) 1e4;
        log("warmup doubleCeil: %d", execDoubleCeil(warmupCount));
        log("warmup integerCeil: %d", execIntegerCeil(warmupCount));

        final int execCount = (int) 1e5;

        {       
        long time = System.nanoTime();
        long s = execDoubleCeil(execCount);
        long elapsed = System.nanoTime() - time;
        log("exec doubleCeil: %d, elapsed: %.3fs",  s, BigDecimal.valueOf(elapsed, 9));
        }

        {
        long time = System.nanoTime();
        long s = execIntegerCeil(execCount);
        long elapsed = System.nanoTime() - time;
        log("exec integerCeil: %d, elapsed: %.3fs",  s, BigDecimal.valueOf(elapsed, 9));            
        }
    }

    static long execDoubleCeil(int count){
        long sum = 0;
        for(int i=0;i<count;i++){
            sum+=doubleCeil();
        }
        return sum;
    }


    static long execIntegerCeil(int count){
        long sum = 0;
        for(int i=0;i<count;i++){
            sum+=integerCeil();
        }
        return sum;
    }

    static void log(String msg, Object... params){
        String s = params.length>0?String.format(msg, params):msg;
        System.out.printf("%tH:%<tM:%<tS.%<tL %s%n", new Long(System.currentTimeMillis()), s);
    }   
}

【讨论】:

  • 很好的答案。断言是一回事,证明完全是另一回事。
  • 好点,证明是另一回事
【解决方案4】:

这也可以:

c = (count - 1) / 10 + 1;

【讨论】:

  • 我最喜欢这个,很好看
  • 我发现您的代码存在多个问题,尤其是数字 0 和 20(将返回 3)或任何大于 10 的数字。
  • @Rumplin,0 是对的,但对于 20,它按预期返回 2。
  • 你是对的,它适用于数字 > 0
  • 一个不错的解决方案,但 IMO 这比使用 Math.Ceiling 的可读性差。乍一看,并不清楚代码的用途。
【解决方案5】:
【解决方案6】:

我认为最简单的方法是将两个整数相除并加一:

int r = list.Count() / 10;
r += (list.Count() % 10 == 0 ? 0 : 1);

不需要库或函数。

使用正确的代码进行编辑。

【讨论】:

  • 在 count % 10 ==0 时无法正常工作。即返回 2 for 10
  • 如果 list.Count() == 10 在除法之前不正确。然后当 1 正确时你得到 2。
  • 糟糕,错过了。你们是对的人:)
【解决方案7】:

Xform 为一个简单的 ceil 加倍(并返回)?

list.Count()/10 + (list.Count()%10 &gt;0?1:0) - 这很糟糕,div + mod

编辑第一个: 2n 认为可能更快(取决于优化): div * mul(mul 比 div 和 mod 快)

int c=list.Count()/10;
if (c*10<list.Count()) c++;

edit2 全部删除。忘记了最自然的(加 9 确保整数四舍五入)

(list.Count()+9)/10

【讨论】:

    【解决方案8】:

    使用 mod 检查 - 如果有余数,只需将值加一即可。

    【讨论】:

    • 您必须先做 mod,然后进行测试,然后再进行增量(即添加和存储)。太贵了。添加然后仅除(与mod一样昂贵)更容易。无需测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多