2011-01-05 28 views
5

Tôi gặp vấn đề này trong đầu của mình là lastfew ngày và tôi đang cố gắng để cụm từ câu hỏi của mình. Tuy nhiên, tôi nghĩ rằng tôi đã đóng đinh những gì tôi muốn biết.Lợi ích của việc chấp nhận điểm không chính xác trong C#

Tại sao C# chấp nhận tính không chính xác bằng cách sử dụng các điểm nổi để lưu trữ dữ liệu? Và lợi ích của việc sử dụng nó qua các phương pháp khác là gì?

Ví dụ: Math.Pow(Math.Sqrt(2),2) không chính xác trong C#. Có những ngôn ngữ lập trình có thể tính toán chính xác (ví dụ, Mathematica). Một đối số tôi có thể nghĩ là tính toán chính xác chậm hơn rất nhiều sau đó chỉ cần đối phó với sự thiếu chính xác, nhưng Mathematica & Matlab được sử dụng để tính toán các vấn đề khoa học khổng lồ, vì vậy tôi thấy khó tin rằng những ngôn ngữ đó thực sự đáng kể chậm hơn C#.

Vậy tại sao lại như vậy?

PS: Tôi xin lỗi vì spam bạn với những câu hỏi này, bạn đã có tất cả được thực sự hữu ích

+0

MatLab chạy trong hộp cát Java. Nếu bạn không tin rằng MatLab là chậm hơn, hãy thử tạo một chương trình thời gian thực trong MatLab. Đã có, làm điều đó, không có niềm vui ... :-) –

+0

Được rồi, nhưng Wolfram Mathematica sau đó? Tôi không thể tìm thấy điểm chuẩn trên internet mà nó được so sánh với C# –

+1

