Làm thế nào để xác định nếu một số thập phân / gấp đôi là một số nguyên?


225

Làm thế nào để tôi biết nếu một giá trị thập phân hoặc gấp đôi là một số nguyên?

Ví dụ:

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

hoặc là

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

Lý do tôi muốn biết điều này là để tôi có thể xác định theo chương trình nếu tôi muốn xuất giá trị bằng cách sử dụng .ToString("N0")hoặc .ToString("N2"). Nếu không có giá trị dấu thập phân, thì tôi không muốn hiển thị điều đó.

Câu trả lời:


410

Đối với số dấu phẩy động, n % 1 == 0thường là cách để kiểm tra xem có bất kỳ thứ gì vượt quá dấu thập phân không.

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

Đầu ra:

False
True

Cập nhật: Như @Adrian Lopez đã đề cập dưới đây, so sánh với một giá trị nhỏepsilonsẽ loại bỏ các phép tính sai tính toán dấu phẩy động. Vì câu hỏi là vềdoublecác giá trị, bên dưới sẽ làcâu trả lời bằng chứng tính toán dấu phẩy động hơn:

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

96
Điều đó hoạt động khi số bắt đầu dưới dạng một số nguyên, nhưng không nhất thiết khi số đó là kết quả của một số tính toán dấu phẩy động. Làm thế nào về một cái gì đó như "(d% 1) <epsilon" trong đó epsion là một giá trị nhỏ?
Adrian Lopez

9
Thật xấu hổ khi câu trả lời tốt nhất trong chủ đề này là một nhận xét, thay vì câu trả lời được chấp nhận. Một người tốt bụng.
starskythehutch

13
Tôi cũng nghĩ rằng nhận xét của Adrian ở trên là câu trả lời tốt nhất. Để đưa lời khuyên của mình vào mã C # chính thức: if (Math.Abs ​​(n% 1) <Double.Epsilon) {// Làm gì đó nếu n là số nguyên}.
Ruben Ramirez Padron

7
IMHO, toán tử mô đun và số dấu phẩy động không trộn lẫn theo bất kỳ cách nào hữu ích. Mã được đề xuất là vô cùng khó hiểu với số lượng tổ hợp phím được sử dụng và sẽ hoạt động gần như không ở đâu ngoài các ngôn ngữ .NET. Tôi cá là nó cũng chậm hơn nhiều so với cách chính xác (không sử dụng bất kỳ phân chia nào cả). Cách chính xác để làm điều này là sử dụng Math.Abs(d-(int)d) < double.Epsilon. Giống như tất cả chúng ta nên học trong tuần đầu tiên của lớp lập trình đầu tiên ở trường đại học.
krowe2

9
Trên thực tế, như câu hỏi được nêu, câu trả lời này là chính xác và các ý kiến ​​đều sai. OP không muốn biết liệu số kép có phải là số nguyên cho mục đích toán học hay không, mà là cách hiển thị nó. Chỉ các giá trị số nguyên chính xác mới được hiển thị mà không có dấu thập phân. Ngoài ra, nhận xét về mod không hữu ích với dấu phẩy động và không hoạt động bên ngoài .NET cũng không được thông báo rõ. Và (int)dlà một thảm họa sẽ ném một ngoại lệ cho hầu hết các giá trị kép.
Jim Balter

49

Có bất kỳ số cách để làm điều này. Ví dụ:

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

Bạn cũng có thể sử dụng modulo.

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

Một trong những cái này sẽ nhanh hơn cái kia? Tôi muốn làm điều này trong một bối cảnh nhạy cảm hiệu suất.
Basil

@Basil - Phụ thuộc vào hoàn cảnh. Bạn nên làm một số thời gian cho chính mình và đánh giá.
Erik Funkenbusch

4
Math.Abs(d-(int)d) < double.Epsilonan toàn hơnd == (int)d
Phản ứng

3
@MathewFoscarini - Tôi nghĩ bạn đang bối rối. Nó đặt thành false, vì kết quả của 16.1 - 6.1 không phải là int. Vấn đề là tìm xem một giá trị đã cho có phải là int không, nếu thứ gì đó xấp xỉ int là int.
Erik Funkenbusch

1
@MathewFoscarini - Có, số nguyên là số không có giá trị thập phân (hoặc giá trị thập phân bằng 0). 16.1-6.1 không tạo ra giá trị thập phân 0, đó là một giá trị khác không rất nhỏ do các quirks định dạng Dấu phẩy động của IEEE gây ra. Không có cách nào để biết liệu số đó có được CUNG CẤP để có giá trị thập phân hay không, do đó, giả sử giá trị làm tròn là không chính xác. Mục đích của câu hỏi là để biết liệu một số dấu phẩy động có phải là một số nguyên hay không, liệu nó có phải là một số nguyên hay không.
Erik Funkenbusch

21

Còn cái này thì sao?

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

Cùng mã cho decimal.

Mark Byers đã đưa ra một quan điểm tốt, thực sự: đây có thể không phải là điều bạn thực sự muốn. Nếu điều bạn thực sự quan tâm là liệu một số được làm tròn đến hai chữ số thập phân gần nhất có phải là số nguyên hay không , bạn có thể thực hiện việc này thay thế:

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

1
có lẽ cập nhật giải pháp của bạn và thêm: && số <int.MaxValue && number> int.MinValue
Walter Vehoeven

12

