Sự khác biệt giữa thập phân, float và double trong .NET?


Câu trả lời:


2267

floatdoublecác loại điểm nhị phân nổi . Nói cách khác, chúng đại diện cho một số như thế này:

10001.10010110011

Số nhị phân và vị trí của điểm nhị phân đều được mã hóa trong giá trị.

decimallà một nổi thập phân loại điểm . Nói cách khác, chúng đại diện cho một số như thế này:

12345.65789

Một lần nữa, số và vị trí của dấu thập phân đều được mã hóa trong giá trị - đó là những gì làm cho decimalvẫn là loại dấu phẩy động thay vì loại điểm cố định.

Điều quan trọng cần lưu ý là con người được sử dụng để biểu diễn các số nguyên không ở dạng thập phân và mong đợi kết quả chính xác trong các biểu diễn thập phân; không phải tất cả các số thập phân đều có thể biểu diễn chính xác trong dấu phẩy động nhị phân - ví dụ 0,1 - vì vậy nếu bạn sử dụng giá trị dấu phẩy động nhị phân, bạn sẽ thực sự có được xấp xỉ 0,1. Bạn vẫn sẽ nhận được xấp xỉ khi sử dụng dấu thập phân trôi nổi - ví dụ, kết quả của việc chia 1 cho 3 không thể được biểu diễn chính xác.

Đối với những gì để sử dụng khi:

  • Đối với các giá trị là "số thập phân chính xác tự nhiên", nên sử dụng decimal. Điều này thường phù hợp với bất kỳ khái niệm nào được phát minh bởi con người: giá trị tài chính là ví dụ rõ ràng nhất, nhưng cũng có những khái niệm khác. Ví dụ, hãy xem xét số điểm được trao cho thợ lặn hoặc người trượt băng.

  • Đối với các giá trị là nhiều vật phẩm tự nhiên hơn mà thực sự không thể đo được chính xác , float/ doublephù hợp hơn. Ví dụ, dữ liệu khoa học thường sẽ được trình bày dưới dạng này. Ở đây, các giá trị ban đầu sẽ không "chính xác về mặt chính xác" để bắt đầu, do đó, kết quả mong đợi để duy trì "độ chính xác thập phân" là không quan trọng. Các loại điểm nhị phân nổi có tốc độ làm việc nhanh hơn nhiều so với số thập phân.


58
float/ doublethường không đại diện cho các số như 101.101110, thông thường nó được biểu diễn dưới dạng 1101010 * 2^(01010010)một số mũ
Mingwei Samuel

79
@Hazzard: Đó là phần "và vị trí của điểm nhị phân" trong câu trả lời có nghĩa là gì.
Jon Skeet

112
Tôi ngạc nhiên khi nó chưa được nói, floatlà một từ khóa bí danh C # và không phải là một loại .Net. đó là System.Single.. singledoublelà các loại điểm nhị phân nổi.
Brett Caswell

54
@BKSpurgeon: Chà, chỉ theo cùng một cách mà bạn có thể nói rằng mọi thứ đều là loại nhị phân, tại thời điểm đó, nó trở thành một định nghĩa khá vô dụng. Số thập phân là một loại thập phân trong đó nó là một số được biểu thị dưới dạng số nguyên và tỷ lệ, sao cho kết quả là tỷ lệ * 10 ^, trong khi số float và double là tỷ lệ có ý nghĩa * 2 ^. Bạn lấy một số được viết bằng số thập phân và di chuyển dấu thập phân đủ xa sang bên phải để bạn có một số nguyên để tìm ra ý nghĩa và tỷ lệ. Đối với float / double, bạn bắt đầu với một số được viết bằng nhị phân.
Jon Skeet

21
Một điểm khác biệt: float 32-bit; nhân đôi 64 bit; và số thập phân 128 bit.
David

1073

Chính xác là sự khác biệt chính.

Float - 7 chữ số (32 bit)

Nhân đôi -15-16 chữ số (64 bit)

Số thập phân -28-29 chữ số có nghĩa (128 bit)

Số thập phân có độ chính xác cao hơn nhiều và thường được sử dụng trong các ứng dụng tài chính đòi hỏi độ chính xác cao. Số thập phân chậm hơn nhiều (tới 20 lần trong một số thử nghiệm) so với số lần tăng / gấp đôi.

