วิธีการตรวจสอบว่าทศนิยม / สองครั้งเป็นจำนวนเต็ม?


225

ฉันจะรู้ได้อย่างไรว่าค่าทศนิยมหรือสองเท่าเป็นจำนวนเต็ม?

ตัวอย่างเช่น:

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

หรือ

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

เหตุผลที่ฉันอยากจะรู้ว่านี่เป็นเพื่อที่จะสามารถตรวจสอบโปรแกรมถ้าผมต้องการที่จะส่งออกค่าใช้หรือ.ToString("N0") .ToString("N2")หากไม่มีค่าทศนิยมแล้วฉันไม่ต้องการแสดงว่า

คำตอบ:


410

สำหรับหมายเลขทศนิยมn % 1 == 0มักจะเป็นวิธีการตรวจสอบว่ามีสิ่งใดที่ผ่านจุดทศนิยม

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

เอาท์พุท:

False
True

อัปเดต:ตามที่ @Adrian Lopez ได้กล่าวถึงด้านล่างการเปรียบเทียบด้วยค่าเล็กน้อยepsilonจะเป็นการยกเลิกการคำนวณเลขทศนิยม เนื่องจากคำถามเกี่ยวกับdoubleค่าด้านล่างจะเป็นคำตอบที่พิสูจน์การคำนวณแบบอิงดัชนี:

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

96
ใช้งานได้เมื่อจำนวนเริ่มต้นเป็นจำนวนเต็ม แต่ไม่จำเป็นเมื่อจำนวนนั้นเป็นผลลัพธ์ของการคำนวณจุดลอยตัวบางอย่าง สิ่งที่เกี่ยวกับเช่น "(d% 1) <epsilon" โดยที่ epsion มีค่าเล็กน้อย
Adrian Lopez

9
เป็นความอัปยศที่คำตอบที่ดีที่สุดในชุดข้อความนี้เป็นความคิดเห็นแทนที่จะตอบรับ นีซเอเดรีย
starskythehutch

13
ฉันคิดว่าความคิดเห็นของ Adrian ด้านบนเป็นคำตอบที่ดีที่สุด หากต้องการให้คำแนะนำของเขาในรหัส C # อย่างเป็นทางการ: ถ้า (Math.Abs ​​(n% 1) <Double.Epsilon) {// ทำบางสิ่งถ้า n เป็นจำนวนเต็ม}
Ruben Ramirez Padron

7
IMHO ผู้ประกอบการโมดูลัสและตัวเลขจุดลอยตัวไม่ได้ปะปนกันในทางที่เป็นประโยชน์ รหัสที่แนะนำมีความสับสนอย่างไม่น่าเชื่อเนื่องจากจำนวนการกดแป้นที่ใช้และจะทำงานแทบไม่มีที่ไหนเลยนอกภาษา. ฉันจะเดิมพันก็ช้ากว่าวิธีที่ถูกต้อง (ซึ่งไม่ได้ใช้การหารใด ๆ เลย) Math.Abs(d-(int)d) < double.Epsilonวิธีที่ถูกต้องในการทำเช่นนี้คือการใช้ เช่นเดียวกับที่เราทุกคนควรได้เรียนรู้ในสัปดาห์แรกของการเรียนการเขียนโปรแกรมครั้งแรกในวิทยาลัย
krowe2

9
จริงๆแล้วตามที่ระบุคำถามคำตอบนี้ถูกต้องและความคิดเห็นที่ไม่ถูกต้อง OP ไม่ต้องการทราบว่า double เป็นจำนวนเต็มสำหรับวัตถุประสงค์ทางคณิตศาสตร์หรือไม่ แต่จะแสดงอย่างไร ควรแสดงเฉพาะค่าจำนวนเต็มที่แน่นอนโดยไม่มีจุดทศนิยม นอกจากนี้ความคิดเห็นเกี่ยวกับ mod ไม่เป็นประโยชน์กับ floating point และไม่ทำงานนอก NET และ(int)dเป็นหายนะที่จะทำให้เกิดข้อยกเว้นสำหรับค่าสองเท่าส่วนใหญ่
Jim Balter

49

มีหลายวิธีในการทำเช่นนี้ ตัวอย่างเช่น:

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

คุณยังสามารถใช้โมดูโล

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

หนึ่งในนั้นจะเร็วกว่าอีกไหม ฉันต้องการทำสิ่งนี้ในบริบทที่อ่อนไหวด้านประสิทธิภาพ
บาซิล

