Ondalık / çiftin bir tam sayı olup olmadığı nasıl belirlenir?


225

Ondalık veya çift değerin bir tam sayı olup olmadığını nasıl anlarım?

Örneğin:

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

veya

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

Bunu bilmek istememin nedeni, .ToString("N0")veya değerini kullanarak çıktı almak isteyip istemediğimi programsal olarak belirleyebilmemdir .ToString("N2"). Ondalık nokta değeri yoksa, bunu göstermek istemiyorum.

Yanıtlar:


411

Kayan nokta sayıları için, n % 1 == 0genellikle ondalık noktadan sonra bir şey olup olmadığını kontrol etmenin bir yoludur.

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

Çıktı:

False
True

Güncelleme: @Adrian Lopez'in de belirttiği gibi, küçük bir değerle karşılaştırmaepsilonkayan nokta hesaplama yanlış hesaplamalarınısilecektir. Sorudoubledeğerlerile ilgili olduğundan, aşağıda daha kayan nokta hesaplama kanıtı yanıtı olacaktır:

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

96
Bu, sayı bir tam sayı olarak başladığında çalışır, ancak sayı bir kayan nokta hesaplamasının sonucu olduğunda zorunlu değildir. Peki, epsionun küçük bir değer olduğu "(d% 1) <epsilon"
Adrian Lopez

9
Bu konudaki en iyi cevabın kabul edilen cevaptan ziyade bir yorum olması çok yazık. İyi biri Adrian.
starskythehutch

13
Ayrıca Adrian'ın yukarıdaki yorumu en iyi cevap olduğunu düşünüyorum. Tavsiyesini resmi C # koduna koymak için: if (Math.Abs ​​(n% 1) <Double.Epsilon) {// n tamsayı ise bir şey yap}.
Ruben Ramirez Padron

7
IMHO, modül operatörü ve kayan nokta sayıları yararlı herhangi bir şekilde karışmaz. Önerilen kod, kullanılan tuş vuruşlarının sayısı göz önüne alındığında inanılmaz derecede kafa karıştırıcıdır ve .NET dilleri dışında neredeyse hiçbir yerde çalışmayacaktır. Bahse girerim aynı zamanda doğru yoldan çok daha yavaştır (ki bu hiç bir bölümü kullanmaz). Bunu yapmanın doğru yolu kullanmaktır Math.Abs(d-(int)d) < double.Epsilon. Hepimiz üniversitedeki ilk programlama sınıfımızın ilk haftasında öğrenmiş olmalıydık.
krowe2

9
Aslında, soru belirtildiği gibi, bu cevap doğrudur ve yorumlar yanlıştır. OP, bir çiftin matematiksel amaçlar için bir tamsayı olup olmadığını bilmek istemez, bunun yerine nasıl görüntüleneceğini. Ondalık basamak olmadan yalnızca tam tam sayı değerleri görüntülenmelidir. Ayrıca, modun kayan nokta ile yararlı olmaması ve .NET dışında çalışmama hakkındaki yorum iyi bilgilendirilmemiştir. Ve (int)dçoğu çift değer için bir istisna atacak bir felaket.
Jim Balter

50

Bunu yapmanın birçok yolu vardır. Örneğin:

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

Ayrıca modulo da kullanabilirsiniz.

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

Bunlardan biri diğerinden daha hızlı olur mu? Bunu performansa duyarlı bir bağlamda yapmak istiyorum.
Basil

@Basil - Koşullara bağlıdır. Kendiniz için zamanlama yapmalı ve yargılamalısınız.
Erik Funkenbusch

4
Math.Abs(d-(int)d) < double.Epsilondaha güvenlidird == (int)d
Reactgular

3
@ MathewFoscarini - Sanırım kafan karıştı. 16.1 - 6.1 sonucu int değil. Burada amaç, int değerine sahip bir şeyin int olması değil, belirli bir değerin int olup olmadığını bulmaktı.
Erik Funkenbusch