Số thập phân và Floats / Double có thể được so sánh mà không cần cast trong khi Floats và Double có thể. Số thập phân cũng cho phép các số không mã hóa hoặc dấu.

float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);

Kết quả :

float: 0.3333333  
double: 0.333333333333333  
decimal: 0.3333333333333333333333333333

65
@Thecrocodhunter: xin lỗi, nhưng không. Số thập phân có thể biểu thị tất cả các số có thể được biểu thị bằng ký hiệu thập phân, nhưng không phải là 1/3 chẳng hạn. 1.0m / 3.0m sẽ ước tính đến 0.33333333 ... với số lượng lớn nhưng hữu hạn là 3 giây ở cuối. Nhân số đó với 3 sẽ không trả về chính xác 1.0.
Erik P.

50
@Thecrocodhunter: Tôi nghĩ bạn khó hiểu chính xác và chính xác. Chúng là những thứ khác nhau trong bối cảnh này. Chính xác là số chữ số có sẵn để đại diện cho một số. Càng chính xác, bạn càng cần phải làm tròn. Không có loại dữ liệu có độ chính xác vô hạn.
Igby Largeeman

13
@Thecrocodhunter: Bạn đang cho rằng giá trị được đo là chính xác 0.1 - điều đó hiếm khi xảy ra trong thế giới thực! Bất kỳ định dạng lưu trữ hữu hạn nào cũng sẽ kết hợp một số lượng vô hạn các giá trị có thể với một số mẫu bit hữu hạn. Ví dụ, floatsẽ conf conf 0.10.1 + 1e-8, trong khi decimalsẽ confatter 0.10.1 + 1e-29. Chắc chắn, trong một phạm vi nhất định, một số giá trị nhất định có thể được biểu diễn ở bất kỳ định dạng nào với độ chính xác bằng 0 (ví dụ: floatcó thể lưu trữ bất kỳ số nguyên nào lên tới 1.6e7 mà không mất độ chính xác) - nhưng đó vẫn không phải là độ chính xác vô hạn .
Daniel Pryden

27
@Thecrocodhunter: Bạn đã bỏ lỡ quan điểm của tôi. 0.1không phải là một giá trị đặc biệt ! Điều duy nhất làm cho 0.1"tốt hơn" 0.10000001là bởi vì con người thích cơ sở 10. Và thậm chí với một floatgiá trị, nếu bạn khởi tạo hai giá trị theo 0.1cùng một cách, cả hai sẽ có cùng giá trị . Chỉ là giá trị đó sẽ không chính xác 0.1 - nó sẽ là giá trị gần nhất 0.1có thể được biểu diễn chính xác như mộtfloat . Chắc chắn, với phao nhị phân (1.0 / 10) * 10 != 1.0, nhưng với phao thập phân, (1.0 / 3) * 3 != 1.0hoặc. Không phảihoàn toàn chính xác.
Daniel Pryden

16
@Thecrocodhunter: Bạn vẫn chưa hiểu. Tôi không biết làm thế nào để nói điều này rõ ràng hơn: Trong C, nếu bạn làm thế double a = 0.1; double b = 0.1;thì a == b sẽ đúng . Chỉ có vậy acả haib sẽ không chính xác như nhau . Trong C #, nếu bạn làm thì cũng sẽ đúng. Nhưng trong trường hợp đó, không phải của cũng sẽ chính xác tương đương - họ sẽ cả bình đẳng . Trong cả hai trường hợp, một số độ chính xác bị mất do đại diện. Bạn bướng bỉnh nói rằng có độ chính xác "vô hạn", đó là sai . 0.1decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;a == bab1/30.3333...decimal
Daniel Pryden

84

Cấu trúc thập phân được định hướng chặt chẽ cho các tính toán tài chính đòi hỏi độ chính xác, tương đối không dung nạp được làm tròn. Số thập phân không đủ cho các ứng dụng khoa học, tuy nhiên, vì một số lý do:

  • Một sự mất mát chính xác nhất định có thể được chấp nhận trong nhiều tính toán khoa học vì các giới hạn thực tế của vấn đề vật lý hoặc tạo tác được đo. Mất độ chính xác không được chấp nhận trong tài chính.
  • Decimal chậm hơn nhiều so với float và double đối với hầu hết các hoạt động, chủ yếu là do các hoạt động của dấu phẩy động được thực hiện ở dạng nhị phân, trong khi công cụ Decimal được thực hiện trong cơ sở 10 (tức là float và double được xử lý bởi phần cứng FPU, chẳng hạn như MMX / SSE , trong khi số thập phân được tính trong phần mềm).
  • Decimal có phạm vi giá trị nhỏ hơn không thể chấp nhận được gấp đôi, mặc dù thực tế là nó hỗ trợ nhiều chữ số chính xác hơn. Do đó, Decimal không thể được sử dụng để thể hiện nhiều giá trị khoa học.