@Basil - ขึ้นอยู่กับสถานการณ์ คุณควรกำหนดเวลาด้วยตัวคุณเองและตัดสิน
Erik Funkenbusch

4
Math.Abs(d-(int)d) < double.Epsilonปลอดภัยกว่าd == (int)d
Reactgular

3
@MathewFoscarini - ฉันคิดว่าคุณสับสน มันตั้งค่าเป็นเท็จเพราะผลลัพธ์ของ 16.1 - 6.1 ไม่ใช่ int จุดคือการค้นหาว่าค่าที่กำหนดเป็น int ไม่ใช่สิ่งที่ประมาณ int เป็น int
Erik Funkenbusch

1
@MathewFoscarini - ใช่ int เป็นตัวเลขที่ไม่มีค่าทศนิยม (หรือค่าทศนิยม 0) 16.1-6.1 ไม่ได้สร้างค่าทศนิยม 0 มันเป็นค่าที่ไม่เป็นศูนย์ขนาดเล็กมากซึ่งเกิดจากรูปแบบจุดลอย IEEE ไม่มีวิธีที่จะรู้ว่าตัวเลขที่ถูกจัดให้มีค่าทศนิยมหรือไม่ดังนั้นการสมมติว่าค่าการปัดเศษนั้นไม่ถูกต้อง จุดประสงค์ของคำถามคือเพื่อทราบว่าเลขทศนิยมเป็นจำนวนเต็มหรือไม่ไม่ว่าจะเป็นจำนวนเต็ม
Erik Funkenbusch

21

แล้วเรื่องนี้ล่ะ

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

decimalรหัสเดียวกัน

มาร์คยอร์สทำจุดดีจริง: นี้อาจไม่เป็นสิ่งที่คุณจริงๆต้องการ หากสิ่งที่คุณสนใจจริงๆคือตัวเลขที่ปัดเศษเป็นทศนิยมสองตำแหน่งที่ใกล้ที่สุดนั้นเป็นจำนวนเต็มหรือไม่คุณสามารถทำได้ดังนี้:

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

1
อาจอัปเดตโซลูชันของคุณและเพิ่ม: && number <int.MaxValue && number> int.MinValue
Walter Vehoeven

12

ในขณะที่วิธีแก้ปัญหาที่เสนอนั้นใช้งานได้เป็นตัวอย่าง จำนวนอาจจะไม่ตรงกับจำนวนเต็ม 1.000000แต่เมื่อคุณพยายามที่จะจัดรูปแบบมันก็ใกล้พอที่จะเป็นจำนวนเต็มที่คุณได้รับ สิ่งนี้สามารถเกิดขึ้นได้หากคุณทำการคำนวณว่าในทางทฤษฎีควรให้ 1 อย่างแน่นอน แต่ในทางปฏิบัติให้ตัวเลขใกล้เคียงกับ แต่ไม่เท่ากับหนึ่งเนื่องจากข้อผิดพลาดในการปัดเศษ

ให้จัดรูปแบบก่อนและถ้าสตริงของคุณลงท้ายด้วยจุดแล้วตามด้วยศูนย์ให้ดึงออกมา นอกจากนี้ยังมีบางรูปแบบที่คุณสามารถใช้ตัดค่าศูนย์ส่วนท้ายนั้นโดยอัตโนมัติ นี่อาจจะดีพอสำหรับวัตถุประสงค์ของคุณ

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

เอาท์พุท:

1
1.02

@ Mark ฟังดูน่าสนใจ คุณมีตัวอย่างของรูปแบบที่ตัดค่าศูนย์ต่อท้ายหรือไม่?
Jim Geurts

ฉันยอมรับว่ามันปลอดภัยกว่าและสิ่งที่ OP น่าจะทำ แต่มันไม่ใช่คำตอบสำหรับคำถามที่แคบลง (แต่น่าสนใจกว่า) ว่าค่ามีส่วนที่เป็นเศษส่วนหรือไม่
Clifford

3
@Clifford: ฉันมักจะพยายามตอบตามสิ่งที่ดีที่สุดในการแก้ปัญหา OP ไม่ได้ขึ้นอยู่กับสิ่งที่ชื่อพูด ชื่อเรื่องไม่ค่อยมีคำอธิบายที่ถูกต้องของปัญหา
Mark Byers