1
@MathewFoscarini - Evet, int ondalık değeri olmayan bir sayıdır (veya ondalık değeri 0'dır). 16.1-6.1 0 ondalık değer oluşturmaz, IEEE Kayan Nokta biçimindeki tuhaflıklardan kaynaklanan çok küçük sıfır olmayan bir değerdir. Sayının ondalık değere sahip olup olmadığını DESTEKLEMEDİĞİNİ bilmenin bir yolu yoktur, bu nedenle yuvarlama değerinin yanlış olduğu varsayılarak. Sorunun amacı, kayan nokta sayısının, bir tamsayı olup olmadığını değil, bir tamsayı olup olmadığını bilmekti.
Erik Funkenbusch

21

Buna ne dersin?

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

İçin aynı kod decimal.

Mark Byers aslında iyi bir noktaya değindi: bu gerçekten istediğiniz şey olmayabilir . Ne olursa gerçekten umurumda olan bir sayı bir tamsayı en yakın iki ondalık basamağa yuvarlanır olsun , bunun yerine bunu:

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

1
belki çözümünüzü güncelleyin ve ekleyin: && number <int.MaxValue && number> int.MinValue
Walter Vehoeven

12

Önerilen çözümler basit örnekler için işe yarıyor gibi görünse de, bunu genel olarak yapmak kötü bir fikirdir. Bir sayı tam olarak bir tamsayı olmayabilir, ancak biçimlendirmeye çalıştığınızda aldığınız bir tamsayıya yeterince yakındır 1.000000. Teoride tam olarak 1 vermesi gereken bir hesaplama yaparsanız, ancak pratikte yuvarlama hataları nedeniyle bire çok yakın ancak tam olarak eşit olmayan bir sayı verirse bu olabilir.

Bunun yerine, önce biçimlendirin ve dizeniz sıfırlar ve ardından sıfırlar ile bitiyorsa, bunları şeritleyin. Ayrıca, şerit sondaki sıfırları otomatik olarak kullanabileceğiniz bazı biçimler de vardır. Bu, amacınız için yeterince iyi olabilir.

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

Çıktı:

1
1.02

@ Mark ilginç geliyor. Sondaki sıfırları ayıran bir biçime örnek var mı?
Jim Geurts

Daha güvenli olduğunu ve OP'nin muhtemelen ne yapması gerektiğini kabul ediyorum, ancak bir değerin kesirli bir parçası olup olmadığı konusunda daha dar (ama daha ilginç) sorunun cevabı değil.
Clifford

3
@Clifford: Genellikle, OP'nin problemini çözmek için en iyi olana, başlığın söylediklerine göre değil, cevap vermeye çalışırım. Başlıklar nadiren sorunun doğru bir tanımıdır.
Mark Byers

+1 Yüzen veya iki katını test etmenin yuvarlanıp bükülmeyeceğini görmek için yuvarlama ve hassasiyet hataları nedeniyle kötü olduğunu kabul edin.
Romain Hippeau

1
Para kullanımı için, önerilen çözümde durum böyle değil, muhtemelen 1.2'nin 1.20 olarak görüntülenmesini istersiniz. Arayan var mı?
Kjell Rilbe

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

Problem çözücü.

Düzenleme: Mark Rushakoff tarafından tasarlandı.


4
ya da sadecereturn ceil(num) == num && floor(num) == num;
Brian Rasmussen

13
or justreturn ceil(num) == floor(num);
gregsdennis

4

Mark Rushakoff'un cevabı daha basit olabilir, ancak aşağıdakiler de işe yarar ve örtülü bölünme işlemi olmadığından daha verimli olabilir:

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

ve

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

Her iki tür için de tek bir ifade istiyorsanız, belki

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

4

Üst ve alt sınır Int32önemlidir:

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

İlk test, daha sonra bu şekilde
yayınlayın

@bilgisayar, evet iyi bir nokta. Oyuncularda fırlatma ile ilgili olarak, sanırım proje ayarınıza bağlı olacaktır.
nawfal

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

2

Çift tip için Dize biçimlendirmesini kullanabilirsiniz. İşte bir örnek:

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"

Bu işe yaramıyorsa bana bildirin.


1
Bu, bir değerin kesirli bir parçası olup olmadığını belirleme sorusunu gerçekten ele almaz, bu da matematiksel bir sorudur. Ancak açıklayıcı notu muhtemelen OP'nin ihtiyaç duyduğu şeydir.
Clifford

2
Evet, yalnızca ondalık basamak olmadan çift veya ondalık değeri biçimlendirmek istiyor. Teşekkür ederim ...
BALKANGraph


0

Benzer bir durumla karşı karşıya kaldım, ancak değer bir dize. Kullanıcı bir dolar tutarı olması gereken bir değer yazıyor, bu yüzden sayısal ve en fazla iki ondalık basamak olduğunu doğrulamak istiyorum.

"S" dizesi en fazla iki ondalık basamağa sahip bir sayıyı temsil ediyorsa true döndürmek için kodum, aksi takdirde false olur. Kayan nokta değerlerinin belirsizliğinden kaynaklanan herhangi bir sorunu önler.

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

Bunu daha ayrıntılı olarak http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html adresinde tartışacağım .


4
Bu, bir kültürle çalıştığınızı varsayar. Örneğin, O 1.000,00 gibi ondalık sayıları temsil kültürleri ile düzgün işe yaramaz
Jim Geurts

0

İnt.TryParse kullanıldığında şu sonuçlar elde edilir:

        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

Belki de en zarif çözüm değil ama çok seçici değilseniz işe yarıyor!

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

8
Bu korkunç bir çözüm
Ospho

-2

'TryParse' yöntemini kullanabilirsiniz.

int.TryParse()

Bu, değerin bir tam sayı tam sayı değerine dönüştürülüp dönüştürülemeyeceğini kontrol eder. Sonuç, kodunuzun başka bir yerinde kullanılabilecek bir bayrağı gösterebilir.


İnt.TryParse için bağımsız değişken bir dize değil, bir dize.
Jim Balter

yourDouble.toString("G17")
BackDoorNoBaby

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.