5
Nếu bạn đang thực hiện các tính toán tài chính, bạn hoàn toàn phải cuộn các kiểu dữ liệu của riêng mình hoặc tìm một thư viện tốt phù hợp với nhu cầu chính xác của bạn. Độ chính xác trong môi trường tài chính được xác định bởi các cơ quan tiêu chuẩn (con người) và họ có các quy tắc địa phương hóa (cả về thời gian và địa lý) rất cụ thể về cách thực hiện các phép tính. Những thứ như làm tròn chính xác không được ghi lại trong các kiểu dữ liệu số đơn giản trong .Net. Khả năng tính toán chỉ là một phần rất nhỏ của câu đố.
James Moore

76
+---------+----------------+---------+----------+---------------------------------------------+
| C#      | .Net Framework | Signed? | Bytes    | Possible Values                             |
| Type    | (System) type  |         | Occupied |                                             |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte   | System.Sbyte   | Yes     | 1        | -128 to 127                                 |
| short   | System.Int16   | Yes     | 2        | -32768 to 32767                             |
| int     | System.Int32   | Yes     | 4        | -2147483648 to 2147483647                   |
| long    | System.Int64   | Yes     | 8        | -9223372036854775808 to 9223372036854775807 |
| byte    | System.Byte    | No      | 1        | 0 to 255                                    |
| ushort  | System.Uint16  | No      | 2        | 0 to 65535                                  |
| uint    | System.UInt32  | No      | 4        | 0 to 4294967295                             |
| ulong   | System.Uint64  | No      | 8        | 0 to 18446744073709551615                   |
| float   | System.Single  | Yes     | 4        | Approximately ±1.5 x 10-45 to ±3.4 x 1038   |
|         |                |         |          |  with 7 significant figures                 |
| double  | System.Double  | Yes     | 8        | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
|         |                |         |          |  with 15 or 16 significant figures          |
| decimal | System.Decimal | Yes     | 12       | Approximately ±1.0 x 10-28 to ±7.9 x 1028   |
|         |                |         |          |  with 28 or 29 significant figures          |
| char    | System.Char    | N/A     | 2        | Any Unicode character (16 bit)              |
| bool    | System.Boolean | N/A     | 1 / 2    | true or false                               |
+---------+----------------+---------+----------+---------------------------------------------+

Xem ở đây để biết thêm thông tin .


5
Bạn đã bỏ qua sự khác biệt lớn nhất, đó là cơ sở được sử dụng cho loại thập phân (số thập phân được lưu trữ dưới dạng cơ sở 10, tất cả các loại số khác được liệt kê là cơ sở 2).
BrainSlugs83 14/03/2015

1
Phạm vi giá trị cho Đơn và Đôi không được mô tả chính xác trong hình ảnh trên hoặc bài đăng trên diễn đàn nguồn. Vì chúng ta không thể dễ dàng ghi lại văn bản ở đây, hãy sử dụng ký tự dấu mũ: Đơn nên là 10 ^ -45 và 10 ^ 38, và Double phải là 10 ^ -324 và 10 ^ 308. Ngoài ra, MSDN có số float với phạm vi -3,4x10 ^ 38 đến + 3,4x10 ^ 38. Tìm kiếm MSDN cho System.Single và System.Double trong trường hợp thay đổi liên kết. Độc thân: msdn.microsoft.com/en-us/l
Library / b1e65aza.aspx

2
Số thập phân là 128 bit ... có nghĩa là nó chiếm 16 byte chứ không phải 12
user1477332

51

Tôi sẽ không nhắc lại hàng tấn thông tin tốt (và một số thông tin xấu) đã được trả lời trong các câu trả lời và nhận xét khác, nhưng tôi sẽ trả lời câu hỏi tiếp theo của bạn bằng một mẹo:

Khi nào thì ai đó sẽ sử dụng một trong những thứ này?

Sử dụng số thập phân cho các giá trị được tính

Sử dụng float / double cho các giá trị đo

