Bagaimana menentukan apakah desimal / dobel adalah bilangan bulat?


225

Bagaimana saya tahu jika nilai desimal atau dobel adalah bilangan bulat?

Sebagai contoh:

decimal d = 5.0; // Would be true
decimal f = 5.5; // Would be false

atau

double d = 5.0; // Would be true
double f = 5.5; // Would be false

Alasan saya ingin mengetahui hal ini adalah agar saya dapat menentukan secara terprogram apakah saya ingin menampilkan nilai menggunakan .ToString("N0")atau .ToString("N2"). Jika tidak ada nilai titik desimal, maka saya tidak ingin menunjukkannya.

Jawaban:


410

Untuk angka floating point, n % 1 == 0biasanya cara untuk memeriksa apakah ada sesuatu yang melewati titik desimal.

public static void Main (string[] args)
{
    decimal d = 3.1M;
    Console.WriteLine((d % 1) == 0);
    d = 3.0M;
    Console.WriteLine((d % 1) == 0);
}

Keluaran:

False
True

Pembaruan: Seperti yang disebutkan @Adrian Lopez di bawah ini, perbandingan dengan nilai kecilepsilonakan membuang perhitungan kesalahan perhitungan floating-point. Karena pertanyaannya adalah tentangdoublenilai, di bawah ini akan menjadijawaban bukti perhitungan floating-point yang lebih :

Math.Abs(d % 1) <= (Double.Epsilon * 100)

96
Itu bekerja ketika bilangan dimulai sebagai bilangan bulat, tetapi tidak harus ketika bilangan adalah hasil dari beberapa perhitungan floating-point. Bagaimana dengan sesuatu seperti "(d% 1) <epsilon" di mana epsion bernilai kecil?
Adrian Lopez

9
Sayang sekali bahwa jawaban terbaik di utas ini adalah komentar, bukan jawaban yang diterima. Adrian yang baik.
starskythehutch

13
Saya juga berpikir komentar Adrian di atas adalah jawaban terbaik. Untuk memberikan sarannya dalam kode C # formal: if (Math.Abs ​​(n% 1) <Double.Epsilon) {// Lakukan sesuatu jika n bilangan bulat}.
Ruben Ramirez Padron

7
IMHO, operator modulus dan angka-angka floating point tidak bercampur dengan cara apa pun yang berguna. Kode yang disarankan sangat membingungkan mengingat jumlah penekanan tombol yang digunakan dan akan bekerja hampir di mana saja di luar bahasa .NET. Saya berani bertaruh itu juga jauh lebih lambat daripada cara yang benar (yang tidak menggunakan divisi sama sekali). Cara yang benar untuk melakukan ini adalah menggunakan Math.Abs(d-(int)d) < double.Epsilon. Seperti yang seharusnya kita semua pelajari di minggu pertama kelas pemrograman pertama kita di perguruan tinggi.
krowe2

9
Sebenarnya, seperti pertanyaan yang dinyatakan, jawaban ini benar dan komentarnya salah. OP tidak ingin tahu apakah dobel adalah bilangan bulat untuk tujuan matematika, melainkan bagaimana menampilkannya. Hanya nilai integer yang tepat yang harus ditampilkan tanpa titik desimal. Juga, komentar tentang mod tidak berguna dengan floating point dan tidak berfungsi di luar. NET tidak diinformasikan dengan baik. Dan (int)dmerupakan bencana yang akan membuat pengecualian untuk sebagian besar nilai ganda.
Jim Balter

49

Ada sejumlah cara untuk melakukan ini. Sebagai contoh:

double d = 5.0;
bool isInt = d == (int)d;

Anda juga dapat menggunakan modulo.

double d = 5.0;
bool isInt = d % 1 == 0;

Apakah salah satunya lebih cepat dari yang lain? Saya ingin melakukan ini dalam konteks sensitif kinerja.
Basil

@ Basil - Tergantung pada situasinya. Anda harus melakukan beberapa pengaturan waktu untuk diri sendiri dan menilai.
Erik Funkenbusch

4
Math.Abs(d-(int)d) < double.Epsilonlebih aman daripadad == (int)d
Reactgular

