Java使用Math.ceil舍入为一个int


101
int total = (int) Math.ceil(157/32);

为什么仍然返回4?157/32 = 4.90625,我需要四舍五入,环顾四周,这似乎是正确的方法。

我尝试total作为double类型,但得到4.0。

我究竟做错了什么?

Answers:


187

您正在执行的操作157/32是彼此除以两个整数,这总是导致四舍五入的整数。因此,(int) Math.ceil(...)什么也没做。有三种可能的解决方案来实现您想要的。我建议使用选项1选项2。请不要使用选项0

##选项0

a和转换b为双精度,然后可以使用除法并按Math.ceil需要工作。但是,我强烈不鼓励使用这种方法,因为双重除法可能不精确。要了解更多关于不精确的双打看到这个问题

int n = (int) Math.ceil((double) a / b));

##选项1

int n = a / b + ((a % b == 0) ? 0 : 1); 

a / b有永远地板如果ab都是整数。然后,您有一个内联的if语句女巫检查您是否应该天花板而不是地板。因此+1或+0,如果除法除法运算中还有余数,则需要+1。a % b == 0检查其余部分。

##选项2

此选项很短,但可能不太直观。我认为这种不太直观的方法会比双重除法和比较方法要快:
请注意,这不适用于b < 0

int n = (a + b - 1) / b;

为了减少溢出的机会,您可以使用以下方法。但是请注意,它不适用于a = 0b < 1

int n = (a - 1) / b + 1;

##“不太直观的方法”背后的解释

由于用Java(和大多数其他编程语言)将两个整数相除将始终使结果无效。所以:

int a, b;
int result = a/b (is the same as floor(a/b) )

但是,我们并不需要floor(a/b),而是ceil(a/b)使用Wikipedia的定义和情节:在此处输入图片说明

使用floor和ceil函数的这些图,您可以看到关系。

楼层功能 Ceil功能

您可以看到floor(x) <= ceil(x)。我们需要floor(x + s) = ceil(x)。所以我们需要找到s。如果我们认为1/2 <= s < 1这是正确的(尝试一些数字,您会看到的,我发现自己很难证明这一点)。而且1/2 <= (b-1) / b < 1,这样

ceil(a/b) = floor(a/b + s)
          = floor(a/b + (b-1)/b)
          = floor( (a+b-1)/b) )

这不是一个真实的证明,但我希望您对此感到满意。如果有人可以更好地解释它,我也将不胜感激。也许在MathOverflow上询问。


1
如果您能解释不太直观的方法背后的直觉,将是一个极大的帮助?我知道这是正确的,我想知道您是如何做到的,以及如何从数学上证明它是正确的。我不敢相信,我试图用数学方法解决它。
Saad Rehman Shah 2014年

希望您对我的编辑感到满意,我认为我做得更好:(
martijnn2008

我假设Math.floor和ceil仅适用于整数除法,不适用于将值强制转换为双精度的长除法。反例是4611686018427386880/4611686018427387137在地板上失败和4611686018427386881/4611686018427386880在天花板上失败
Wouter

2
需要澄清的一点是:选项2的两个子选项的结果在所有情况下都不相同。a的零值将在第一个中提供0,在第二个中提供1(对于大多数应用程序,这不是正确的答案)。
Sushisource,2013年

1
您确定您不是
要说


34

157/32是整数除法,因为所有数字文字都是整数,除非另有后缀指定(长d为double l

在将除法转换为双精度(4.0)之前将其四舍五入(至4),然后将其四舍五入(至4.0)

如果使用变量可以避免

double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);


7

没有人提到最直观的:

int x = (int) Math.round(Math.ceil((double) 157 / 32));

该解决方案解决了分割不精确问题。


1
Math.round长久回报
Zulqurnain Jutt

感谢@ZulqurnainJutt,添加了一个演员
IG Pascual,


3

当除以两个整数时,例如,

int c = (int) a / (int) b;

结果是an int,其值a除以b,并四舍五入为零。由于结果已经四舍五入,因此ceil()不会执行任何操作。请注意,此舍入与的舍入不同floor(),后者朝负无穷大舍入。因此,3/2等于1(和floor(1.5)等于1.0,但(-3)/2等于-1(但floor(-1.5)等于-2.0)。

因为如果这是显著a/b总是一样的floor(a / (double) b),那么你可以只实施ceil()a/b作为-( (-a) / b)

ceil(a/b)来自的建议

int n = (a + b - 1) / b;,等效于a / b + (b - 1) / b(a - 1) / b + 1

之所以起作用,ceil(a/b)是因为总是大于floor(a/b),除非a/b是整数。因此,除非a/b是整数,否则您想将其撞到(或超过)下一个整数。添加1 - 1 / b将执行此操作。对于整数,它不会完全推升到下一个整数。对于其他一切,它都会。

kes 希望这是有道理的。我敢肯定,有一种数学上更优雅的方式来解释它。



2
int total = (int) Math.ceil( (double)157/ (double) 32);

1

检查以下问题的解决方案:

int total = (int) Math.ceil(157/32);

在这里,您应该将分子乘以1.0,然后它将给出您的答案。

int total = (int) Math.ceil(157*1.0/32);

0

使用double进行投射

Math.ceil((double)value) 或喜欢

Math.ceil((double)value1/(double)value2);

0

Java /默认仅提供地板分割。但是我们可以用地板写天花板。让我们来看看:

任何整数y都可以用形式书写y == q*k+r。根据floor四舍五入的楼层划分(在此)的定义r

floor(q*k+r, k) == q  , where 0  r  k-1

ceil四舍五入的天花板分区(在此)r₁

ceil(q*k+r₁, k) == q+1  , where 1  r  k

在这里我们可以替换r+1r₁

ceil(q*k+r+1, k) == q+1  , where 0  r  k-1


然后我们替换第一方程式为第三为q获得

ceil(q*k+r+1, k) == floor(q*k+r, k) + 1  , where 0  r  k-1

最后,给定任意整数y,其中y = q*k+r+1一些qkr,我们有

ceil(y, k) == floor(y-1, k) + 1

我们完成了。希望这可以帮助。


我确定这是正确的,但是由于要澄清这一点,所以我不清楚为什么ceil从直观定义中就这样定义,特别是在我们采用整数ceil的情况下,即r1 = k。由于边缘情况是棘手的问题,因此我认为还需要进一步说明。
路易吉·普林格

@LuigiPlinge对我而言,由于除法运算中地板和天花板之间的内在差异,推导无法简单。我认为您不必关注边缘情况-当您尝试通过分解整数来统一地板和天花板的定义时,这是自然的事实。结果,证明只是三个步骤,结论可以粗略地记住为“一个摊销的步骤,然后是绝对的步骤”。
ShellayLee

0

您可以通过两种方法舍入双精度值。

  1. 数学细胞
  2. 数学地板

如果您希望答案4.90625为4,则应使用Math.floor;如果您希望答案4.90625为5,则可以使用Math.ceil

您可以参考以下代码。

public class TestClass {

    public static void main(String[] args) {
        int floorValue = (int) Math.floor((double)157 / 32);
        int ceilValue = (int) Math.ceil((double)157 / 32);
        System.out.println("Floor: "+floorValue);
        System.out.println("Ceil: "+ceilValue);

    }

}

-3
int total = (157-1)/32 + 1

或更一般

(a-1)/b +1 

我认为这可行,但是您还没有真正解释为什么原始版本不起作用。
Teepeemm

但是请注意,对于a = 0和b <1而言,它不起作用
IG Pascual,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.