Vài ví dụ:

  • tiền (chúng ta đếm tiền hay đo tiền?)

  • khoảng cách (chúng ta có tính khoảng cách hoặc đo khoảng cách không? *)

  • điểm số (chúng ta có tính điểm hay đo điểm không?)

Chúng tôi luôn luôn đếm tiền và không bao giờ nên đo lường nó. Chúng tôi thường đo khoảng cách. Chúng tôi thường tính điểm.

* Trong một số trường hợp, cái mà tôi gọi là khoảng cách danh nghĩa , chúng ta thực sự có thể muốn 'đếm' khoảng cách. Ví dụ: có thể chúng ta đang xử lý các dấu hiệu quốc gia hiển thị khoảng cách đến các thành phố và chúng ta biết rằng những khoảng cách đó không bao giờ có nhiều hơn một chữ số thập phân (xxx.x km).


1
Tôi thực sự thích câu trả lời này, đặc biệt là câu hỏi "chúng ta đếm hay đo tiền?" Tuy nhiên, ngoài tiền, tôi không thể nghĩ ra bất cứ thứ gì được "tính" không chỉ đơn giản là số nguyên. Tôi đã thấy một số ứng dụng sử dụng số thập phân đơn giản vì double có quá ít chữ số có nghĩa. Nói cách khác, số thập phân có thể được sử dụng vì C # không có loại tăng gấp bốn lần en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
John Henckel

48

float 7 chữ số chính xác

double có khoảng 15 chữ số chính xác

decimal có khoảng 28 chữ số chính xác

Nếu bạn cần độ chính xác tốt hơn, sử dụng gấp đôi thay vì nổi. Trong các CPU hiện đại, cả hai loại dữ liệu đều có hiệu năng gần như giống nhau. Lợi ích duy nhất của việc sử dụng phao là chúng chiếm ít không gian hơn. Thực tế chỉ quan trọng nếu bạn có nhiều người trong số họ.

Tôi thấy điều này thật thú vị. Những gì mọi nhà khoa học máy tính nên biết về số học dấu phẩy động


1
@RogerLipscombe: Tôi sẽ xem xét doublethích hợp trong các ứng dụng kế toán trong những trường hợp đó (và về cơ bản chỉ những trường hợp đó) khi không có loại số nguyên lớn hơn 32 bit và doubleđược sử dụng như thể đó là loại số nguyên 53 bit (ví dụ: để giữ toàn bộ số xu, hoặc toàn bộ một phần trăm của một xu). Ngày nay không sử dụng nhiều cho những thứ như vậy, nhưng nhiều ngôn ngữ đã đạt được khả năng sử dụng các giá trị dấu phẩy động có độ chính xác kép từ lâu trước khi chúng đạt được toán học số nguyên 64 bit (hoặc trong một số trường hợp thậm chí là 32 bit!).
supercat

1
Câu trả lời của bạn ngụ ý độ chính xác là sự khác biệt duy nhất giữa các loại dữ liệu này. Với số học dấu phẩy động nhị phân thường được triển khai trong phần cứng FPU , hiệu năng là một sự khác biệt đáng kể. Điều này có thể không quan trọng đối với một số ứng dụng, nhưng rất quan trọng đối với những ứng dụng khác.
thuyền

6
@supercat đôi không bao giờ đúng trong các ứng dụng kế toán. Bởi vì Double chỉ có thể xấp xỉ các giá trị thập phân (ngay cả trong phạm vi độ chính xác của chính nó). Điều này là do lưu trữ gấp đôi các giá trị theo định dạng lệch tâm cơ sở 2 (nhị phân).
BrainSlugs83

2
@ BrainSlugs83: Việc sử dụng các loại dấu phẩy động để giữ các đại lượng không phải là số nguyên sẽ không phù hợp, nhưng về mặt lịch sử, các ngôn ngữ có các loại dấu phẩy động có thể biểu thị chính xác các giá trị số lớn hơn các số nguyên của chúng . Có lẽ ví dụ cực đoan nhất là Turbo-87 với các loại số nguyên duy nhất được giới hạn ở -32768 đến +32767, nhưng RealIIRC có thể biểu thị các giá trị lên tới 1.8E + 19 với độ chính xác đơn vị. Tôi nghĩ rằng sẽ tốt hơn nhiều cho một ứng dụng kế toán được sử dụng Realđể đại diện cho toàn bộ số xu hơn ...
supercat

