2009-04-29 7 views
228

tôi có thể đặt tên cho ba lợi thế để sử dụng double (hoặc float) thay vì decimal:Khi nào tôi nên sử dụng gấp đôi thay vì số thập phân?

  1. Sử dụng ít bộ nhớ.
  2. Nhanh hơn vì các thao tác toán học dấu phẩy động được hỗ trợ bởi bộ vi xử lý.
  3. Có thể đại diện cho một phạm vi số lớn hơn.

Nhưng những lợi thế này dường như chỉ áp dụng cho các hoạt động tính toán chuyên sâu, chẳng hạn như các hoạt động được tìm thấy trong phần mềm mô hình hóa. Tất nhiên, không nên sử dụng gấp đôi khi cần có độ chính xác, chẳng hạn như tính toán tài chính. Vì vậy, có bất kỳ lý do thực tế nào để chọn double (hoặc float) thay vì decimal trong các ứng dụng "bình thường" không?

Chỉnh sửa để thêm: Cảm ơn tất cả các câu trả lời tuyệt vời, tôi đã học được từ chúng.

Một câu hỏi nữa: Một số người cho rằng đôi khi có thể biểu diễn chính xác hơn số thực. Khi tuyên bố tôi sẽ nghĩ rằng họ thường đại diện chính xác hơn cho họ là tốt. Nhưng nó có phải là một tuyên bố đúng rằng độ chính xác có thể giảm (đôi khi đáng kể) khi các hoạt động điểm trôi nổi được thực hiện?

+0

cũng xem http://stackoverflow.com/questions/2545567/in-net-how-do-i-choose-between-a-decimal-and-a-double –

+3

Điều này được thăng hạng khá thường xuyên và tôi vẫn đang gặp khó khăn với nó. Ví dụ, tôi đang làm việc trên một ứng dụng mà tính toán tài chính vì vậy tôi đang sử dụng thập phân trong suốt. Nhưng các hàm toán học và VisualBasic.Financial sử dụng gấp đôi nên có rất nhiều chuyển đổi mà tôi liên tục đoán lần thứ hai về việc sử dụng số thập phân. –

+0

@JamieIde thật điên rồ các chức năng Tài chính sử dụng gấp đôi, tiền phải luôn ở dạng thập phân. –

Trả lời

273

Tôi nghĩ bạn đã tóm tắt những lợi thế khá tốt. Tuy nhiên bạn đang thiếu một điểm. Loại decimal chỉ chính xác hơn khi đại diện cho số cơ sở 10 (ví dụ: số được sử dụng trong tính toán tiền tệ/tài chính). Nói chung, loại double sẽ cung cấp ít nhất là độ chính xác tuyệt vời (ai đó sửa tôi nếu tôi sai) và tốc độ chắc chắn hơn cho các số thực bất kỳ. Kết luận đơn giản là: khi xem xét việc sử dụng, luôn sử dụng double trừ khi bạn cần độ chính xác base 10 mà cung cấp decimal.

Edit:

Về câu hỏi bổ sung của bạn về việc giảm độ chính xác của số dấu chấm động sau khi hoạt động, đây là một vấn đề hơi tế nhị hơn. Thật vậy, độ chính xác (tôi sử dụng thuật ngữ thay thế cho độ chính xác ở đây) sẽ giảm dần sau mỗi thao tác được thực hiện. Điều này là do hai lý do: a) thực tế là các số nhất định (rõ ràng nhất là số thập phân) không thể được biểu diễn thực sự dưới dạng dấu phẩy động, b) các lỗi làm tròn xảy ra, giống như khi bạn tính toán bằng tay. Nó phụ thuộc rất nhiều vào bối cảnh (bao nhiêu hoạt động bạn đang thực hiện) cho dù các lỗi này là đủ quan trọng để đảm bảo nhiều suy nghĩ tuy nhiên.Trong tất cả các trường hợp, nếu bạn muốn so sánh hai số dấu phẩy mà theo lý thuyết là tương đương (nhưng đã được sử dụng các phép tính khác nhau), bạn cần cho phép một mức độ khoan dung nhất định (có bao nhiêu thay đổi, nhưng thường rất nhỏ) .

Để biết tổng quan chi tiết hơn về các trường hợp cụ thể trong đó các lỗi trong độ chính xác có thể được giới thiệu, hãy xem phần Độ chính xác của Wikipedia article. Cuối cùng, nếu bạn muốn có một cuộc thảo luận nghiêm túc (và toán học) về các số/số hoạt động ở mức máy, hãy thử đọc bài báo được trích dẫn của số What Every Computer Scientist Should Know About Floating-Point Arithmetic.

