2010-01-27 17 views
10

Tôi muốn biết liệu tôi có thể giả định rằng các hoạt động tương tự trên cùng số điểm nổi 64 bit cho kết quả giống nhau trên bất kỳ PC hiện đại nào và bằng các ngôn ngữ lập trình phổ biến nhất không? (C++, Java, C#, v.v.). Chúng ta có thể giả định rằng chúng ta đang hoạt động trên các con số và kết quả cũng là một số (không có NaN, INF và vv).Số lượng dấu phẩy động 64 bit có hoạt động giống nhau trên tất cả các máy tính hiện đại không?

Tôi biết có hai tiêu chuẩn tính toán rất giống với số điểm nổi (IEEE 854-1987 và IEEE 754-2008). Tuy nhiên tôi không biết nó được thực hành như thế nào.

Trả lời

8

hiện đại xử lý mà thực hiện 64-bit floating-point thường thực hiện một cái gì đó gần với tiêu chuẩn IEEE 754-1985, thời gian gần đây thay thế bởi các tiêu chuẩn 754-2008.

Chuẩn 754 chỉ định kết quả bạn sẽ nhận được từ các hoạt động cơ bản nhất định, đáng chú ý là cộng, trừ, nhân, chia, căn bậc hai và phủ định. Trong hầu hết các trường hợp, kết quả số được chỉ định chính xác: Kết quả phải là số có thể biểu diễn gần nhất với kết quả toán học chính xác theo hướng được chỉ định bởi chế độ làm tròn (gần nhất, về hướng vô cực, về 0 hoặc hướng tới cực âm). Trong chế độ "gần nhất", tiêu chuẩn cũng chỉ định cách các mối quan hệ bị hỏng.

Do đó, các thao tác không liên quan đến các điều kiện ngoại lệ như tràn sẽ nhận được kết quả tương tự trên các bộ xử lý khác nhau phù hợp với tiêu chuẩn.

Tuy nhiên, có một số vấn đề cản trở việc nhận kết quả giống nhau trên các bộ vi xử lý khác nhau. Một trong số đó là trình biên dịch thường miễn phí để thực hiện chuỗi các thao tác dấu phẩy động theo nhiều cách khác nhau. Ví dụ: nếu bạn viết "a = b c + d" trong C, trong đó tất cả các biến được khai báo kép, trình biên dịch sẽ tự do tính "b c" trong số học chính xác kép hoặc thứ gì đó có nhiều độ chính xác hơn. Ví dụ, nếu bộ xử lý có các thanh ghi có khả năng giữ các số dấu phẩy động chính xác mở rộng và làm số học với độ chính xác mở rộng không mất nhiều thời gian CPU hơn làm phép tính số học với độ chính xác gấp đôi, trình biên dịch có khả năng tạo mã bằng cách sử dụng mở rộng -độ chính xác. Trên một bộ xử lý như vậy, bạn có thể không nhận được kết quả tương tự như bạn làm trên một bộ xử lý khác. Ngay cả khi trình biên dịch thực hiện điều này thường xuyên, nó có thể không trong một số trường hợp vì thanh ghi đầy trong một chuỗi phức tạp, vì vậy nó lưu trữ các kết quả trung gian trong bộ nhớ tạm thời. Khi thực hiện điều đó, nó có thể ghi chỉ số 64 bit đôi chứ không phải là số chính xác mở rộng. Vì vậy, một thói quen chứa số học dấu phẩy động có thể cho kết quả khác nhau chỉ vì nó được biên dịch với mã khác nhau, có lẽ được đặt ở một nơi, và trình biên dịch cần đăng ký cho cái gì khác.

Một số bộ xử lý có hướng dẫn tính toán số nhân và thêm một chỉ lệnh, vì vậy "b c + d" có thể được tính không làm tròn trung gian và nhận kết quả chính xác hơn so với bộ xử lý đầu tiên tính b c và sau đó thêm d.

Trình biên dịch của bạn có thể có các nút chuyển để kiểm soát hành vi như thế này.

Có một số nơi mà tiêu chuẩn 754-1985 không yêu cầu kết quả duy nhất. Ví dụ, khi xác định liệu dòng chảy đã xảy ra (kết quả là quá nhỏ để được biểu diễn chính xác), tiêu chuẩn cho phép thực hiện để xác định trước hoặc sau khi nó làm tròn (và các bit phân số) đến độ chính xác đích. Vì vậy, một số triển khai sẽ cho bạn biết lưu lượng đã xảy ra khi các triển khai khác sẽ không xảy ra.

Một tính năng phổ biến trong bộ vi xử lý là có chế độ "gần như IEEE 754" giúp loại bỏ khó khăn trong việc xử lý dòng chảy bằng cách thay thế bằng không thay vì trả lại số rất nhỏ mà tiêu chuẩn yêu cầu. Đương nhiên, bạn sẽ nhận được các con số khác nhau khi thực hiện ở chế độ như vậy hơn khi thực hiện ở chế độ tương thích hơn. Chế độ không tuân thủ có thể được thiết lập mặc định bởi trình biên dịch và/hoặc hệ điều hành của bạn, vì lý do hiệu suất.

Lưu ý rằng việc triển khai IEEE 754 thường không được cung cấp chỉ bằng phần cứng mà bởi sự kết hợp giữa phần cứng và phần mềm. Bộ vi xử lý có thể thực hiện phần lớn công việc nhưng dựa vào phần mềm để xử lý các ngoại lệ nhất định, đặt các chế độ nhất định, v.v.

Khi bạn di chuyển ra ngoài các phép tính số học cơ bản cho những thứ như sin và cosin, bạn phụ thuộc rất nhiều vào thư viện bạn sử dụng. Chức năng siêu việt thường được tính toán với các xấp xỉ được thiết kế cẩn thận. Việc triển khai được phát triển độc lập bởi các kỹ sư khác nhau và có được kết quả khác nhau. Trên một hệ thống, hàm sin có thể cho kết quả chính xác trong một ULP (đơn vị ít chính xác nhất) cho các đối số nhỏ (nhỏ hơn pi hoặc hơn) nhưng các lỗi lớn hơn cho các đối số lớn. Trên một hệ thống khác, hàm sin có thể cho kết quả chính xác trong một vài ULP cho tất cả các đối số. Không có thư viện toán học hiện tại nào được biết là tạo ra các kết quả được làm tròn chính xác cho tất cả các đầu vào. Có một dự án, crlibm (Libect Rounded Libm), đã thực hiện một số công việc tốt hướng tới mục tiêu này, và họ đã phát triển các phần triển khai cho các phần quan trọng của thư viện toán được làm tròn chính xác và có hiệu năng tốt, nhưng không phải tất cả thư viện toán chưa.

Tóm lại, nếu bạn có một bộ tính toán có thể quản lý, hãy hiểu việc triển khai trình biên dịch của bạn và rất cẩn thận, bạn có thể dựa vào kết quả giống nhau trên các bộ xử lý khác nhau. Nếu không, nhận được kết quả hoàn toàn giống hệt nhau không phải là thứ bạn có thể dựa vào.

+0

Tất cả các điểm tốt. Ví dụ về phần cứng cung cấp kết quả khác nhau, x86_64 (tức là tất cả các bộ vi xử lý Intel Pentium) cho kết quả khác với k1om (tức là Intel Phi aka Intel MIC). Các thanh ghi bên trong có kích thước khác nhau, mặc dù biểu diễn bộ nhớ 64 bit bên ngoài (IEEE 754) là giống nhau. –

2

FPU hiện đại tất cả triển khai thực hiện IEEE754 nổi ở định dạng đơn và kép và một số ở định dạng mở rộng. Một số hoạt động nhất định được hỗ trợ (khá nhiều thứ trong math.h), với một số hướng dẫn đặc biệt nổi xung quanh đó.

+0

Đúng, nhưng IEEE đảm bảo cho bạn khả năng tái sản xuất là gì? – ergosys

+0

Không, như lỗi Intel FDIV cho thấy. –

1

giả sử bạn đang nói về việc áp dụng nhiều thao tác, tôi không nghĩ bạn sẽ nhận được số chính xác. Kiến trúc CPU, sử dụng trình biên dịch, cài đặt tối ưu hóa sẽ thay đổi kết quả tính toán của bạn.

nếu bạn có nghĩa là thứ tự hoạt động chính xác (ở cấp độ lắp ráp), tôi nghĩ bạn vẫn sẽ nhận được các biến thể. Ví dụ: chip Intel sử dụng độ chính xác mở rộng (80 bit) trong nội bộ, có thể không phải là trường hợp cho các CPU khác. (Tôi không nghĩ rằng độ chính xác mở rộng là bắt buộc)

0

Đối với loại dữ liệu 64 bit, tôi chỉ biết "double precision"/"binary64" từ IEEE 754 (1985 và 2008 không khác biệt nhiều ở đây).

Lưu ý: Các loại cơ số được xác định trong IEEE 854-1987 được thay thế bởi IEEE 754-2008 anyways.

1

Chương trình C# giống nhau có thể đưa ra các kết quả bằng số khác nhau trên cùng một PC, sau khi được biên dịch ở chế độ gỡ lỗi mà không tối ưu hóa, lần thứ hai được biên dịch ở chế độ phát hành có bật tối ưu hóa. Đó là kinh nghiệm cá nhân của tôi. Chúng tôi không quan tâm đến điều này khi chúng tôi thiết lập một bộ kiểm thử hồi quy tự động cho một trong các chương trình của chúng tôi lần đầu tiên và hoàn toàn ngạc nhiên rằng nhiều thử nghiệm của chúng tôi không thành công mà không có lý do rõ ràng nào.

7

Nếu bạn muốn nhận được kết quả tương tự, thì câu trả lời là không.

Bạn thậm chí có thể nhận được kết quả khác nhau để xây dựng gỡ lỗi (không được tối ưu hóa) so với bản phát hành (tối ưu hóa) trên cùng một máy trong một số trường hợp, vì vậy thậm chí không giả định rằng kết quả có thể luôn giống nhau trên các máy khác nhau.

(Điều này có thể xảy ra, ví dụ: trên máy tính có bộ xử lý Intel, nếu trình tối ưu hóa giữ một biến cho kết quả trung gian trong sổ đăng ký, được lưu trữ trong bộ nhớ trong bản dựng chưa được tối ưu hóa. các biến kép là 64 bit, kết quả trung gian sẽ được lưu trữ với độ chính xác cao hơn trong bản dựng được tối ưu hóa, gây ra các giá trị khác nhau trong các kết quả sau này).

Trong thực tế, tuy nhiên, bạn thường có thể nhận được kết quả tương tự, nhưng bạn không nên dựa vào nó.

1

Đối với C# trên x86, thanh ghi FP 80 bit được sử dụng.

Chuẩn C# cho biết bộ vi xử lý phải hoạt động ở cùng độ chính xác hoặc lớn hơn loại chính nó (tức là 64 bit trong trường hợp 'đôi'). Quảng cáo được phép, ngoại trừ lưu trữ. Điều đó có nghĩa là người dân địa phương và các tham số có thể có độ chính xác lớn hơn 64 bit.

Nói cách khác, gán biến thành viên cho biến cục bộ có thể (và thực tế trong một số trường hợp nhất định) là đủ để tạo ra sự bất bình đẳng.

Xem thêm: Float/double precision in debug/release modes