1
... Để nó cố gắng thực hiện phép toán đa độ chính xác bằng cách sử dụng một loạt các giá trị 16 bit. Đối với hầu hết các ngôn ngữ khác, sự khác biệt không quá lớn, nhưng trong một thời gian dài, rất phổ biến đối với các ngôn ngữ không có bất kỳ loại số nguyên nào vượt quá 4E9 nhưng có doubleloại có độ chính xác đơn vị lên đến 9E15. Nếu người ta cần lưu trữ toàn bộ số lớn hơn loại số nguyên lớn nhất hiện có, việc sử dụng doublecó thể đơn giản và hiệu quả hơn so với cố gắng làm mờ toán học đa độ chính xác, đặc biệt là trong khi các bộ xử lý có hướng dẫn thực hiện 16x16-> 32 hoặc. ..
supercat

36

Không ai đề cập đến điều đó

Trong cài đặt mặc định, Floats (System.Single) và double (System.Double) sẽ không bao giờ sử dụng kiểm tra tràn trong khi Decimal (System.Decimal) sẽ luôn sử dụng kiểm tra tràn.

Ý tôi là

decimal myNumber = decimal.MaxValue;
myNumber += 1;

ném OverflowException .

Nhưng những điều này không:

float myNumber = float.MaxValue;
myNumber += 1;

&

double myNumber = double.MaxValue;
myNumber += 1;

1
float.MaxValue+1 == float.MaxValue, Giống như decimal.MaxValue+0.1D == decimal.MaxValue. Có lẽ bạn có ý nghĩa như thế float.MaxValue*2nào?
supercat

@supercar Nhưng không đúng là thập phân.MaxValue + 1 == binary.MaxValue
GorkemHalulu 14/1/2015

@supercar binary.MaxValue + 0.1m == binary.MaxValue ok
GorkemHalulu 14/1/2015

1
Việc System.Decimalném một ngoại lệ ngay trước khi nó trở nên không thể phân biệt toàn bộ các đơn vị, nhưng nếu một ứng dụng được cho là đang xử lý ví dụ như đô la và xu, thì điều đó có thể là quá muộn.
supercat

28
  1. Double và float có thể được chia cho số nguyên 0 mà không có ngoại lệ ở cả thời gian biên dịch và thời gian chạy.
  2. Số thập phân không thể chia cho số nguyên bằng không. Biên dịch sẽ luôn thất bại nếu bạn làm điều đó.

6
Họ chắc chắn có thể! Chúng cũng có một vài giá trị "ma thuật" như Vô cực, Vô cực âm và NaN (không phải số), điều này rất hữu ích để phát hiện các đường thẳng đứng trong khi tính toán độ dốc ... Hơn nữa, nếu bạn cần quyết định giữa việc gọi phao .TryPude, double.TryPude và binary.TryPude (để phát hiện xem một chuỗi là một số chẳng hạn), tôi khuyên bạn nên sử dụng double hoặc float, vì chúng sẽ phân tích cú pháp "Infinity", "-Infinity" và "NaN" đúng cách , trong khi thập phân sẽ không.
BrainSlugs83

Quá trình biên dịch chỉ thất bại nếu bạn cố chia một chữ decimalbằng 0 (CS0020), và điều tương tự cũng đúng với chữ nguyên. Tuy nhiên, nếu giá trị thập phân thời gian chạy được chia cho 0, bạn sẽ nhận được một ngoại lệ không phải là lỗi biên dịch.
Drew Noakes

@ BrainSlugs83 Tuy nhiên, bạn có thể không muốn phân tích "Vô cực" hoặc "NaN" tùy theo ngữ cảnh. Có vẻ như là một khai thác tốt cho đầu vào của người dùng nếu nhà phát triển không đủ nghiêm túc.
Mùa đông

28

Số nguyên, như đã đề cập, là số nguyên. Họ không thể lưu trữ điểm gì đó, như .7, .42 và .007. Nếu bạn cần lưu trữ các số không phải là số nguyên, bạn cần một loại biến khác. Bạn có thể sử dụng loại kép hoặc loại nổi. Bạn đặt các loại biến này theo cùng một cách chính xác: thay vì sử dụng từ này int, bạn nhập doublehoặc float. Như thế này:

float myFloat;
double myDouble;

( floatviết tắt của "dấu phẩy động" và chỉ có nghĩa là một số có một điểm gì đó ở cuối.)