+1

Bạn có thể cung cấp số examp, e của số cơ sở 10 mà độ chính xác bị mất khi chuyển sang cơ sở 2 không? –

+0

@Mark: 1.000001 là một ví dụ, ít nhất theo Jon Skeet. (Xem câu hỏi 3 của trang này: http://www.yoda.arachsys.com/csharp/teasers-answers.html) – Noldorin

+18

@Mark: ví dụ rất đơn giản: 0,1 là một phân đoạn định kỳ trong cơ sở 2 vì vậy nó không thể được thể hiện chính xác trong một 'double'. Máy tính hiện đại vẫn sẽ in giá trị chính xác nhưng chỉ vì chúng "đoán" ở kết quả - không phải vì nó thực sự được thể hiện chính xác. –

6

Sử dụng đôi hoặc nổi khi bạn không cần độ chính xác, ví dụ: trong trò chơi platformer tôi đã viết, tôi đã sử dụng một phao để lưu trữ tốc độ của trình phát. Rõ ràng là tôi không cần siêu chính xác ở đây bởi vì cuối cùng tôi quay sang một Int để vẽ trên màn hình.

+3

Chính xác là lợi thế duy nhất của số thập phân, điều này là đúng. Bạn không nên hỏi khi nào bạn nên sử dụng các số dấu phẩy động trên số thập phân. Đó sẽ là suy nghĩ đầu tiên của bạn. Câu hỏi sau đó là khi bạn nên sử dụng số thập phân (và câu trả lời là đúng ở đây ... khi độ chính xác quan trọng). –

+2

@Daniel Thẳng, Thật buồn cười, nhưng tôi có ý kiến ​​trái ngược. Tôi nghĩ rằng việc sử dụng một loại ít chính xác hơn vì các đặc tính hiệu suất của nó là một số tiền cho quá trình preoptimization. Bạn có khả năng sẽ phải trả tiền cho việc tiền trước đó nhiều lần trước khi bạn nhận ra lợi ích của nó. –

+3

@Michael Meadows, tôi có thể hiểu được lập luận này. Một cái gì đó cần lưu ý mặc dù là một trong những khiếu nại chính với tối ưu hóa sớm là các lập trình viên không có xu hướng biết những gì sẽ được làm chậm. Tuy nhiên, chúng tôi biết rằng, số thập phân chậm hơn gấp đôi. Tuy nhiên, tôi cho rằng trong hầu hết các trường hợp, cải thiện hiệu suất sẽ không được chú ý đến người dùng. Tất nhiên, trong hầu hết các trường hợp, độ chính xác cũng không cần thiết. Heh. –

50

Bạn có vẻ như đang ở chỗ với lợi ích của việc sử dụng loại dấu phẩy động. Tôi có xu hướng thiết kế cho số thập phân trong mọi trường hợp, và dựa vào một profiler để cho tôi biết nếu hoạt động trên thập phân gây ra tắc nghẽn hoặc chậm lại. Trong những trường hợp đó, tôi sẽ "xuống" để tăng gấp đôi hoặc trôi nổi, nhưng chỉ thực hiện nội bộ và cẩn thận cố gắng quản lý tổn thất chính xác bằng cách giới hạn số chữ số có nghĩa trong hoạt động toán học đang được thực hiện.

Nói chung, nếu giá trị của bạn là tạm thời (không được sử dụng lại), bạn an toàn để sử dụng loại dấu phẩy động. Vấn đề thực sự với các loại dấu phẩy động là ba kịch bản sau đây.

  1. Bạn đang tập hợp các giá trị dấu chấm động (trong trường hợp các hợp chất lỗi chính xác mà)
  2. Bạn xây dựng các giá trị dựa trên giá trị dấu chấm động (ví dụ như trong một thuật toán đệ quy)
  3. Bạn đang làm toán với một số lượng rất lớn các chữ số có nghĩa (ví dụ, 123456789.1 * .000000000000000987654321)

EDIT

Một ccording đến reference documentation on C# decimals:

Các thập phân từ khóa biểu thị một 128-bit kiểu dữ liệu . So với loại dấu phẩy động, loại thập phân có độ chính xác cao hơn và phạm vi nhỏ hơn, điều này làm cho nó phù hợp với các tính toán tài chính và tiền tệ .

Vì vậy, để làm rõ tuyên bố trên của tôi:

tôi có xu hướng để thiết kế cho số thập phân trong tất cả các trường hợp, và dựa vào một hồ sơ để cho tôi biết nếu hoạt động trên thập phân là tắc nghẽn gây ra hoặc chậm -trước.

Tôi chỉ từng làm việc trong các ngành có số thập phân thuận lợi. Nếu bạn đang nghiên cứu về các công cụ đồ họa hoặc phương pháp đồ họa, nó có thể mang lại nhiều lợi ích hơn cho thiết kế cho một loại điểm nổi (float hoặc double).

Decimal là không hoàn toàn chính xác (nó là không thể để đại diện cho chính xác vô hạn cho người không thể thiếu trong một kiểu dữ liệu cơ bản), nhưng nó là xa hơn chính xác hơn gấp đôi:

  • thập phân = 28-29 chữ số có nghĩa
  • đôi = 15-16 chữ số có nghĩa
  • float = 7 chữ số có nghĩa

EDIT 2

Để trả lời nhận xét của Konrad Rudolph, mụC# 1 (ở trên) chắc chắn là chính xác. Sự tổng hợp của sự thiếu chính xác thực sự hợp chất. Xem mã dưới đây để biết một ví dụ:

private const float THREE_FIFTHS = 3f/5f; 
private const int ONE_MILLION = 1000000; 

public static void Main(string[] args) 
{ 
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10")); 
    float asSingle = 0f; 
    double asDouble = 0d; 
    decimal asDecimal = 0M; 

    for (int i = 0; i < ONE_MILLION; i++) 
    { 
     asSingle += THREE_FIFTHS; 
     asDouble += THREE_FIFTHS; 
     asDecimal += (decimal) THREE_FIFTHS; 
    } 
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION); 
    Console.WriteLine("Single: {0}", asSingle.ToString("F10")); 
    Console.WriteLine("Double: {0}", asDouble.ToString("F10")); 
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10")); 
    Console.ReadLine(); 
} 