3
@MathewFoscarini - Saya pikir Anda bingung. Ini membuatnya salah, karena hasil 16.1 - 6.1 bukan int. Intinya adalah untuk menemukan apakah nilai yang diberikan adalah int, bukan jika sesuatu yang kira-kira int adalah int.
Erik Funkenbusch

1
@MathewFoscarini - Ya, int adalah angka tanpa nilai desimal (atau nilai desimal 0). 16.1-6.1 tidak membuat nilai desimal 0, ini adalah nilai non-nol yang sangat kecil yang disebabkan oleh quirks format Floating Point IEEE. Tidak ada cara untuk mengetahui apakah angka tersebut SEHARUSNYA memiliki nilai desimal atau tidak, sehingga dengan asumsi nilai pembulatan sama tidak akuratnya. Tujuan dari pertanyaan ini adalah untuk mengetahui apakah angka floating point adalah bilangan bulat, bukan apakah kira-kira bilangan bulat.
Erik Funkenbusch

21

Bagaimana dengan ini?

public static bool IsInteger(double number) {
    return number == Math.Truncate(number);
}

Kode yang sama untuk decimal.

Mark Byers membuat titik yang baik, benar-benar: ini mungkin bukan apa yang Anda benar-benar inginkan. Jika apa yang Anda benar-benar peduli adalah apakah angka dibulatkan ke dua desimal terdekat integer , Anda bisa melakukan ini sebagai gantinya:

public static bool IsNearlyInteger(double number) {
    return Math.Round(number, 2) == Math.Round(number);
}

1
mungkin perbarui solusi Anda dan tambahkan: && number <int.MaxValue && number> int.MinValue
Walter Vehoeven

12

Sementara solusi yang diajukan tampaknya bekerja untuk contoh sederhana, melakukan ini secara umum adalah ide yang buruk. Angka mungkin bukan bilangan bulat persis tetapi ketika Anda mencoba memformatnya, bilangan itu cukup dekat dengan bilangan bulat yang Anda dapatkan 1.000000. Ini dapat terjadi jika Anda melakukan perhitungan yang secara teori harus memberikan tepat 1, tetapi dalam praktiknya memberikan angka yang sangat dekat tetapi tidak persis sama dengan satu karena kesalahan pembulatan.

Alih-alih, format terlebih dahulu dan jika string Anda berakhir dalam periode yang diikuti oleh nol maka cabut mereka. Ada juga beberapa format yang dapat Anda gunakan untuk menghapus angka nol secara otomatis. Ini mungkin cukup baik untuk tujuan Anda.

double d = 1.0002;
Console.WriteLine(d.ToString("0.##"));
d = 1.02;
Console.WriteLine(d.ToString("0.##"));

Keluaran:

1
1.02

@Mark Kedengarannya menarik. Apakah Anda memiliki contoh format yang menghapus angka nol?
Jim Geurts

Saya setuju bahwa ini lebih aman dan apa yang harus dilakukan OP, tetapi itu bukan jawaban untuk pertanyaan yang lebih sempit (tetapi lebih menarik) tentang apakah suatu nilai memiliki bagian fraksional atau tidak.
Clifford

3
@Clifford: Saya biasanya mencoba menjawab berdasarkan apa yang terbaik untuk menyelesaikan masalah OPs, bukan berdasarkan apa kata judulnya. Judul jarang merupakan deskripsi masalah yang akurat.
Mark Byers

+1 Setuju bahwa mencoba menguji mengapung atau menggandakan untuk melihat apakah mereka bisa int adalah buruk karena kesalahan pembulatan dan presisi.
Romain Hippeau

1
Untuk penggunaan uang, Anda mungkin ingin 1,2 ditampilkan sebagai 1,20, yang tidak demikian halnya dengan solusi yang disarankan. Ada yang mengambil?
Kjell Rilbe

10
bool IsInteger(double num) {
    if (ceil(num) == num && floor(num) == num)
        return true;
    else
        return false;
}

Problemo solvo.

Sunting: Dimiliki oleh Mark Rushakoff.


4
atau hanyareturn ceil(num) == num && floor(num) == num;
Brian Rasmussen

13
atau hanyareturn ceil(num) == floor(num);
gregsdennis

4

Jawaban Mark Rushakoff mungkin lebih sederhana, tetapi berikut ini juga berfungsi dan mungkin lebih efisien karena tidak ada operasi pembagian yang tersirat:

     bool isInteger = (double)((int)f) == f ;

