Sự khác nhau giữa là gì decimal
, float
và double
trong NET?
Khi nào thì ai đó sẽ sử dụng một trong những thứ này?
Sự khác nhau giữa là gì decimal
, float
và double
trong NET?
Khi nào thì ai đó sẽ sử dụng một trong những thứ này?
Câu trả lời:
float
và double
là cá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ị.
decimal
là 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 decimal
vẫ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
/ double
phù 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.
float
/ double
thườ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ũ
float
là một từ khóa bí danh C # và không phải là một loại .Net. đó là System.Single
.. single
và double
là các loại điểm nhị phân nổi.
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
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ụ, float
sẽ conf conf 0.1
và 0.1 + 1e-8
, trong khi decimal
sẽ confatter 0.1
và 0.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ụ: float
có 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 .
0.1
là khô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.10000001
là bởi vì con người thích cơ sở 10. Và thậm chí với một float
giá trị, nếu bạn khởi tạo hai giá trị theo 0.1
cù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.1
có 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.0
hoặc. Không phải là hoàn toàn chính xác.
double a = 0.1; double b = 0.1;
thì a == b
sẽ đúng . Chỉ có vậy a
và cả 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.1
decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m;
a == b
a
b
1/3
0.3333...
decimal
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:
+---------+----------------+---------+----------+---------------------------------------------+
| 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 |
+---------+----------------+---------+----------+---------------------------------------------+
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).
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
double
thí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!).
Real
IIRC 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 ...
double
loạ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 double
có 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. ..
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;
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*2
nào?
System.Decimal
né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.
decimal
bằ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.
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 double
hoặc float
. Như thế này:
float myFloat;
double myDouble;
( float
viế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 double
s, 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
float
là số 32 bit và double
là 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!
decimal
thự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, decimal
không có khái niệm về các giá trị đặc biệt như NaN, -0, hoặc -∞.
Đâ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 decimal
việ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 decimal
lạ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ù double
có độ 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.TryParse
thự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.
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?
Đố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!
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
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)
Nói một cách đơn giản:
/==========================================================================================
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 , Double và Decimal .
Decimal
phù 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 Decimal
và Double
. Chẳng hạn, Double
độ chính xác không đủ cho các ứng dụng khoa học, ví dụ (và Decimal
thườ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ó).
Sự khác biệt chính giữa mỗi trong số này là độ chính xác.
float
là một 32-bit
số, double
là một 64-bit
số và decimal
là một 128-bit
số.
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.
Decimals
chậm hơn nhiều so với a double/float
.
Decimals
và Floats/Doubles
không thể được so sánh mà không có diễn viên trong khi Floats
và Doubles
có thể.
Decimals
cũng cho phép các số không mã hóa hoặc dấu.
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ả.
Float - 4
Double - 8
Decimal - 12