này kết quả đầu ra như sau:

Three Fifths: 0.6000000000 
Six Hundred Thousand: 600000.0000000000 
Single: 599093.4000000000 
Double: 599999.9999886850 
Decimal: 600000.0000000000 

Như bạn có thể thấy, mặc dù chúng tôi đang bổ sung thêm từ cùng một nguồn liên tục, kết quả của các đôi là ít chính xác (mặc dù có thể sẽ làm tròn chính xác), và phao chính xác hơn rất nhiều, đến mức nó chỉ được giảm xuống còn hai chữ số có nghĩa.

+1

Điểm 1 không đúng. Sai số chính xác/làm tròn chỉ xảy ra khi truyền, chứ không phải trong tính toán. Nó * là * tất nhiên chính xác rằng hầu hết các phép toán không ổn định, do đó nhân lỗi. Nhưng đây là một vấn đề khác và nó áp dụng giống nhau cho tất cả các loại dữ liệu có độ chính xác giới hạn, do đó đặc biệt cho thập phân. –

+1

@Konrad Rudolph, xem ví dụ trong "EDIT 2" làm bằng chứng về điểm tôi đã cố gắng thực hiện trong mụC# 1. Thông thường, vấn đề này không biểu hiện chính nó vì số dư không chính xác tích cực với sự không chính xác tiêu cực, và họ rửa trong tổng hợp, nhưng tổng hợp cùng một số (như tôi đã làm trong ví dụ) làm nổi bật vấn đề. –

+0

Ví dụ tuyệt vời. Chỉ cần hiển thị nó cho các nhà phát triển cơ sở của tôi, những đứa trẻ đã rất ngạc nhiên. – Machado

3

Nếu bạn cần interrop nhị phân với các ngôn ngữ hoặc nền tảng khác, thì bạn có thể cần sử dụng float hoặc double, được chuẩn hóa.

0

Sử dụng các dấu phẩy động nếu bạn đánh giá cao hiệu suất theo độ chính xác.

+6

Số thập phân không chính xác hơn, ngoại trừ trong một số trường hợp giới hạn nhất định đôi khi (không có nghĩa là luôn luôn) quan trọng. –

0

Chọn loại trong chức năng của ứng dụng của bạn. Nếu bạn cần độ chính xác như trong phân tích tài chính, bạn đã trả lời câu hỏi của mình. Nhưng nếu ứng dụng của bạn có thể giải quyết với một ước tính ok của bạn với đôi.

