Java làm tròn thành int bằng Math.ceil


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

Tại sao nó vẫn trả về 4? 157/32 = 4.90625, Tôi cần phải làm tròn, tôi đã quan sát xung quanh và đây có vẻ là phương pháp đúng.

Tôi đã thử totallàm doubleloại nhưng nhận được 4.0.

Tôi đang làm gì sai?

Câu trả lời:


187

Bạn đang làm 157/32đó là chia hai số nguyên với nhau, luôn dẫn đến một số nguyên làm tròn xuống. Vì vậy, (int) Math.ceil(...)không làm bất cứ điều gì. Có ba giải pháp khả thi để đạt được điều bạn muốn. Tôi khuyên bạn nên sử dụng tùy chọn 1 hoặc tùy chọn 2 . Vui lòng KHÔNG sử dụng tùy chọn 0 .

## Tùy chọn 0

Chuyển đổi abthành một đôi, và bạn có thể sử dụng phép chia và Math.ceilnhư bạn muốn nó hoạt động. Tuy nhiên, tôi thực sự không khuyến khích việc sử dụng phương pháp này, vì phép chia đôi có thể không chính xác. Để đọc thêm về không bao quy đầu của đôi, hãy xem câu hỏi này .

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

##Lựa chọn 1

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

Bạn làm a / bvới luôn sàn nếu abcả hai đều là số nguyên. Sau đó, bạn có một phù thủy câu lệnh if nội tuyến kiểm tra xem bạn có nên dừng thay vì sàn hay không. Vì vậy, +1 hoặc +0, nếu có phần dư với phép chia, bạn cần +1. a % b == 0kiểm tra phần còn lại.

##Lựa chọn 2

Tùy chọn này rất ngắn, nhưng có thể đối với một số người ít trực quan hơn. Tôi nghĩ rằng cách tiếp cận ít trực quan hơn này sẽ nhanh hơn so với cách tiếp cận chia đôi và so sánh:
Xin lưu ý rằng cách này không hoạt động cho b < 0.

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

Để giảm nguy cơ tràn, bạn có thể sử dụng các cách sau. Tuy nhiên, xin lưu ý rằng nó không hoạt động cho a = 0b < 1.

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

## Giải thích đằng sau "cách tiếp cận ít trực quan hơn"

Vì phép chia hai số nguyên trong Java (và hầu hết các ngôn ngữ lập trình khác) sẽ luôn dẫn đến kết quả giống nhau. Vì thế:

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

Nhưng chúng tôi không muốn floor(a/b), nhưng ceil(a/b)và sử dụng các định nghĩa và âm mưu từ Wikipedia :nhập mô tả hình ảnh ở đây

Với những mảnh đất này của tầng và chức năng, bạn có thể thấy mối quan hệ.

Chức năng tầng Hàm trần

Bạn có thể thấy điều đó floor(x) <= ceil(x). Chúng tôi cần floor(x + s) = ceil(x). Vì vậy, chúng ta cần phải tìm s. Nếu chúng ta chấp nhận 1/2 <= s < 1nó sẽ vừa phải (hãy thử một số con số và bạn sẽ thấy nó đúng, bản thân tôi thấy rất khó để chứng minh điều này). Và 1/2 <= (b-1) / b < 1, vì vậy

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

Đây không phải là một bằng chứng thực tế, nhưng tôi hy vọng bạn hài lòng với nó. Nếu ai đó có thể giải thích nó tốt hơn, tôi cũng sẽ đánh giá cao nó. Có thể hỏi nó trên MathOverflow .


1
Sẽ là một lợi ích rất lớn nếu bạn có thể giải thích trực giác đằng sau cách tiếp cận ít trực quan hơn? Tôi biết điều này là chính xác, tôi muốn biết làm thế nào bạn có được nó, và làm thế nào tôi có thể toán học cho thấy nó là chính xác. Tôi đã thử giải nó bằng toán học, nhưng không bị thuyết phục.
Saad Rehman Shah