Sự khác biệt giữa hai là ở kích thước của các số mà họ có thể giữ. Đối với float, bạn có thể có tối đa 7 chữ số trong số của bạn. Đối với doubles, bạn có thể có tối đa 16 chữ số. Nói chính xác hơn, đây là kích thước chính thức:

float:  1.5 × 10^-45  to 3.4 × 10^38  
double: 5.0 × 10^-324 to 1.7 × 10^308

floatlà số 32 bit và doublelà số 64 bit.

Nhấp đúp chuột vào nút mới của bạn để lấy mã. Thêm ba dòng sau vào mã nút của bạn:

double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());

Dừng chương trình của bạn và quay lại cửa sổ mã hóa. Thay đổi dòng này:

myDouble = 0.007;
myDouble = 12345678.1234567;

Chạy chương trình của bạn và nhấp vào nút đôi của bạn. Hộp thông báo hiển thị chính xác số. Tuy nhiên, thêm một số khác vào cuối và C # sẽ lại làm tròn lên hoặc xuống. Đạo đức là nếu bạn muốn chính xác, hãy cẩn thận làm tròn!


2
"Điểm gì đó" mà bạn đề cập thường được gọi là "phần phân số" của một số. "Điểm nổi" không có nghĩa là "một số có điểm ở cuối"; nhưng thay vào đó "Điểm nổi" phân biệt loại số, trái ngược với số "Điểm cố định" (cũng có thể lưu trữ giá trị phân số); sự khác biệt là cho dù độ chính xác là cố định hay nổi. - Số điểm nổi cung cấp cho bạn phạm vi giá trị động lớn hơn nhiều (Min và Max), với chi phí chính xác, trong khi số điểm cố định cung cấp cho bạn số lượng chính xác không đổi với chi phí phạm vi.
BrainSlugs83