Ứng dụng của bạn có cần tính toán nhanh không hoặc liệu anh ấy có đủ thời gian để cung cấp cho bạn câu trả lời không? Nó thực sự phụ thuộc vào loại ứng dụng.

Đồ họa đói? float hoặc double là đủ. Phân tích dữ liệu tài chính, sao băng nổi bật một loại hành tinh chính xác? Những người cần một chút chính xác :)

+8

Số thập phân cũng là ước tính. Chúng tuân theo các quy ước về số học tài chính, nhưng không có lợi thế trong các tính toán liên quan đến vật lý. –

21

Sử dụng số thập phân cho giá trị cơ bản 10, ví dụ: tính toán tài chính, như những người khác đã gợi ý.

Nhưng gấp đôi thường chính xác hơn cho các giá trị được tính toán tùy ý.

Ví dụ: nếu bạn muốn tính toán trọng số của mỗi dòng trong danh mục, hãy sử dụng gấp đôi vì kết quả sẽ gần như thêm gần 100%.

Trong ví dụ sau, doubleResult là gần gũi hơn với 1 hơn decimalResult:

// Add one third + one third + one third with decimal 
decimal decimalValue = 1M/3M; 
decimal decimalResult = decimalValue + decimalValue + decimalValue; 
// Add one third + one third + one third with double 
double doubleValue = 1D/3D; 
double doubleResult = doubleValue + doubleValue + doubleValue; 

Vì vậy, một lần nữa lấy ví dụ về một danh mục đầu tư:

  • Giá trị thị trường của mỗi dòng trong danh mục đầu tư là một giá trị tiền tệ và có lẽ sẽ được biểu diễn tốt nhất dưới dạng thập phân.

  • Trọng số của mỗi dòng trong danh mục (= Giá trị thị trường/SUM (Giá trị thị trường)) thường được thể hiện tốt hơn gấp đôi.

+1

+1 Ví dụ đơn giản và dễ dàng! –

-1

Thập phân có byte rộng hơn, đôi được hỗ trợ nguyên bản bởi CPU. Thập phân là cơ số-10, do đó, một chuyển đổi thập phân sang hai lần đang diễn ra trong khi một số thập phân được tính toán.

For accounting - decimal 
For finance - double 
For heavy computation - double 

Lưu ý .NET CLR chỉ hỗ trợ Math.Pow (double, double). Thập phân không được hỗ trợ.

.NET Framework 4

[SecuritySafeCritical] 
public static extern double Pow(double x, double y); 
0

Một giá trị tăng gấp đôi sẽ serialize để ký hiệu khoa học theo mặc định nếu ký hiệu đó là ngắn hơn so với màn hình hiển thị chữ số thập phân. (ví dụ :00000003 sẽ là 3e-8) Giá trị thập phân sẽ không bao giờ được sắp xếp theo ký pháp khoa học.Khi serializing cho tiêu thụ bởi một bên ngoài, điều này có thể là một xem xét.

4

Trong một số Kế toán, hãy xem xét khả năng sử dụng các loại tích phân thay vì hoặc kết hợp. Ví dụ, giả sử rằng các quy tắc mà bạn vận hành theo yêu cầu, mỗi kết quả tính toán đều có ít nhất 6 chữ số thập phân và kết quả cuối cùng sẽ được làm tròn thành xu gần nhất.

Tính toán 1/6 của $ 100 sản lượng $ 16.66666666666666 ..., do đó, giá trị được thực hiện trong một trang tính sẽ là $ 16.666667. Cả hai chữ số kép và số thập phân sẽ cho kết quả chính xác đến 6 chữ số thập phân. Tuy nhiên, chúng ta có thể tránh bất kỳ lỗi tích lũy nào bằng cách mang kết quả về phía trước dưới dạng số nguyên 16666667. Mỗi phép tính tiếp theo có thể được thực hiện với cùng độ chính xác và được tiến hành tương tự. Tiếp tục ví dụ, tôi tính thuế bán hàng Texas với số tiền đó (16666667 * .0825 = 1375000). Thêm hai (đó là một bảng tính ngắn) 1666667 + 1375000 = 18041667. Di chuyển dấu thập phân trở lại trong cung cấp cho chúng tôi 18.041667, hoặc $ 18.04.

