Java membulatkan ke int menggunakan Math.ceil

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

Mengapa masih mengembalikan 4? 157/32 = 4.90625, Saya perlu mengumpulkan, Saya telah melihat sekeliling dan ini sepertinya metode yang tepat.

Saya mencoba totalsebagai doubletipe, tetapi mendapatkan 4.0.

Apa yang saya lakukan salah?

tom
sumber

Jawaban:

188

Anda melakukan 157/32yang membagi dua bilangan bulat satu sama lain, yang selalu menghasilkan bilangan bulat yang dibulatkan ke bawah. Oleh karena itu mereka (int) Math.ceil(...)tidak melakukan apapun. Ada tiga kemungkinan solusi untuk mencapai apa yang Anda inginkan. Saya merekomendasikan menggunakan opsi 1 atau 2 . Harap JANGAN gunakan opsi 0 .

## Opsi 0

Ubah adan bmenjadi ganda, dan Anda dapat menggunakan pembagian dan Math.ceilsesuai keinginan Anda. Namun saya sangat tidak menyarankan penggunaan pendekatan ini, karena pembagian ganda bisa jadi tidak tepat. Untuk membaca lebih lanjut tentang ketidaktepatan ganda, lihat pertanyaan ini .

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

##Pilihan 1

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

Anda lakukan a / bdengan selalu lantai jika adan bkeduanya adalah bilangan bulat. Kemudian Anda memiliki seorang penyihir pernyataan-if inline memeriksa apakah Anda harus langit-langit dan bukan lantai. Jadi +1 atau +0, jika ada sisa pembagian Anda perlu +1. a % b == 0periksa sisanya.

##Pilihan 2

Pilihan ini sangat singkat, tetapi mungkin untuk beberapa orang kurang intuitif. Saya pikir pendekatan yang kurang intuitif ini akan lebih cepat daripada pendekatan pembagian dan perbandingan ganda:
Harap dicatat bahwa ini tidak berhasil b < 0.

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

Untuk mengurangi kemungkinan meluap, Anda bisa menggunakan yang berikut ini. Namun harap dicatat bahwa ini tidak berfungsi untuk a = 0dan b < 1.

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

## Penjelasan di balik "pendekatan yang kurang intuitif"

Karena membagi dua integer di Java (dan sebagian besar bahasa pemrograman lainnya) akan selalu memberikan hasil. Begitu:

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

Tapi kami tidak mau floor(a/b), tapi ceil(a/b), dan menggunakan definisi dan plot dari Wikipedia :masukkan deskripsi gambar di sini

Dengan fungsi plot lantai dan langit-langit ini Anda bisa melihat hubungannya.

Fungsi lantai Fungsi plafon

Kamu bisa lihat itu floor(x) <= ceil(x). Kami membutuhkan floor(x + s) = ceil(x). Jadi kita perlu mencari s. Jika kita mengambilnya 1/2 <= s < 1akan benar (coba beberapa angka dan Anda akan melihatnya, saya merasa sulit untuk membuktikan ini). Dan 1/2 <= (b-1) / b < 1, jadi

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

Ini bukan bukti nyata, tapi saya harap Anda puas dengannya. Jika seseorang dapat menjelaskannya dengan lebih baik, saya akan menghargainya juga. Mungkin menanyakannya di MathOverflow .