dan

     bool isInteger = (decimal)((int)d) == d ;

Jika Anda ingin satu ekspresi untuk kedua jenis, mungkin

     bool isInteger = (double)((int)val) == (double)val ;

4

Jika batas atas dan bawah Int32masalah:

public bool IsInt32(double value)
{
    return  value >= int.MinValue && value <= int.MaxValue && value == (int)value;
}

Tes pertama, kemudian dilemparkan seperti ini akan mengeluarkan pengecualian selain return false, mungkin memperbarui jawaban Anda
Walter Vehoeven

Komputer @, ya bagus. Mengenai melempar pemain, saya kira itu akan tergantung pada pengaturan proyek Anda.
nawfal

3
static bool IsWholeNumber(double x) 
{
    return Math.Abs(x % 1) < double.Epsilon;
}

2

Anda dapat menggunakan pemformatan string untuk tipe ganda. Berikut ini sebuah contoh:

double val = 58.6547;
String.Format("{0:0.##}", val);      
//Output: "58.65"

double val = 58.6;
String.Format("{0:0.##}", val);      
//Output: "58.6"

double val = 58.0;
String.Format("{0:0.##}", val);      
//Output: "58"

Beri tahu saya jika ini tidak membantu.


1
Itu tidak benar-benar menjawab pertanyaan menentukan apakah suatu nilai tidak memiliki bagian pecahan, yang merupakan pertanyaan matematika. Namun itu mungkin yang dibutuhkan OP dengan catatan penjelasannya.
Clifford

2
Ya, dia ingin memformat nilai ganda atau desimal tanpa titik desimal. Terima kasih ...
BALKANGraph


0

Saya menghadapi situasi yang sama, tetapi di mana nilainya adalah string. Pengguna mengetikkan nilai yang seharusnya merupakan jumlah dolar, jadi saya ingin memvalidasi bahwa itu numerik dan memiliki paling banyak dua tempat desimal.

Inilah kode saya untuk mengembalikan true jika string "s" mewakili angka dengan paling banyak dua tempat desimal, dan false jika tidak. Ini menghindari masalah yang akan timbul dari ketidaktepatan nilai floating-point.

try
{
    // must be numeric value
    double d = double.Parse(s);
    // max of two decimal places
    if (s.IndexOf(".") >= 0)
    {
        if (s.Length > s.IndexOf(".") + 3)
            return false;
    }
    return true;
catch
{
    return false;
}

Saya membahas ini secara lebih rinci di http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html .


4
Ini mengasumsikan bahwa Anda bekerja dengan satu budaya. Misalnya, Ini tidak akan berfungsi dengan baik dengan budaya yang mewakili desimal seperti 1.000,00
Jim Geurts

0

Menggunakan int.TryParse akan menghasilkan hasil ini:

        var shouldBeInt = 3;

        var shouldntBeInt = 3.1415;

        var iDontWantThisToBeInt = 3.000f;

        Console.WriteLine(int.TryParse(shouldBeInt.ToString(), out int parser)); // true

        Console.WriteLine(int.TryParse(shouldntBeInt.ToString(), out parser)); // false

        Console.WriteLine(int.TryParse(iDontWantThisToBeInt.ToString(), out parser)); // true, even if I don't want this to be int

        Console.WriteLine(int.TryParse("3.1415", out  parser)); // false

        Console.WriteLine(int.TryParse("3.0000", out parser)); // false

        Console.WriteLine(int.TryParse("3", out parser)); // true

        Console.ReadKey();

-2

Mungkin bukan solusi yang paling elegan tetapi berhasil jika Anda tidak terlalu pilih-pilih!

bool IsInteger(double num) {
    return !num.ToString("0.################").Contains(".");
}

8
Ini adalah solusi yang mengerikan
Ospho

-2

Anda bisa menggunakan metode 'TryParse'.

int.TryParse()

Ini memeriksa untuk melihat apakah nilai dapat dikonversi ke nilai bilangan bulat seluruh. Hasilnya kemudian dapat menunjukkan bendera yang dapat digunakan di tempat lain dalam kode Anda.


Argumen untuk int.TryParse adalah string, bukan dobel.
Jim Balter

yourDouble.toString("G17")
BackDoorNoBaby

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.