[CAS] (http://en.wikipedia.org/wiki/Computer_algebra_system) được tích hợp vào máy tính TI-89 mà thực tế đã cho tôi thông qua các khóa học toán đại học các quần tắt của các chức năng toán học được xây dựng vào các.NET Framework, quá. Thực tế đơn giản là chúng được thiết kế cho các trường hợp sử dụng hoàn toàn khác nhau. –

Trả lời

32

Tại sao C# chấp nhận sự thiếu chính xác bằng cách sử dụng các điểm nổi để lưu trữ dữ liệu?

"C#" không chấp nhận sự cân bằng hiệu suất chính xác; người dùng làm hoặc không chấp nhận điều đó.

C# có ba loại dấu phẩy động - nổi, kép và thập phân - vì ba loại đó đáp ứng phần lớn các nhu cầu của các lập trình viên trong thế giới thực.

float và double là tốt cho các phép tính "khoa học" trong đó câu trả lời đúng với ba hoặc bốn chữ số thập phân luôn đủ gần, vì đó là độ chính xác mà phép đo ban đầu đi kèm. Giả sử bạn chia 10,00 cho 3 và nhận được 3.333333333333. Vì phép đo ban đầu có lẽ chính xác chỉ bằng 0,01, thực tế là kết quả tính toán bị giảm đi ít hơn 0,0000000000004 là không liên quan. Trong tính toán khoa học, bạn không đại diện cho số lượng đã biết chính xác. Việc hiển thị ở vị trí thập phân mười lăm là không liên quan nếu giá trị đo ban đầu chỉ chính xác đến vị trí thập phân thứ hai.

Điều này tất nhiên là không đúng với các tính toán tài chính. Các toán hạng tính toán tài chính thường chính xác đến hai chữ số thập phân và đại diện cho số lượng chính xác. Số thập phân là tốt cho tính toán "tài chính" vì kết quả hoạt động thập phân là chính xác với điều kiện tất cả đầu vào và đầu ra có thể được biểu diễn chính xác dưới dạng số thập phân (và tất cả đều nằm trong phạm vi hợp lý). Số thập phân vẫn có lỗi làm tròn, tất nhiên, nhưng các hoạt động chính xác là những lỗi mà bạn có thể muốn chính xác khi tính toán tài chính.

Và lợi ích của việc sử dụng nó trên các phương pháp khác là gì?

Bạn nên nêu rõ các phương pháp khác mà bạn muốn so sánh. Có rất nhiều kỹ thuật khác nhau để thực hiện các phép tính trên máy tính.

Ví dụ: Math.Pow (Math.Sqrt (2), 2) không chính xác trong C#. Có những ngôn ngữ lập trình có thể tính toán chính xác (ví dụ, Mathematica).

Hãy rõ ràng về điểm này; Mathematica không "tính" gốc 2 chính xác; số này là không hợp lý, vì vậy nó không thể được tính toán chính xác trong bất kỳ lượng lưu trữ hữu hạn nào. Thay vào đó, những gì mathematica làm là nó đại diện cho các con số như là các đối tượng mô tả cách số được tạo ra. Nếu bạn nói "cho tôi căn bậc hai của hai", thì Mathematica về cơ bản phân bổ một đối tượng có nghĩa là "việc áp dụng toán tử căn bậc hai tới số chính xác 2". Nếu bạn sau đó vuông đó, nó có logic mục đích đặc biệt mà nói "nếu bạn vuông cái gì đó là căn bậc hai của cái gì khác, trả lại giá trị ban đầu". Mathematica có các đối tượng đại diện cho các số đặc biệt khác nhau, như pi hoặc e, và một cơ thể lớn của các quy tắc cho cách thao tác khác nhau của những con số kết hợp với nhau.

Về cơ bản, hệ thống là tượng trưng hệ thống; nó thao tác các con số giống như cách mọi người làm khi họ làm toán học bút chì và giấy. Hầu hết các chương trình máy tính thao tác các con số như máy tính: thực hiện phép tính ngay lập tức và làm tròn nó đi. Nếu điều đó không được chấp nhận thì bạn nên dính vào một hệ thống tượng trưng.

Một lập luận tôi có thể nghĩ đến là tính nó chính xác là chậm hơn rất nhiều sau đó chỉ cần đối phó với sự thiếu chính xác, nhưng Mathematica & Matlab được sử dụng để tính toán các vấn đề khoa học khổng lồ, vì vậy tôi thấy khó để tin rằng những ngôn ngữ là thực sự chậm hơn đáng kể so với C#.

Không phải chúng chậm hơn, mặc dù nhân các điểm nổi thực sự cực kỳ nhanh trên phần cứng hiện đại. Đó là công cụ tính toán biểu tượng là vô cùng phức tạp. Nó mã hóa tất cả các quy tắc của toán học cơ bản và có rất nhiều quy tắc đó! C# không có ý định trở thành một công cụ tính toán biểu tượng cấp chuyên nghiệp, nó được dự định là một ngôn ngữ lập trình có mục đích chung.

+2

+1 câu trả lời tuyệt vời –

+1

Rất nhiều máy tính khoa học "lừa gạt" bằng cách giữ thêm vài chữ số đằng sau hậu trường và sử dụng chúng để làm tròn thay vì hiển thị chúng. Hãy xem xét Google, vui vẻ nhận được ['Sqrt (2) ** 2'] (http://www.google.com/search?q=sqrt%282%29%2A%2A2) đúng ... nhưng còn về [ 'sqrt (1.999999999) ** 2'] (http://www.google.com/search?q=sqrt%281.999999999%29%2A%2A2)? – Brian

+2

+1 Tôi không thể cho bạn biết làm thế nào làm mới nó là để xem một lập trình viên thực sự hiểu và đánh giá cao con số đáng kể. Nhưng đây là một câu trả lời hoàn toàn tuyệt vời vì rất nhiều lý do. –

0

C# và hầu hết tất cả các ngôn ngữ khác (ngoại trừ những người cụ thể, như Matlab) cửa hàng số dấu phảy động các trường có kích thước cố định (6 hoặc 8 byte), dẫn đến thiếu chính xác.

+0

Tôi biết điều đó, nhưng tại sao nó lại sử dụng các số dấu phẩy động, nếu có những cách khác. –

+0

@Timo Những cách khác, nếu bạn đang sử dụng các trường có kích thước cố định? Phần lớn máy tính, ngoại trừ máy tính khoa học, không cần độ chính xác vô hạn và có thể chấp nhận một số mức độ vô chính xác. –

+0

Do tốc độ xử lý và hiệu quả lưu trữ. Đó là lý do chính. Hầu hết các chương trình không cần độ chính xác trong 10 biểu tượng sau dấu chấm. –

12

Một từ: hiệu suất. Số học dấu chấm động thường được thực hiện trên phần cứng và có nhiều đơn đặt hàng có cường độ nhanh hơn các phương pháp khác.

Ví dụ của bạn về MATLAB là gì không có thật. MATLAB sử dụng số học dấu chấm động chính xác gấp đôi giống như C#.

+1

+1 Không chỉ hiệu suất, mà thực tế là sự cân bằng hiệu suất giá trị không đáng giá trong 99% các trường hợp. Lần duy nhất bạn cần mức độ chính xác cao mà câu hỏi của bạn giả định là nếu bạn đang thực hiện các phép tính toán hoặc kỹ thuật chuyên ngành. Và đã có phần mềm cho điều đó. –

+0

OK Tôi đã xóa ví dụ MATLAB. Tôi không chắc lắm, nhưng toán học có thể làm đúng không? –

+3

@Timo Có sự khác biệt giữa tính toán số và ký hiệu. Hầu hết các kỹ thuật thực tế và các vấn đề khoa học được phục vụ tốt nhất bằng các thuật toán số và cho chúng số học dấu chấm động là tốt nhất. Điều này chủ yếu là nói lại những gì @Cody Gray đang nói. –

0

Tôi không nghĩ rằng đó là vấn đề về C#. C# là ngôn ngữ mục đích chung và cung cấp cho bạn các kiểu dữ liệu cơ bản để chơi cùng. Nếu bạn không hài lòng với họ, bạn luôn tự do để tạo của riêng bạn.

Hơn nữa, C# không phải là người chấp nhận không chính xác. Lập trình viên. Đối với tập hợp lớn các vấn đề không chính xác là chấp nhận được. Float không nên được sử dụng khi kết quả chính xác được mong đợi nhưng đây là quyết định cho lập trình viên không dành cho nhà thiết kế ngôn ngữ.

0

Một lý do là số và định dạng số rõ ràng và phổ quát. Có, có lỗi làm tròn, nhưng chúng là hằng số và có thể dự đoán được. Cố gắng thiết lập một định dạng chung cho bất kỳ vấn đề thuật toán nào là không nhỏ.

2

Đối với hầu hết các sự cố lập trình, sự thiếu chính xác không phải là vấn đề và float (hoặc double) loại dữ liệu đủ tốt. Nhiều năm trước, không có những thứ như "giá trị điểm trôi nổi" và phần mềm phải lưu trữ các giá trị như hai số nguyên. Và hiệu suất một vấn đề (không đề cập đến lỗi lập trình - và kịch bản wtf - từ các hàm tính toán dấu phẩy động tùy chỉnh). Do đó, một quy ước được thiết kế và ngay sau khi các máy tính được trang bị FPU s.

Bây giờ, khi nào sử dụng FPU để tính toán hoặc sử dụng các chương trình/librairies toán học khác (như Mathematica) tùy thuộc vào vấn đề. Ví dụ, việc tính toán các đỉnh trong môi trường 3d thích hiệu suất chính xác hơn. Nhưng phần mềm kế toán thì khác. Trong khía cạnh đó, cả hai vấn đề khác nhau; một phần mềm kế toán sẽ không cần phải tính số phức tạp hàng triệu lần mỗi giây :) (chỉnh sửa: hoặc nếu có, một số phần cứng rất đắt tiền có lẽ cũng sẽ là một phần của phương trình!)

Nếu bạn biết bạn sẽ làm Math.pow (Math.sqrt (2), 2) thì bạn nên suy nghĩ lại cách bạn lưu trữ cả hai giá trị (như tính toán lại chúng mỗi lần). Đây không phải là vấn đề với ngôn ngữ lập trình, mà là vấn đề khái niệm hơn.

3

Tại sao C# chấp nhận tính không chính xác bằng cách sử dụng các điểm nổi để lưu trữ dữ liệu?

Bằng cách này, hỗ trợ dấu chấm động có thể lập bản đồ để cách phần cứng hỗ trợ điểm nổi, đó là - đó là nhiều hay ít là cách duy nhất lợi dụng nổi điểm hoạt động trong phần cứng, mà là nhiều nhanh hơn một giải pháp phần mềm. Hạn chế là phần cứng đại diện cho các điểm nổi với một số hữu hạn các bit, dẫn đến không chính xác (lưu ý rằng sự thiếu chính xác cũng được xác định).

Các cách khác để biểu thị các giá trị dấu phẩy động cần một giải pháp phần mềm, nó chậm hơn đáng kể và cần nhiều không gian hơn. "Bất cứ ai" có thể thực hiện điều đó với những gì có sẵn trong C#, bao gồm hỗ trợ dấu chấm động gốc cho phần cứng có sẵn sẽ khá khó cho "bất kỳ ai" nếu điều này chưa được hỗ trợ trong ngôn ngữ/CLR.

0

Có một chút của một lời giải thích here cho Mathematica

Phiên bản ngắn gọn là cho ngày thường xuyên cho đến ngày toán dấu chấm động, phần cứng có thể làm điều đó một cách nhanh chóng với một khoản tiền gọi của sự thiếu chính xác. Vì vậy, nếu tính toán của bạn không dựa vào chính xác hơn, thì hãy thực hiện nó một cách nhanh chóng.

Nếu bạn cần độ chính xác, thì người lập trình phải viết thuật toán theo mức độ chính xác cần thiết. Mà sẽ chậm hơn.

Các vấn đề liên quan