Tôi hy vọng bạn hài lòng với bản chỉnh sửa của tôi, tôi nghĩ tôi không thể làm tốt hơn được nữa :(
martijnn2008

Tôi giả sử Math.floor và ceil chỉ đúng cho phép chia số nguyên không đúng cho phép chia dài khi các giá trị được ép lên gấp đôi. Ví dụ Counter là 4611686018427386880/4611686018427387137 không thành công trên sàn và 4611686018427386881/4611686018427386880 không thành công trên ceil
Wouter

2
Một điểm cần làm rõ: Kết quả của hai phương án phụ của phương án 2 không giống nhau trong mọi trường hợp. Giá trị 0 của a sẽ cung cấp giá trị 0 trong lần đầu tiên và 1 trong lần thứ hai (không phải là câu trả lời chính xác cho hầu hết các ứng dụng).
Sushisource

1
Bạn có chắc ý không phải là "Tuy nhiên, xin lưu ý rằng nó không hoạt động đối với a = 0 và b < 1"
dantiston 22/02/17

60

157/32 là int/int, dẫn đến một int.

Hãy thử sử dụng chữ kép - 157/32d, nghĩa là int/double, kết quả là a double.


Bạn có chắc rằng int / int sẽ luôn dẫn đến một int ?! bạn có thể vui lòng cung cấp nguồn cho điều đó?!


34

157/32là một phép chia số nguyên vì tất cả các chữ số đều là số nguyên trừ khi được chỉ định khác bằng một hậu tố ( dđối với kép ldài)

phép chia được làm tròn xuống (thành 4) trước khi chuyển thành kép (4,0), sau đó được làm tròn lên (thành 4,0)

nếu bạn sử dụng một biến, bạn có thể tránh điều đó

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


7

Không ai đã đề cập đến trực quan nhất:

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

Giải pháp này khắc phục sự không chính xác của phép chia đôi .


1
Math.round trả về lâu
Zulqurnain Jutt

Cảm ơn @ZulqurnainJutt, bổ sung một dàn diễn viên
IG Pascual

4

Trong Java, thêm một .0 sẽ làm cho nó trở thành ...

int total = (int) Math.ceil(157.0 / 32.0);

3

Khi chia hai số nguyên, ví dụ:

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

kết quả là một int, giá trị của nó được achia cho b, làm tròn về 0. Bởi vì kết quả đã được làm tròn, ceil()không làm bất cứ điều gì. Lưu ý rằng việc làm tròn này không giống như làm floor()tròn về phía âm vô cực. Vì vậy, 3/2bằng 1(và floor(1.5)bằng 1.0, nhưng (-3)/2bằng -1(nhưng floor(-1.5)bằng -2.0).

Đây là quan trọng bởi vì nếu a/blúc nào cũng giống như floor(a / (double) b), sau đó bạn chỉ có thể thực hiện ceil()các a/bnhư -( (-a) / b).

Đề xuất nhận được ceil(a/b)từ

int n = (a + b - 1) / b;, tương đương với a / b + (b - 1) / b, hoặc(a - 1) / b + 1

hoạt động bởi vì ceil(a/b) luôn luôn lớn hơn floor(a/b), ngoại trừ khi a/blà một số nguyên. Vì vậy, bạn muốn chuyển nó sang (hoặc qua) số nguyên tiếp theo, trừ khi a/blà một số nguyên. Thêm1 - 1 / b sẽ làm điều này. Đối với số nguyên, nó sẽ không hoàn toàn đẩy chúng lên số nguyên tiếp theo. Đối với mọi thứ khác, nó sẽ.

Rất tiếc. Hy vọng rằng điều đó có ý nghĩa. Tôi chắc chắn rằng có một cách giải thích toán học thanh lịch hơn.


2

Ngoài ra, để chuyển đổi một số từ số nguyên sang số thực, bạn có thể thêm dấu chấm:

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

Và kết quả của (157/32.) Cũng sẽ là thực. ;)



1

Kiểm tra giải pháp bên dưới cho câu hỏi của bạn:

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

Ở đây bạn nên nhân Numerator với 1,0, sau đó nó sẽ cho câu trả lời của bạn.

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

0

Sử dụng double để truyền lượt like

Math.ceil((double)value) hoặc thích

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

0

Java chỉ cung cấp phân chia tầng /theo mặc định. Nhưng chúng ta có thể viết trần về mặt sàn . Hãy xem nào:

Bất kỳ số nguyên nào ycũng có thể được viết với biểu mẫu y == q*k+r. Theo định nghĩa của phân chia tầng (tại đây floor) làm tròn r,

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

và phân chia trần (tại đây ceil) làm tròn lên r₁,

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

nơi chúng tôi có thể thay thế r+1cho r₁:

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


Sau đó, chúng tôi thay thế phương trình đầu tiên thành phương trình thứ ba để qnhận được

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

Cuối cùng, với bất kỳ số nguyên ynơi y = q*k+r+1đối với một số q, k, r, chúng tôi có

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

Và chúng tôi đã hoàn thành. Hi vọng điêu nay co ich.


Tôi chắc chắn rằng điều này là chính xác, nhưng vì vấn đề của điều này là phải làm rõ, tôi không rõ tại sao lại ceilđược định nghĩa như vậy từ định nghĩa trực quan, cụ thể là khi chúng ta lấy dấu của một số nguyên, tức là r1 = k. Vì các trường hợp cạnh là điều khó khăn về điều này, tôi nghĩ rằng nó cần phải được viết rõ hơn một chút.
Luigi Plinge

@LuigiPlinge Đối với tôi, việc dẫn xuất không thể đơn giản hơn do sự khác biệt nội tại giữa sàn và trần trong bối cảnh hoạt động của bộ phận. Tôi nghĩ rằng bạn không cần phải tập trung vào trường hợp cạnh - đó là một thực tế tự nhiên khi bạn cố gắng thống nhất các định nghĩa về sàn và trần bằng cách chia nhỏ một số nguyên. Kết quả là, bằng chứng chỉ là ba bước, và kết luận có thể được nhớ đại khái là "lùi một bước khấu hao, sau đó tiến một bước tuyệt đối".
ShellayLee

0

Có hai phương pháp mà bạn có thể làm tròn giá trị nhân đôi của mình.

  1. Math.ceil
  2. Math.floor

Nếu bạn muốn câu trả lời của mình là 4.90625 là 4 thì bạn nên sử dụng Math.floor và nếu bạn muốn câu trả lời của mình là 4.90625 là 5 thì bạn có thể sử dụng Math.ceil

Bạn có thể tham khảo mã sau đây cho điều đó.

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

hoặc tổng quát hơn

(a-1)/b +1 

Tôi nghĩ điều này hiệu quả, nhưng bạn chưa thực sự giải thích tại sao phiên bản gốc không hoạt động.
Teepeemm

" Tuy nhiên xin lưu ý rằng nó không làm việc cho a = 0 và b <1 "
IG Pascual
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.