+1 ยอมรับว่าการพยายามทดสอบการลอยหรือดับเบิลเพื่อดูว่าพวกเขาอาจเป็น ints ไม่ดีเนื่องจากข้อผิดพลาดในการปัดเศษและแม่นยำ
Romain Hippeau

1
สำหรับการใช้เงินคุณอาจต้องการให้ 1.2 แสดงเป็น 1.20 ซึ่งไม่ใช่กรณีของโซลูชันที่แนะนำ ผู้รับใด ๆ
Kjell Rilbe


4

คำตอบของ Mark Rushakoff อาจจะง่ายกว่า แต่การปฏิบัติต่อไปนี้ใช้ได้ผลและอาจมีประสิทธิภาพมากกว่าเนื่องจากไม่มีการดำเนินการโดยปริยาย:

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

และ

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

หากคุณต้องการนิพจน์เดียวสำหรับทั้งสองประเภทอาจจะ

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

4

หากขอบบนและล่างของInt32เรื่อง:

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

การทดสอบครั้งแรกแล้วโยนแบบนี้มันจะทำให้เกิดข้อยกเว้นอื่น ๆ นอกเหนือจากการกลับมาผิด ๆ บางทีอาจอัพเดตคำตอบของคุณ
Walter Vehoeven

@ คอมพิวเตอร์ใช่จุดดี ผมคิดว่ามันจะขึ้นอยู่กับการตั้งค่าโปรเจคของคุณ
nawfal


2

คุณสามารถใช้การจัดรูปแบบสตริงสำหรับประเภทที่สอง นี่คือตัวอย่าง:

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"

แจ้งให้เราทราบหากสิ่งนี้ไม่ช่วย


1
นั่นไม่ได้ตอบคำถามในการพิจารณาว่าค่าไม่มีส่วนที่เป็นเศษส่วนหรือไม่ซึ่งเป็นคำถามทางคณิตศาสตร์ อย่างไรก็ตามมันอาจเป็นสิ่งที่ OP ต้องการได้รับข้อความอธิบายของเขา
Clifford

2
ใช่เขาต้องการเพียงแค่จัดรูปแบบค่าสองหรือทศนิยมโดยไม่ต้องจุดทศนิยม ขอบคุณ ...
BALKANGraph


0

ฉันต้องเผชิญกับสถานการณ์ที่คล้ายกัน แต่ค่าที่เป็นสตริง ผู้ใช้พิมพ์ค่าที่ควรจะเป็นจำนวนเงินดอลล่าร์ดังนั้นฉันต้องการตรวจสอบว่าเป็นตัวเลขและมีทศนิยมไม่เกินสองตำแหน่ง

นี่คือรหัสของฉันที่จะคืนค่าจริงถ้าสตริง "s" แทนตัวเลขที่มีทศนิยมไม่เกินสองตำแหน่งและเป็นเท็จ หลีกเลี่ยงปัญหาใด ๆ ที่อาจเกิดขึ้นจากการไม่ทราบค่าของเลขทศนิยม

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

ผมปรึกษาเรื่องนี้ในรายละเอียดเพิ่มเติมได้ที่http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html


4
สมมติว่าคุณกำลังทำงานกับวัฒนธรรมเดียว ตัวอย่างเช่นมันจะไม่ทำงานอย่างถูกต้องกับวัฒนธรรมที่ใช้แทนทศนิยมเช่น 1.000,00
Jim Geurts

0

การใช้ int.TryParse จะให้ผลลัพธ์เหล่านี้:

        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

อาจไม่ใช่วิธีที่หรูหราที่สุด แต่ใช้งานได้ถ้าคุณไม่จู้จี้จุกจิกเกินไป!

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

8
นี่เป็นวิธีการแก้ปัญหาที่เลวร้าย
Ospho

-2

คุณสามารถใช้วิธี 'TryParse'

int.TryParse()

สิ่งนี้จะตรวจสอบว่าสามารถแปลงค่าเป็นจำนวนเต็มจำนวนเต็มได้หรือไม่ ผลลัพธ์สามารถระบุการตั้งค่าสถานะซึ่งสามารถใช้ที่อื่นในรหัสของคุณ


อาร์กิวเมนต์สำหรับ int.TryParse เป็นสตริงไม่ใช่ double
Jim Balter

yourDouble.toString("G17")
BackDoorNoBaby

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.