martijnn2008
sumber
1
Akan sangat membantu jika Anda bisa menjelaskan intuisi di balik pendekatan yang kurang intuitif? Saya tahu ini benar, saya ingin tahu bagaimana Anda mendapatkannya, dan bagaimana saya bisa menunjukkan secara matematis bahwa itu benar. Saya mencoba menyelesaikannya secara matematis, tidak yakin.
Saad Rehman Shah
Saya harap Anda puas dengan hasil edit saya, saya tidak bisa melakukan yang lebih baik lagi Saya pikir :(
martijnn2008
Saya berasumsi Math.floor dan ceil hanya benar untuk pembagian integer bukan untuk pembagian panjang ketika nilai dicor menjadi dua kali lipat. Contoh penghitung adalah 4611686018427386880/4611686018427387137 gagal di lantai dan 4611686018427386881/4611686018427386880 gagal di langit
Wouter
2
Poin klarifikasi: Hasil dari dua sub-opsi opsi 2 tidak identik di semua kasus. Nilai nol untuk a akan memberikan 0 di pertama, dan 1 di detik (yang bukan jawaban yang benar untuk sebagian besar aplikasi).
Sushisource
1
Apakah Anda yakin Anda tidak bermaksud "Namun harap dicatat bahwa itu tidak bekerja untuk a = 0 dan b < 1"
dantiston
60

157/32 adalah int/int, yang menghasilkan file int.

Coba gunakan literal ganda - 157/32d, yaitu int/double, yang menghasilkan a double.

Bozho
sumber
Apakah Anda yakin int / int akan selalu menghasilkan int ?! bisakah anda memberikan sumbernya ?!
34

157/32adalah pembagian bilangan bulat karena semua literal numerik adalah bilangan bulat kecuali ditentukan lain dengan sufiks ( duntuk ganda luntuk panjang)

pembagian dibulatkan ke bawah (menjadi 4) sebelum diubah menjadi dobel (4,0) yang kemudian dibulatkan (menjadi 4,0)

jika Anda menggunakan variabel, Anda dapat menghindarinya

double a1=157;
double a2=32;
int total = (int) Math.ceil(a1/a2);
ratchet freak
sumber
26
int total = (int) Math.ceil((double)157/32);
Phoebus
sumber
7

Tidak ada yang menyebutkan yang paling intuitif:

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

Solusi ini memperbaiki ketidaktepatan divisi ganda .

IG Pascual
sumber
1
Math.round kembali lama
Zulqurnain Jutt
Terima kasih @ZulqurnainJutt, menambahkan pemeran
IG Pascual
4

Di Java, menambahkan .0 akan membuatnya menjadi ...

int total = (int) Math.ceil(157.0 / 32.0);
Scott Higgins
sumber
3

Saat membagi dua bilangan bulat, misalnya,

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

hasilnya adalah an int, nilai yang adibagi dengan b, dibulatkan menuju nol. Karena hasilnya sudah bulat, ceil()tidak melakukan apa-apa. Perhatikan bahwa pembulatan ini tidak sama dengan floor(), yang membulatkan ke arah negatif tak terhingga. Jadi, 3/2sama dengan 1(dan floor(1.5)sama 1.0, tapi (-3)/2sama -1(tapi floor(-1.5)sama -2.0).

Hal ini penting karena jika a/bselalu sama dengan floor(a / (double) b), maka Anda hanya bisa menerapkan ceil()dari a/bsebagai -( (-a) / b).

Saran untuk mendapatkan ceil(a/b)dari

int n = (a + b - 1) / b;, yang setara dengan a / b + (b - 1) / b, atau(a - 1) / b + 1

bekerja karena ceil(a/b)selalu satu lebih besar dari floor(a/b), kecuali jika a/bbilangan bulat. Jadi, Anda ingin menggesernya ke (atau melewati) bilangan bulat berikutnya, kecuali a/bbilangan bulat. Menambahkan 1 - 1 / bakan melakukan ini. Untuk bilangan bulat, itu tidak akan cukup mendorong mereka ke bilangan bulat berikutnya. Untuk yang lainnya, itu akan terjadi.

Astaga. Semoga masuk akal. Saya yakin ada cara yang lebih elegan secara matematis untuk menjelaskannya.

jorgenman
sumber
2

Juga untuk mengubah bilangan dari bilangan bulat menjadi bilangan real, Anda dapat menambahkan titik:

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

Dan hasil (157/32.) Juga akan menjadi nyata. ;)

Vitaliy Borisok
sumber
2
int total = (int) Math.ceil( (double)157/ (double) 32);
batu333
sumber
1

Periksa solusi di bawah untuk pertanyaan Anda:

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

Di sini Anda harus mengalikan Pembilang dengan 1,0, maka itu akan memberikan jawaban Anda.

int total = (int) Math.ceil(157*1.0/32);
Tidak diketahui
sumber
0

Gunakan ganda untuk melakukan cast seperti

Math.ceil((double)value) atau suka

Math.ceil((double)value1/(double)value2);
Bhupinder
sumber
0

Java hanya menyediakan pembagian lantai /secara default. Tapi kita bisa menulis langit-langit dengan istilah lantai . Ayo lihat:

Semua bilangan bulat ydapat ditulis dengan formulir y == q*k+r. Menurut definisi pembagian lantai (di sini floor) yang membulatkan r,

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

dan divisi langit-langit (di sini ceil) yang membulatkan r₁,

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

di mana kita dapat menggantikan r+1untuk r₁:

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


Kemudian kami mengganti persamaan pertama menjadi persamaan ketiga untuk qmendapatkan

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

Akhirnya, diberikan setiap bilangan bulat ydi mana y = q*k+r+1untuk beberapa q, k, r, kita memiliki

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

Dan kita selesai. Semoga ini membantu.

ShellayLee
sumber
Saya yakin ini benar, tetapi karena intinya adalah untuk memperjelas, tidak jelas bagi saya mengapa ceildidefinisikan seperti itu dari definisi awal, khususnya di mana kita mengambil langit-langit dari sebuah integer, yaitu r1 = k. Karena kasus tepi adalah yang rumit tentang ini, saya pikir itu perlu dijelaskan lebih banyak.
Luigi Plinge
@LuigiPlinge Bagi saya derivasi tidak bisa lebih sederhana karena perbedaan intrinsik antara lantai dan langit-langit dalam konteks operasi divisi. Saya pikir Anda tidak perlu fokus pada kasus tepi - itu adalah fakta alami ketika Anda mencoba menyatukan definisi lantai dan langit-langit melalui pemecahan bilangan bulat. Akibatnya, pembuktiannya hanya tiga langkah, dan kesimpulannya secara kasar dapat diingat sebagai "satu langkah diamortisasi mundur, lalu satu langkah mutlak ke depan".
ShellayLee
0

Ada dua metode untuk mengumpulkan nilai ganda Anda.

  1. Math.ceil
  2. Math.floor

Jika Anda menginginkan jawaban Anda 4.90625 sebagai 4 maka Anda harus menggunakan Math.floor dan jika Anda menginginkan jawaban Anda 4.90625 sebagai 5 maka Anda dapat menggunakan Math.ceil

Anda dapat merujuk kode berikut untuk itu.

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);

    }

}
Deepak Kumbhar
sumber
-3
int total = (157-1)/32 + 1

atau lebih umum

(a-1)/b +1 
oldcolder
sumber
Saya pikir ini berfungsi, tetapi Anda belum benar-benar menjelaskan mengapa versi aslinya tidak berfungsi.
Teepeemm
" Namun harap diperhatikan bahwa ini tidak berfungsi untuk a = 0 dan b <1 "
IG Pascual