Mặc dù ví dụ ngắn này không mang lại lỗi tích lũy khi sử dụng gấp đôi hoặc thập phân, nó khá dễ dàng để hiển thị các trường hợp đơn giản là tính toán gấp đôi hoặc thập phân và chuyển tiếp sẽ tích lũy lỗi đáng kể. Nếu các quy tắc bạn hoạt động theo yêu cầu số lượng chữ số thập phân giới hạn, lưu trữ mỗi giá trị dưới dạng số nguyên bằng cách nhân với 10^(số thập phân bắt buộc) và sau đó chia cho 10^(số thập phân bắt buộc) để nhận thực tế giá trị sẽ tránh được bất kỳ lỗi tích lũy nào.

Trong trường hợp các phân số của đồng xu không xảy ra (ví dụ, máy bán hàng tự động), không có lý do gì để sử dụng các loại không tách rời. Đơn giản chỉ cần nghĩ về nó như đếm đồng xu, không phải đô la. Tôi đã thấy mã mà mỗi phép tính chỉ liên quan đến toàn bộ đồng xu, nhưng việc sử dụng gấp đôi dẫn đến lỗi! Integer chỉ toán học loại bỏ vấn đề. Vì vậy, câu trả lời độc đáo của tôi là, khi có thể, bỏ cả hai và hai thập phân.

2

Lưu ý: bài đăng này được dựa trên thông tin về khả năng của loại thập phân từ http://csharpindepth.com/Articles/General/Decimal.aspx và cách giải thích của riêng tôi về ý nghĩa của nó. Tôi sẽ giả sử đôi là chính xác đôi IEEE bình thường.

Lưu ý 2: nhỏ nhất và lớn nhất trong bài đăng này so với độ lớn của số.

Ưu điểm của "thập phân".

  • "thập phân" có thể biểu diễn chính xác các con số có thể được viết dưới dạng (đủ ngắn) các phân số thập phân, không thể kép. Điều này là quan trọng trong sổ cái tài chính và tương tự như thế nào là quan trọng là kết quả chính xác phù hợp với những gì một con người làm các tính toán sẽ cung cấp cho.
  • "thập phân" có độ nghiêng lớn hơn nhiều so với "gấp đôi". Điều đó có nghĩa là đối với các giá trị trong phạm vi chuẩn hóa "thập phân" của nó sẽ có độ chính xác cao hơn nhiều so với gấp đôi.

Nhược điểm của số thập phân

  • Nó sẽ chậm hơn nhiều (Tôi không có tiêu chuẩn nhưng tôi đoán ít nhất một bậc có thể nhiều hơn), số thập phân sẽ không được hưởng lợi từ bất kỳ khả năng tăng tốc phần cứng và số học trên nó sẽ yêu cầu phép nhân/chia tương đối tốn kém bằng 10 (đắt hơn nhiều so với phép nhân và chia cho lũy thừa 2) để khớp với số mũ trước phép cộng/trừ và đưa số mũ trở lại phạm vi sau phép nhân/phép chia.
  • số thập phân sẽ tràn trước số lần tha trước đó. số thập phân chỉ có thể đại diện cho số lên đến & plusmn; 2 -1.Bằng cách so sánh đôi có thể đại diện cho số lên đến gần & plusmn; 2
  • số thập phân sẽ tràn trước đó. Các số nhỏ nhất thể hiện bằng số thập phân là & plusmn; 10 -28. Bằng cách so sánh đôi có thể đại diện cho các giá trị xuống đến 2 -149 (khoảng 10 -45 ) nếu số subnromal được hỗ trợ và 2 -126 (khoảng 10 -38 ) nếu họ không.
  • số thập phân chiếm gấp đôi bộ nhớ gấp đôi.

Ý kiến ​​của tôi là bạn nên sử dụng "thập phân" cho công việc kiếm tiền và các trường hợp khác khi tính toán con người chính xác là quan trọng và bạn nên sử dụng gấp đôi làm lựa chọn mặc định của bạn trong thời gian còn lại.

0

Phụ thuộc vào những gì bạn cần.

Vì float và double là kiểu dữ liệu nhị phân bạn có một số diifculties và errrors trong cách với số lượng đạn, vì vậy ví dụ đôi sẽ tròn ,1-,100000001490116, đôi cũng sẽ tròn 1/3 đến 0,33333334326441. Đơn giản chỉ cần đặt không phải tất cả các số thực có đại diện chính xác trong hai loại

May mắn C# cũng hỗ trợ số thập phân dấu phẩy động, số được biểu diễn qua hệ thập phân số chứ không phải hệ nhị phân. Do đó, dấu phẩy động thập phân số học không mất tính chính xác khi lưu trữ và xử lý số dấu phẩy động. Điều này làm cho nó vô cùng phù hợp với các phép tính trong đó mức độ chính xác cao là cần thiết.