16
  • số float: ± 1,5 x 10 ^ -45 đến ± 3,4 x 10 ^ 38 (~ 7 số liệu có ý nghĩa
  • gấp đôi: ± 5.0 x 10 ^ -324 đến ± 1.7 x 10 ^ 308 (15-16 số liệu có ý nghĩa)
  • số thập phân: ± 1.0 x 10 ^ -28 đến ± 7.9 x 10 ^ 28 (28-29 số liệu có ý nghĩa)

9
Sự khác biệt không chỉ là độ chính xác. - decimalthực sự được lưu trữ ở định dạng thập phân (trái ngược với cơ sở 2; vì vậy nó sẽ không bị mất hoặc các chữ số tròn do chuyển đổi giữa hai hệ thống số); ngoài ra, decimalkhông có khái niệm về các giá trị đặc biệt như NaN, -0, hoặc -∞.
BrainSlugs83

13

Đây là một chủ đề thú vị đối với tôi, vì ngày nay, chúng ta vừa gặp một lỗi nhỏ khó chịu, liên quan đến decimalviệc có độ chính xác thấp hơn mộtfloat .

Trong mã C # của chúng tôi, chúng tôi đang đọc các giá trị số từ bảng tính Excel, chuyển đổi chúng thành một decimal, sau đó gửi decimallại cho Dịch vụ để lưu vào cơ sở dữ liệu SQL Server .

Microsoft.Office.Interop.Excel.Range cell = 
object cellValue = cell.Value2;
if (cellValue != null)
{
    decimal value = 0;
    Decimal.TryParse(cellValue.ToString(), out value);
}

Bây giờ, đối với hầu hết tất cả các giá trị Excel của chúng tôi, điều này đã hoạt động rất tốt. Nhưng đối với một số người, các giá trị Excel rất nhỏ, sử dụng decimal.TryParseđã mất hoàn toàn giá trị. Một ví dụ như vậy là

  • cellValue = 0,00006317592

  • Decimal.TryPude (cellValue.ToString (), out value); // sẽ trả về 0

Giải pháp, thật kỳ lạ, là chuyển đổi các giá trị Excel thành doubleđầu tiên, sau đó thành mộtdecimal :

Microsoft.Office.Interop.Excel.Range cell = 
object cellValue = cell.Value2;
if (cellValue != null)
{
    double valueDouble = 0;
    double.TryParse(cellValue.ToString(), out valueDouble);
    decimal value = (decimal) valueDouble;
    
}

Mặc dù doublecó độ chính xác thấp hơn a decimal, nhưng số lượng nhỏ thực sự đảm bảo này vẫn sẽ được công nhận. Vì một số lý do, double.TryParsethực tế đã có thể lấy được số lượng nhỏ như vậy, trong khidecimal.TryParse sẽ đặt chúng về 0.

Lạ Rất kỳ quặc.


3
Vì tò mò, giá trị thô của cellValue.ToString () là gì? Decimal.TryPude ("0,00006317592", hết val) dường như hoạt động ...
micahtan

11
-1 Đừng hiểu sai ý tôi, nếu đúng, nó rất thú vị nhưng đây là một câu hỏi riêng biệt, nó chắc chắn không phải là một câu trả lời cho câu hỏi này.
weston

2
Có thể do ô Excel đã trả về giá trị gấp đôi và giá trị ToString () là "6.31759E-05", do đó, số thập phân.Pude () không giống như ký hiệu. Tôi đặt cược nếu bạn đã kiểm tra giá trị trả về của Decimal.TryPude () thì nó sẽ là sai.
SergioL

2
@weston Câu trả lời thường bổ sung cho các câu trả lời khác bằng cách điền vào các sắc thái mà họ đã bỏ lỡ. Câu trả lời này nêu bật một sự khác biệt về mặt phân tích cú pháp. Nó là rất nhiều một câu trả lời cho câu hỏi!
Robino

1
Er ... decimal.Parse("0.00006317592")hoạt động - bạn đã có một cái gì đó khác đang diễn ra. - Có thể ký hiệu khoa học?
BrainSlugs83

9

Đối với các ứng dụng như trò chơi và hệ thống nhúng trong đó bộ nhớ và hiệu suất đều quan trọng, float thường là loại lựa chọn số vì nó nhanh hơn và bằng một nửa kích thước gấp đôi. Các số nguyên từng là vũ khí được lựa chọn, nhưng hiệu suất điểm nổi đã vượt qua số nguyên trong các bộ xử lý hiện đại. Số thập phân là đúng!


Khá nhiều hệ thống hiện đại, thậm chí cả điện thoại di động, đều hỗ trợ phần cứng gấp đôi; và nếu trò chơi của bạn có vật lý đơn giản, bạn sẽ nhận thấy sự khác biệt lớn giữa nhân đôi và nổi. (Ví dụ: tính toán vận tốc / ma sát trong bản sao Asteroid đơn giản, tăng gấp đôi cho phép gia tốc chảy trôi chảy hơn nhiều so với phao. - Có vẻ như điều đó không quan trọng, nhưng hoàn toàn không.)
BrainSlugs83

Nhân đôi cũng gấp đôi kích thước của số float, nghĩa là bạn cần phải nhai gấp đôi số lượng dữ liệu, điều này làm tổn hại đến hiệu suất bộ nhớ cache của bạn. Như mọi khi, đo lường và tiến hành phù hợp.
yoyo

7

Các loại biến số thập phân, kép và nổi khác nhau theo cách chúng lưu trữ các giá trị. Độ chính xác là điểm khác biệt chính trong đó float là kiểu dữ liệu dấu phẩy động có độ chính xác đơn (32 bit), double là kiểu dữ liệu dấu phẩy động chính xác (64 bit) và thập phân là kiểu dữ liệu dấu phẩy động 128 bit.

Float - 32 bit (7 chữ số)

Nhân đôi - 64 bit (15-16 chữ số)

Số thập phân - 128 bit (28-29 chữ số có nghĩa)

Tìm hiểu thêm về ... sự khác biệt giữa Thập phân, Nổi và Đôi


5

Vấn đề với tất cả các loại này là một sự thiếu chính xác nhất định VÀ vấn đề này có thể xảy ra với các số thập phân nhỏ như trong ví dụ sau

Dim fMean as Double = 1.18
Dim fDelta as Double = 0.08
Dim fLimit as Double = 1.1

If fMean - fDelta < fLimit Then
    bLower = True
Else
    bLower = False
End If

Câu hỏi: Biến bLower chứa giá trị nào?

Trả lời: Trên máy 32 bit, bLower chứa TRUE !!!

Nếu tôi thay thế Double by Decimal, bLower chứa FALSE là câu trả lời tốt.

Nhân đôi, vấn đề là fMean-fDelta = 1.09999999999 thấp hơn 1.1.

Thận trọng: Tôi nghĩ rằng cùng một vấn đề chắc chắn có thể tồn tại đối với số khác vì Decimal chỉ là một gấp đôi với độ chính xác cao hơn và độ chính xác luôn luôn là một giới hạn.

Trên thực tế, Double, Float và Decimal tương ứng với số thập phân BINary trong COBOL!

Thật đáng tiếc rằng các loại số khác được triển khai trong COBOL không tồn tại trong .Net. Đối với những người không biết về COBOL, tồn tại trong COBOL theo kiểu số

BINARY or COMP like float or double or decimal
PACKED-DECIMAL or COMP-3 (2 digit in 1 byte)
ZONED-DECIMAL (1 digit in 1 byte) 

4

Nói một cách đơn giản:

  1. Các loại biến số thập phân, kép và nổi khác nhau theo cách chúng lưu trữ các giá trị.
  2. Độ chính xác là sự khác biệt chính (Lưu ý rằng đây không phải là sự khác biệt duy nhất) trong đó float là loại dữ liệu dấu phẩy động có độ chính xác đơn (32 bit), gấp đôi là loại dữ liệu dấu phẩy động chính xác (64 bit) và thập phân là 128 bit kiểu dữ liệu dấu phẩy động.
  3. Bảng tóm tắt:

/==========================================================================================
    Type       Bits    Have up to                   Approximate Range 
/==========================================================================================
    float      32      7 digits                     -3.4 × 10 ^ (38)   to +3.4 × 10 ^ (38)
    double     64      15-16 digits                 ±5.0 × 10 ^ (-324) to ±1.7 × 10 ^ (308)
    decimal    128     28-29 significant digits     ±7.9 x 10 ^ (28) or (1 to 10 ^ (28)
/==========================================================================================
Bạn có thể đọc thêm ở đây , Float , DoubleDecimal .


Câu trả lời này thêm gì chưa được bao gồm trong các câu trả lời hiện có? BTW, "hoặc" trong dòng "thập phân" của bạn không chính xác: dấu gạch chéo trong trang web mà bạn đang sao chép từ biểu thị phân chia thay vì thay thế.
Mark Dickinson

1
Và tôi tranh cãi mạnh mẽ rằng độ chính xác là sự khác biệt chính. Sự khác biệt chính là cơ sở: dấu phẩy động thập phân so với dấu phẩy động nhị phân. Sự khác biệt đó là những gì Decimalphù hợp cho các ứng dụng tài chính và đó là tiêu chí chính để sử dụng khi quyết định giữa DecimalDouble. Chẳng hạn, Doubleđộ chính xác không đủ cho các ứng dụng khoa học, ví dụ (và Decimalthường không phù hợp với các ứng dụng khoa học vì phạm vi hạn chế của nó).
Đánh dấu Dickinson

2

Sự khác biệt chính giữa mỗi trong số này là độ chính xác.

floatlà một 32-bitsố, doublelà một 64-bitsố và decimallà một 128-bitsố.


0
  • Số thập phân 128 bit (28-29 chữ số có nghĩa) Trong trường hợp ứng dụng tài chính, tốt hơn là sử dụng loại Số thập phân vì nó mang lại cho bạn mức độ chính xác cao và dễ tránh các lỗi làm tròn Sử dụng số thập phân cho toán học không nguyên khi cần độ chính xác (ví dụ: tiền và tiền tệ)

  • Double 64 bit (15-16 chữ số) Loại kép có lẽ là loại dữ liệu được sử dụng phổ biến nhất cho các giá trị thực, ngoại trừ tiền xử lý. Sử dụng gấp đôi cho toán học không nguyên trong đó câu trả lời chính xác nhất là không cần thiết.

  • Float 32 bit (7 chữ số) Nó được sử dụng chủ yếu trong các thư viện đồ họa vì nhu cầu xử lý rất cao, cũng được sử dụng trong các tình huống có thể chịu đựng các lỗi làm tròn.

Decimalschậm hơn nhiều so với a double/float.

DecimalsFloats/Doubleskhông thể được so sánh mà không có diễn viên trong khi FloatsDoublescó thể.

Decimals cũng cho phép các số không mã hóa hoặc dấu.


-1

Để xác định thập phân, nổi và gấp đôi trong .Net (c #)

bạn phải đề cập đến các giá trị như:

Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;

và kiểm tra kết quả.

Và Byte Chiếm bởi mỗi

Float - 4
Double - 8
Decimal - 12
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.