Trong khi các giải pháp được đề xuất dường như hoạt động cho các ví dụ đơn giản, thì việc làm này nói chung là một ý tưởng tồi. Một số có thể không chính xác là một số nguyên nhưng khi bạn cố gắng định dạng nó, nó đủ gần với một số nguyên mà bạn nhận được 1.000000. Điều này có thể xảy ra nếu bạn thực hiện một phép tính mà trên lý thuyết sẽ đưa ra chính xác 1, nhưng trong thực tế, đưa ra một con số rất gần nhưng không chính xác bằng một do sai số làm tròn.

Thay vào đó, định dạng nó trước và nếu chuỗi của bạn kết thúc trong một khoảng thời gian theo sau là số không thì hãy loại bỏ chúng. Ngoài ra còn có một số định dạng mà bạn có thể sử dụng các số 0 ở đó. Điều này có thể đủ tốt cho mục đích của bạn.

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

Đầu ra:

1
1.02

@Mark Nghe có vẻ thú vị. Bạn có một ví dụ về một định dạng dải số 0 không?
Jim Geurts

Tôi đồng ý rằng nó an toàn hơn và những gì OP có thể nên làm, nhưng nó không phải là câu trả lời cho câu hỏi hẹp hơn (nhưng thú vị hơn) về việc liệu một giá trị có một phần phân số hay không.
Clifford

3
@Clifford: Tôi thường cố gắng trả lời dựa trên những gì tốt nhất để giải quyết vấn đề OP, không dựa trên những gì tiêu đề nói. Các tiêu đề hiếm khi là một mô tả chính xác của vấn đề.
Mark Byers

+1 Đồng ý rằng việc thử kiểm tra số float hoặc nhân đôi để xem liệu chúng có thể là số nguyên không tốt do lỗi làm tròn và độ chính xác.
Romain Hippeau

1
Đối với việc sử dụng tiền, có lẽ bạn sẽ muốn 1,2 được hiển thị là 1,20, đây không phải là trường hợp với giải pháp được đề xuất. Có ai nhận không?
Kjell Rilbe

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

Vấn đề solvo.

Chỉnh sửa: Được viết bởi Mark Rushakoff.


4
hoặc chỉreturn ceil(num) == num && floor(num) == num;
Brian Rasmussen

13
hoặc chỉreturn ceil(num) == floor(num);
gregsdennis

4

Câu trả lời của Mark Rushakoff có thể đơn giản hơn, nhưng những điều sau đây cũng hoạt động và có thể hiệu quả hơn vì không có hoạt động phân chia ngầm định:

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

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

Nếu bạn muốn một biểu thức cho cả hai loại, có lẽ

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

4

Nếu giới hạn trên và dưới của Int32vấn đề:

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

Thử nghiệm đầu tiên, sau đó thực hiện như thế này, nó sẽ đưa ra một ngoại lệ khác ngoài trả về sai, có thể cập nhật câu trả lời của bạn
Walter Vehoeven

@ máy tính, vâng điểm tốt. Về việc ném vào dàn diễn viên, tôi đoán nó sẽ phụ thuộc vào thiết lập dự án của bạn.
nawfal

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

2

Bạn có thể sử dụng định dạng chuỗi cho loại kép. Đây là một ví dụ:

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"

Hãy cho tôi biết nếu điều này không giúp đỡ.


1
Điều đó không thực sự giải quyết câu hỏi xác định xem một giá trị không có phần phân số, đó là một câu hỏi toán học. Tuy nhiên, đó có lẽ là những gì OP cần đưa ra lưu ý giải thích của mình.
Clifford

2
Có, anh ta chỉ muốn định dạng giá trị gấp đôi hoặc thập phân mà không có dấu thập phân. Cảm ơn bạn ...
BALKANGraph


0

Tôi đã phải đối mặt với một tình huống tương tự, nhưng trong đó giá trị là một chuỗi. Người dùng nhập vào một giá trị được coi là số tiền, vì vậy tôi muốn xác thực rằng đó là số và có nhiều nhất là hai chữ số thập phân.

Đây là mã của tôi để trả về true nếu chuỗi "s" đại diện cho một số có nhiều nhất hai chữ số thập phân và ngược lại là sai. Nó tránh mọi vấn đề có thể xảy ra do sự thiếu chính xác của các giá trị dấu phẩy động.

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

Tôi thảo luận chi tiết hơn tại http://progblog10.blogspot.com/2011/04/determining-whether-numeric-value-has.html .


4
Điều này giả định rằng bạn đang làm việc với một nền văn hóa. Ví dụ: Nó sẽ không hoạt động đúng với các nền văn hóa đại diện cho số thập phân như 1.000,00
Jim Geurts

0

Sử dụng int.TryPude sẽ mang lại những kết quả sau:

        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

Có lẽ không phải là giải pháp thanh lịch nhất nhưng nó hoạt động nếu bạn không quá cầu kỳ!

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

8
Đây là một giải pháp khủng khiếp
Ospho

-2

Bạn có thể sử dụng phương pháp 'TryPude'.

int.TryParse()

Điều này kiểm tra xem giá trị có thể được chuyển đổi thành giá trị số nguyên không. Kết quả sau đó có thể chỉ ra một cờ có thể được sử dụng ở nơi khác trong mã của bạn.


Đối số cho int.TryPude là một chuỗi, không phải là một chuỗi.
Jim Balter

yourDouble.toString("G17")
BackDoorNoBaby

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.