Nhân mảng javascript
Số học dấu phẩy động được coi là một chủ đề bí truyền của nhiều người. Điều này khá ngạc nhiên vì dấu chấm động phổ biến trong các hệ thống máy tính. Hầu hết mọi ngôn ngữ đều có kiểu dữ liệu dấu phẩy động; . Bài báo này trình bày một hướng dẫn về các khía cạnh của dấu phẩy động có tác động trực tiếp đến các nhà thiết kế hệ thống máy tính. Nó bắt đầu với thông tin cơ bản về biểu diễn dấu phẩy động và lỗi làm tròn, tiếp tục với phần thảo luận về tiêu chuẩn dấu phẩy động IEEE và kết thúc bằng nhiều ví dụ về cách các nhà chế tạo máy tính có thể hỗ trợ dấu phẩy động tốt hơn. Show
Danh mục và mô tả chủ đề. (Chính) C. 0 [Tổ chức hệ thống máy tính]. Chung -- thiết kế tập lệnh; . 3. 4 [Ngôn ngữ lập trình]. Bộ xử lý -- trình biên dịch, tối ưu hóa; . 1. 0 [Phân tích số]. Chung -- số học máy tính, phân tích lỗi, thuật toán số (Trung học) D. 2. 1 [Kỹ thuật phần mềm]. Yêu cầu/Thông số kỹ thuật -- ngôn ngữ; . 3. 4 Ngôn ngữ lập trình]. Định nghĩa và lý thuyết chính thức -- ngữ nghĩa; . 4. 1 Hệ điều hành]. Quản lý quy trình -- đồng bộ hóa Điều khoản chung. Thuật toán, Thiết kế, Ngôn ngữ Các từ và cụm từ chính bổ sung. Số không chuẩn hóa, ngoại lệ, dấu phẩy động, tiêu chuẩn dấu phẩy động, tràn dần, số bảo vệ, NaN, tràn, lỗi tương đối, lỗi làm tròn, chế độ làm tròn, ulp, tràn Giới thiệuCác nhà xây dựng hệ thống máy tính thường cần thông tin về số học dấu phẩy động. Tuy nhiên, có rất ít nguồn thông tin chi tiết về nó. Một trong số ít cuốn sách về chủ đề này, Tính toán dấu phẩy động của Pat Sterbenz, đã hết bản in từ lâu. Bài viết này là một hướng dẫn về các khía cạnh của số học dấu phẩy động (dấu phẩy động sau đây) có kết nối trực tiếp với việc xây dựng hệ thống. Nó bao gồm ba phần kết nối lỏng lẻo. Phần đầu tiên, , thảo luận về ý nghĩa của việc sử dụng các chiến lược làm tròn khác nhau cho các phép toán cơ bản cộng, trừ, nhân và chia. Nó cũng chứa thông tin cơ bản về hai phương pháp đo lỗi làm tròn, ulps và n = n/22 n = n/23. Phần thứ hai thảo luận về tiêu chuẩn dấu phẩy động IEEE, đang được các nhà sản xuất phần cứng thương mại chấp nhận nhanh chóng. Bao gồm trong tiêu chuẩn IEEE là phương pháp làm tròn cho các hoạt động cơ bản. Thảo luận về tiêu chuẩn dựa trên tài liệu trong phần. Phần thứ ba thảo luận về các kết nối giữa dấu phẩy động và thiết kế các khía cạnh khác nhau của hệ thống máy tính. Các chủ đề bao gồm thiết kế tập lệnh, tối ưu hóa trình biên dịch và xử lý ngoại lệ Tôi đã cố gắng tránh đưa ra các phát biểu về dấu phẩy động mà không đưa ra lý do tại sao các phát biểu đó là đúng, đặc biệt là khi các biện minh không liên quan gì phức tạp hơn phép tính cơ bản. Những giải thích không phải là trọng tâm của lập luận chính đã được nhóm lại thành một phần gọi là "Chi tiết" để chúng có thể được bỏ qua nếu muốn. Đặc biệt, phần chứng minh của nhiều định lý xuất hiện trong phần này. Kết thúc mỗi bằng chứng được đánh dấu bằng ký hiệu z. Khi không có bằng chứng, z xuất hiện ngay sau phát biểu của định lý Lỗi làm trònÉp vô số số thực vào một số bit hữu hạn yêu cầu biểu diễn gần đúng. Mặc dù có vô số số nguyên, nhưng trong hầu hết các chương trình, kết quả tính toán số nguyên có thể được lưu trữ trong 32 bit. Ngược lại, với bất kỳ số lượng bit cố định nào, hầu hết các phép tính với số thực sẽ tạo ra các đại lượng không thể được biểu diễn chính xác bằng cách sử dụng nhiều bit đó. Do đó, kết quả của một phép tính dấu phẩy động thường phải được làm tròn để phù hợp trở lại với biểu diễn hữu hạn của nó. Lỗi làm tròn này là tính năng đặc trưng của tính toán dấu phẩy động. Phần này mô tả cách nó được đo lường Vì hầu hết các phép tính dấu phẩy động đều có lỗi làm tròn, nên có vấn đề gì nếu các phép toán số học cơ bản gây ra lỗi làm tròn nhiều hơn một chút so với mức cần thiết? . Phần thảo luận về các số bảo vệ, một phương tiện để giảm lỗi khi trừ hai số gần nhau. Các chữ số bảo vệ được IBM coi là đủ quan trọng nên vào năm 1968, hãng đã thêm một chữ số bảo vệ vào định dạng độ chính xác kép trong kiến trúc Hệ thống/360 (độ chính xác đơn đã có một chữ số bảo vệ) và trang bị thêm cho tất cả các máy hiện có trong lĩnh vực này. Hai ví dụ được đưa ra để minh họa tiện ích của các chữ số bảo vệ Tiêu chuẩn IEEE đi xa hơn là chỉ yêu cầu sử dụng chữ số bảo vệ. Nó cung cấp một thuật toán để cộng, trừ, nhân, chia và căn bậc hai, đồng thời yêu cầu việc triển khai tạo ra kết quả giống như thuật toán đó. Như vậy, khi một chương trình được chuyển từ máy này sang máy khác, kết quả của các thao tác cơ bản sẽ giống nhau đến từng bit nếu cả hai máy đều hỗ trợ chuẩn IEEE. Điều này đơn giản hóa rất nhiều việc chuyển các chương trình. Các cách sử dụng khác của thông số kỹ thuật chính xác này được đưa ra trong Định dạng dấu phẩy độngMột số cách biểu diễn khác nhau của số thực đã được đề xuất, nhưng cho đến nay cách biểu diễn được sử dụng rộng rãi nhất là biểu diễn dấu phẩy động. Biểu diễn dấu phẩy động có cơ sở Nói chung, số dấu phẩy động sẽ được biểu diễn dưới dạng ± d. đ. d × Thuật ngữ số dấu phẩy động sẽ được sử dụng để chỉ một số thực có thể được biểu diễn chính xác ở định dạng đang được thảo luận. Hai tham số khác liên quan đến biểu diễn dấu phẩy động là số mũ lớn nhất và nhỏ nhất được phép, emax và emin. Vì có bit, trong đó +1 cuối cùng dành cho bit dấu. Mã hóa chính xác không quan trọng bây giờ Có hai lý do tại sao một số thực có thể không được biểu diễn chính xác dưới dạng số dấu phẩy động. Tình huống phổ biến nhất được minh họa bằng số thập phân 0. 1. Mặc dù nó có dạng biểu diễn thập phân hữu hạn, nhưng ở dạng nhị phân, nó có dạng biểu diễn lặp lại vô hạn. Như vậy khi Các biểu diễn dấu phẩy động không nhất thiết phải là duy nhất. Ví dụ, cả 0. 01 × 101 và 1. 00 × 10-1 đại diện cho 0. 1. Nếu chữ số đầu khác không (d0 Lưu ý rằng × trong số dấu phẩy động là một phần của ký hiệu và khác với thao tác nhân dấu phẩy động. Ý nghĩa của biểu tượng × phải rõ ràng trong ngữ cảnh. Chẳng hạn, biểu thức (2. 5 × 10-3) × (4. 0 × 102) chỉ liên quan đến một phép nhân dấu phẩy động duy nhất HÌNH D-1 Số chuẩn hóa khi Lỗi tương đối và UlpsVì lỗi làm tròn vốn có trong tính toán dấu phẩy động nên điều quan trọng là phải có cách đo lỗi này. Xem xét định dạng dấu phẩy động với Để tính toán lỗi tương đối tương ứng với. 5 ulp, hãy quan sát rằng khi một số thực được xấp xỉ bằng số dấu phẩy động gần nhất có thể d. đ. dd × Đặc biệt, lỗi tương đối tương ứng với. 5 ulp có thể thay đổi theo hệ số Trong ví dụ trên, lỗi tương đối là. 00159/3. 14159 Để minh họa sự khác biệt giữa ulps và lỗi tương đối, hãy xem xét số thực x = 12. 35. Nó được xấp xỉ bởi = 1. 24 × 101. lỗi là 0. 5 ulps, lỗi tương đối là 0. 8 Cách tự nhiên nhất để đo lỗi làm tròn là trong ulps. Ví dụ: làm tròn đến số dấu phẩy động gần nhất tương ứng với lỗi nhỏ hơn hoặc bằng. 5 lần. Tuy nhiên, khi phân tích lỗi làm tròn do các công thức khác nhau gây ra, lỗi tương đối là biện pháp tốt hơn. Một minh họa tốt cho điều này là phân tích trong phần. Vì Khi chỉ quan tâm đến thứ tự độ lớn của lỗi làm tròn, ulps và Số bảo vệMột phương pháp tính toán sự khác biệt giữa hai số dấu phẩy động là tính toán sự khác biệt một cách chính xác và sau đó làm tròn nó thành số dấu phẩy động gần nhất. Điều này rất tốn kém nếu các toán hạng khác nhau rất nhiều về kích thước. Giả sử p = 3, 2. 15×1012 - 1. 25 × 10-5 sẽ được tính là x = 2. 15 × 1012y =. 0000000000000000125 × 1012 x - y = 2. 1499999999999999875 × 1012 làm tròn thành 2. 15×1012. Thay vì sử dụng tất cả các chữ số này, phần cứng dấu phẩy động thường hoạt động trên một số chữ số cố định. Giả sử rằng số chữ số được giữ lại là p và khi toán hạng nhỏ hơn được dịch sang phải, các chữ số sẽ bị loại bỏ (trái ngược với làm tròn). Sau đó 2. 15 × 1012 - 1. 25 × 10-5 trở thành x = 2. 15 × 1012y = 0. 00 × 1012 x - y = 2. 15 × 1012 Câu trả lời giống hệt như thể sự khác biệt đã được tính toán chính xác và sau đó làm tròn. Lấy một ví dụ khác. 10. 1 - 9. 93. Điều này trở thành x = 1. 01 × 101y = 0. 99 × 101 x - y =. 02 × 101 Đáp án đúng là. 17, do đó, sự khác biệt được tính toán là 30 ulps và sai ở mỗi chữ số. Lỗi có thể tệ đến mức nào? Định lý 1Sử dụng định dạng dấu phẩy động có tham sốBằng chứngMột lỗi tương đối củaKhi y = 0. 993 × 101 x - y =. 017 × 101 và câu trả lời là chính xác. Với một chữ số bảo vệ, sai số tương đối của kết quả có thể lớn hơn y =. 085 × 102 x - y = 1. 015 × 102 Điều này làm tròn thành 102, so với câu trả lời đúng là 101. 41, cho một lỗi tương đối của. 006, lớn hơn Định lý 2Nếu x và y là các số dấu phẩy động ở định dạng có tham sốĐịnh lý này sẽ được chứng minh trong. Phép cộng được bao gồm trong định lý trên vì x và y có thể dương hoặc âm hủy bỏPhần cuối cùng có thể được tóm tắt bằng cách nói rằng nếu không có số bảo vệ, sai số tương đối mắc phải khi trừ hai đại lượng gần nhau có thể rất lớn. Nói cách khác, việc đánh giá bất kỳ biểu thức nào chứa phép trừ (hoặc phép cộng các đại lượng trái dấu) có thể dẫn đến sai số tương đối lớn đến mức tất cả các chữ số đều vô nghĩa (Định lý 1). Khi trừ các đại lượng lân cận, các chữ số có nghĩa nhất trong toán hạng khớp và triệt tiêu lẫn nhau. Có hai loại hủy bỏ. thảm họa và lành tính Hủy thảm khốc xảy ra khi các toán hạng có lỗi làm tròn. Ví dụ, trong công thức bậc hai, biểu thức b2 - 4ac xảy ra. Các đại lượng b2 và 4ac có thể bị lỗi làm tròn vì chúng là kết quả của phép nhân dấu phẩy động. Giả sử rằng chúng được làm tròn đến số dấu phẩy động gần nhất và do đó chính xác trong phạm vi. 5 lần. Khi chúng bị trừ, việc hủy bỏ có thể khiến nhiều chữ số chính xác biến mất, để lại các chữ số chủ yếu bị ô nhiễm do lỗi làm tròn. Do đó sự khác biệt có thể có lỗi của nhiều ulps. Ví dụ: xét b = 3. 34, a = 1. 22 và c = 2. 28. Giá trị chính xác của b2 - 4ac là. 0292. Nhưng b2 làm tròn thành 11. 2 và 4ac làm tròn thành 11. 1, do đó câu trả lời cuối cùng là. 1 là lỗi của 70 ulps, mặc dù 11. 2 - 11. 1 chính xác bằng. 1. Phép trừ không đưa ra bất kỳ lỗi nào, mà chỉ để lộ ra lỗi được đưa ra trong các phép nhân trước đó. Xuất trừ lành tính xảy ra khi trừ chính xác các đại lượng đã biết. Nếu x và y không có sai số làm tròn thì theo Định lý 2 nếu phép trừ được thực hiện với một chữ số bảo vệ thì hiệu x-y có sai số tương đối rất nhỏ (nhỏ hơn 2 Một công thức thể hiện sự hủy bỏ nghiêm trọng đôi khi có thể được sắp xếp lại để loại bỏ vấn đề. Lại xét công thức bậc hai (4)Khi nào, sau đó không liên quan đến việc hủy bỏ và .Nhưng phép cộng (trừ) khác trong một trong các công thức sẽ bị hủy bỏ thảm khốc. Để tránh điều này, hãy nhân tử số và mẫu số của r1 với (và tương tự cho r2) để có được (5)Nếu và, thì tính toán r1 bằng công thức sẽ liên quan đến việc hủy bỏ. Do đó, hãy sử dụng công thức để tính r1 và cho r2. Mặt khác, nếu b < 0, sử dụng để tính r1 và cho r2. Biểu thức x2 - y2 là một công thức khác thể hiện sự hủy bỏ thảm khốc. Sẽ chính xác hơn nếu đánh giá nó là (x - y)(x + y). Khác với căn thức bậc hai, dạng cải tiến này vẫn có phép trừ, nhưng là phép trừ đại lượng lành tính, không làm tròn sai, không thảm hại. Theo Định lý 2, sai số tương đối trong x - y tối đa là 2 Để tránh nhầm lẫn giữa giá trị chính xác và giá trị được tính toán, ký hiệu sau được sử dụng. Trong khi x - y biểu thị sự khác biệt chính xác của x và y, xy biểu thị sự khác biệt được tính toán (i. e. , với lỗi làm tròn). Tương tự như vậy n = n/24 hoặc n = n/25. Các hàm chữ thường và ký hiệu toán học truyền thống biểu thị các giá trị chính xác của chúng như trong ln(x) và. Mặc dù (xy) Biểu thức x2 - y2 chính xác hơn khi được viết lại thành (x - y)(x + y) vì một phép hủy thảm khốc được thay thế bằng một phép hủy lành tính. Tiếp theo, chúng tôi trình bày các ví dụ thú vị hơn về các công thức thể hiện sự hủy bỏ nghiêm trọng có thể được viết lại để chỉ biểu hiện sự hủy bỏ lành tính Diện tích của một tam giác có thể được biểu thị trực tiếp theo độ dài của các cạnh a, b và c của nó như (6)(Giả sử tam giác rất phẳng; nghĩa là a Có một cách để viết lại công thức sao cho nó sẽ trả về kết quả chính xác ngay cả đối với tam giác phẳng [Kahan 1986]. Nó là (7)Nếu a, b và c không thỏa mãn a Mặc dù công thức chính xác hơn nhiều so với ví dụ này, nhưng thật tuyệt khi biết hiệu suất nói chung tốt như thế nào Định lý 3Sai số làm tròn phát sinh khi sử dụng để tính diện tích tam giác tối đa là 11Điều kiện e <. 005 được đáp ứng trong hầu hết mọi hệ thống dấu phẩy động thực tế. Ví dụ: khi = 2, p 8 đảm bảo rằng e <. 005 và khi = 10, p 3 là đủ. Trong các phát biểu như Định lý 3 thảo luận về sai số tương đối của một biểu thức, người ta hiểu rằng biểu thức được tính toán bằng cách sử dụng số học dấu phẩy động. Đặc biệt, lỗi tương đối thực sự là của biểu thức (8)n = n/26((a Do tính chất cồng kềnh của , trong phát biểu của các định lý, chúng ta thường nói giá trị tính toán của E thay vì viết ra E bằng ký hiệu vòng tròn Giới hạn lỗi thường quá bi quan. Trong ví dụ số đưa ra ở trên, giá trị tính toán của là 2. 35, so với giá trị thực là 2. 34216 cho lỗi tương đối bằng 0. 7 Ví dụ cuối cùng về một biểu thức có thể được viết lại để sử dụng phép hủy lành tính là (1 + x)n, trong đó. Biểu thức này phát sinh trong tính toán tài chính. Cân nhắc gửi 100 đô la mỗi ngày vào tài khoản ngân hàng với lãi suất hàng năm là 6%, ghép lãi hàng ngày. Nếu n = 365 và i =. 06, số tiền tích lũy được vào cuối một năm là 100đô la. Nếu giá trị này được tính bằng cách sử dụng Biểu thức rắc rối (1 + i/n)n có thể được viết lại thành enln(1 + i/n), vấn đề bây giờ là tính ln(1 + x) cho x nhỏ. Một cách tiếp cận là sử dụng phép tính gần đúng ln(1 + x) Định lý 4 giả định rằng n = n/24 xấp xỉ ln(x) trong phạm vi 1/2 ulp. Vấn đề nó giải quyết là khi x nhỏ, n = n/28(1 Định lý 4Nếu ln(1 + x) được tính theo công thứcsai số tương đối nhiều nhất là 5 Công thức này sẽ hoạt động với bất kỳ giá trị nào của x nhưng chỉ thú vị khi xảy ra sự hủy bỏ thảm khốc trong công thức ngây thơ ln(1 + x). Mặc dù công thức có vẻ bí ẩn, nhưng có một lời giải thích đơn giản cho lý do tại sao nó hoạt động. Viết ln(1 + x) dưới dạng Hệ số bên trái có thể được tính chính xác, nhưng hệ số bên phải µ(x) = ln(1 + x)/x sẽ bị lỗi làm tròn lớn khi thêm 1 vào x. Tuy nhiên, µ gần như không đổi, vì ln(1 + x) Kết quả của phần này có thể được tóm tắt bằng cách nói rằng một chữ số bảo vệ đảm bảo độ chính xác khi các đại lượng đã biết chính xác gần đó bị trừ đi (khử lành tính). Đôi khi một công thức đưa ra kết quả không chính xác có thể được viết lại để có độ chính xác số cao hơn nhiều bằng cách sử dụng phép hủy lành tính; . Giá của một chữ số bảo vệ không cao, bởi vì nó chỉ yêu cầu làm cho bộ cộng rộng hơn một chút. Đối với bộ cộng chính xác kép 54 bit, chi phí bổ sung nhỏ hơn 2%. Với mức giá này, bạn có thể chạy nhiều thuật toán, chẳng hạn như công thức tính diện tích hình tam giác và biểu thức ln(1 + x). Mặc dù hầu hết các máy tính hiện đại đều có số bảo vệ, nhưng có một số ít (chẳng hạn như hệ thống Cray) không có. Hoạt động tròn chính xácKhi các phép tính dấu phẩy động được thực hiện với một chữ số bảo vệ, chúng không chính xác như thể chúng được tính toán chính xác sau đó được làm tròn thành số dấu phẩy động gần nhất. Các hoạt động được thực hiện theo cách này sẽ được gọi là làm tròn chính xác. Ví dụ ngay trước Định lý 2 cho thấy một chữ số bảo vệ không phải lúc nào cũng cho kết quả được làm tròn chính xác. Phần trước đã đưa ra một số ví dụ về thuật toán yêu cầu chữ số bảo vệ để hoạt động bình thường. Phần này đưa ra các ví dụ về thuật toán yêu cầu làm tròn chính xác Cho đến nay, định nghĩa về làm tròn vẫn chưa được đưa ra. Làm tròn đơn giản, ngoại trừ cách làm tròn nửa chừng các trường hợp; . 5 vòng thành 12 hay 13? . 5 sẽ làm tròn thành 13. Đây là cách làm tròn hoạt động trên máy tính VAX của Digital Equipment Corporation. Một trường phái tư duy khác nói rằng vì các số kết thúc bằng 5 nằm ở giữa hai lần làm tròn có thể, nên chúng nên làm tròn xuống một nửa và làm tròn nửa còn lại. Một cách để đạt được hành vi 50% này là yêu cầu kết quả được làm tròn có chữ số có nghĩa nhỏ nhất là số chẵn. Như vậy 12. 5 vòng thành 12 chứ không phải 13 vì 2 chẵn. Phương pháp nào trong số những phương pháp này là tốt nhất, làm tròn lên hoặc làm tròn thành số chẵn? Định lý 5Cho x và y là các số dấu phẩy động và xác định x0 = x, x1 = (x0y)Để làm rõ kết quả này, hãy xem xét và mỗi giá trị liên tiếp của xn tăng thêm. 01, cho đến khi xn = 9. 45 (n Một ứng dụng của làm tròn chính xác xảy ra trong nhiều số học chính xác. Có hai cách tiếp cận cơ bản để đạt được độ chính xác cao hơn. Một cách tiếp cận biểu thị các số dấu phẩy động bằng cách sử dụng một ý nghĩa rất lớn, được lưu trữ trong một mảng các từ và mã hóa các quy trình để thao tác các số này trong hợp ngữ. Cách tiếp cận thứ hai biểu thị các số dấu phẩy động có độ chính xác cao hơn dưới dạng một mảng các số dấu phẩy động thông thường, trong đó việc thêm các phần tử của mảng với độ chính xác vô hạn sẽ phục hồi số dấu phẩy động có độ chính xác cao. Đây là cách tiếp cận thứ hai sẽ được thảo luận ở đây. Ưu điểm của việc sử dụng một mảng các số dấu phẩy động là nó có thể được mã hóa khả chuyển bằng ngôn ngữ cấp cao, nhưng nó yêu cầu phép tính số học được làm tròn chính xác Chìa khóa của phép nhân trong hệ thống này là biểu diễn tích xy dưới dạng tổng, trong đó mỗi phép cộng có cùng độ chính xác với x và y. Điều này có thể được thực hiện bằng cách tách x và y. Viết x = xh + xl và y = yh + yl, tích chính xác là xy = xh yh + xh yl + xl yh + xl ylNếu x và y có p bit có nghĩa, thì các phép cộng cũng sẽ có p bit có nghĩa với điều kiện là xl, xh, yh, yl có thể được biểu diễn bằng cách sử dụng [p/2] bit. Khi p chẵn, dễ dàng tìm được một phép chia. số x0. x1. xp - 1 có thể được viết dưới dạng tổng của x0. x1. xp/2 - 1 và 0. 0. 0xp/2. xp - 1. Khi p là số lẻ, phương pháp tách đơn giản này sẽ không hoạt động. Tuy nhiên, có thể thu được thêm một bit bằng cách sử dụng các số âm. Ví dụ: nếu Định lý 6Cho p là độ chính xác của dấu phẩy động, với hạn chế là p chẵn khivà mỗi xi có thể biểu diễn bằng cách sử dụng [p/2] bit chính xác Để xem định lý này hoạt động như thế nào trong một ví dụ, hãy Ví dụ cuối cùng về làm tròn chính xác, xem xét chia m cho 10. Kết quả là một số dấu phẩy động nói chung sẽ không bằng m/10. Khi Định lý 7KhiBằng chứngChia tỷ lệ theo lũy thừa hai là vô hại, vì nó chỉ thay đổi số mũ, không thay đổi ý nghĩa. Nếu q = m/n, thì chia tỷ lệ n sao cho 2p - 1Đó là do m có nhiều nhất 1 bit bên phải điểm nhị phân nên n sẽ làm tròn thành m. Để đối phó với trường hợp giữa chừng khi. n-m. = 1/4, lưu ý rằng vì m chưa chia tỷ lệ ban đầu có. m. < 2p - 1, bit bậc thấp của nó là 0, vì vậy bit bậc thấp của m được chia tỷ lệ cũng là 0. Do đó, các trường hợp nửa chừng sẽ làm tròn thành m. Giả sử rằng q =. q1q2. , và để =. q1q2. qp1. Ước tính, ước lượng. n-m. , tính toán đầu tiên. - q. =. N/2p + 1 - m/n. , trong đó N là số nguyên lẻ. Vì n = 2i + 2j và 2p - 1 Tử số là một số nguyên, và vì N là số lẻ nên thực tế nó là một số nguyên lẻ. Như vậy,. - q. Giả sử q =(2p-1+2k)2-p-1-2-p-1 . z This establishes and proves the theorem. z Định lý đúng với mọi cơ số Bây giờ chúng ta đang ở vị trí để trả lời câu hỏi, Có vấn đề gì không nếu các phép toán số học cơ bản gây ra lỗi làm tròn nhiều hơn một chút so với mức cần thiết? . Phần này đã thảo luận về một số thuật toán yêu cầu các chữ số bảo vệ để tạo ra kết quả chính xác theo nghĩa này. Tuy nhiên, nếu đầu vào của các công thức đó là các số đại diện cho các phép đo không chính xác, thì các giới hạn của Định lý 3 và 4 trở nên ít thú vị hơn. Lý do là sự hủy lành tính x - y có thể trở thành thảm họa nếu x và y chỉ xấp xỉ với một đại lượng đo được nào đó. Nhưng các phép toán chính xác rất hữu ích ngay cả khi đối mặt với dữ liệu không chính xác, bởi vì chúng cho phép chúng ta thiết lập các mối quan hệ chính xác như đã thảo luận trong Định lý 6 và 7. Chúng rất hữu ích ngay cả khi mọi biến dấu phẩy động chỉ là một giá trị gần đúng với một số giá trị thực Tiêu chuẩn IEEECó hai tiêu chuẩn IEEE khác nhau cho tính toán dấu phẩy động. IEEE 754 là một tiêu chuẩn nhị phân yêu cầu Phần này giới thiệu về tiêu chuẩn IEEE. Mỗi tiểu mục thảo luận về một khía cạnh của tiêu chuẩn và lý do tại sao nó được đưa vào. Mục đích của bài báo này không phải là để tranh luận rằng tiêu chuẩn IEEE là tiêu chuẩn dấu phẩy động tốt nhất có thể mà là để chấp nhận tiêu chuẩn như đã cho và giới thiệu về việc sử dụng nó. Để biết đầy đủ chi tiết, hãy tham khảo các tiêu chuẩn [IEEE 1987; . 1984] Định dạng và hoạt độngCăn cứRõ ràng là tại sao IEEE 854 cho phép Có một số lý do tại sao IEEE 854 yêu cầu rằng nếu cơ sở không phải là 10 thì nó phải là 2. Phần này đã đề cập đến một lý do. kết quả phân tích lỗi chặt chẽ hơn nhiều khi Một lời giải thích khả dĩ khác cho việc chọn Trong hầu hết các phần cứng hiện đại, hiệu suất đạt được bằng cách tránh dịch chuyển cho một tập hợp con toán hạng là không đáng kể và do đó, độ dao động nhỏ của Độ chính xác đơn của IEEE 754 được mã hóa thành 32 bit, sử dụng 1 bit cho dấu, 8 bit cho số mũ và 23 bit cho dấu và. Tuy nhiên, nó sử dụng một bit ẩn, do đó, ý nghĩa là 24 bit (p = 24), mặc dù nó được mã hóa chỉ bằng 23 bit Độ chính xácTiêu chuẩn IEEE xác định bốn độ chính xác khác nhau. đơn, đôi, mở rộng đơn và mở rộng gấp đôi. Trong IEEE 754, độ chính xác đơn và kép tương ứng với hầu hết các phần cứng dấu phẩy động cung cấp. Độ chính xác đơn chiếm một từ 32 bit duy nhất, độ chính xác kép chiếm hai từ 32 bit liên tiếp. Độ chính xác mở rộng là một định dạng cung cấp thêm ít nhất một chút độ chính xác và phạm vi số mũ () Tiêu chuẩn IEEE chỉ xác định giới hạn dưới về số lượng bit bổ sung mà độ chính xác mở rộng cung cấp. Định dạng mở rộng kép tối thiểu được phép đôi khi được gọi là định dạng 80 bit, mặc dù bảng hiển thị định dạng đó bằng cách sử dụng 79 bit. Lý do là việc triển khai phần cứng với độ chính xác mở rộng thường không sử dụng bit ẩn và do đó sẽ sử dụng 80 thay vì 79 bit Tiêu chuẩn nhấn mạnh nhất vào độ chính xác mở rộng, không đưa ra khuyến nghị nào liên quan đến độ chính xác kép, nhưng khuyến nghị mạnh mẽ rằng Triển khai nên hỗ trợ định dạng mở rộng tương ứng với định dạng cơ bản rộng nhất được hỗ trợ, Một động lực cho độ chính xác mở rộng đến từ máy tính, thường sẽ hiển thị 10 chữ số, nhưng sử dụng 13 chữ số bên trong. Bằng cách chỉ hiển thị 10 trong số 13 chữ số, máy tính xuất hiện với người dùng dưới dạng "hộp đen" tính toán hàm mũ, cosin, v.v. chính xác đến 10 chữ số. Để máy tính tính toán các hàm như exp, log và cos trong vòng 10 chữ số với hiệu quả hợp lý, nó cần thêm một vài chữ số để hoạt động với. Không khó để tìm một biểu thức hữu tỷ đơn giản xấp xỉ nhật ký với sai số 500 đơn vị ở vị trí cuối cùng. Do đó tính toán với 13 chữ số cho câu trả lời đúng với 10 chữ số. Bằng cách ẩn 3 chữ số thừa này, máy tính đưa ra một mô hình đơn giản cho người vận hành Độ chính xác mở rộng trong tiêu chuẩn IEEE phục vụ chức năng tương tự. Nó cho phép các thư viện tính toán số lượng một cách hiệu quả trong khoảng. 5 ulp với độ chính xác đơn (hoặc kép), cung cấp cho người dùng các thư viện đó một mô hình đơn giản, cụ thể là mỗi thao tác nguyên thủy, có thể là một phép nhân đơn giản hoặc một lệnh gọi nhật ký, trả về một giá trị chính xác trong khoảng. 5 lần. Tuy nhiên, khi sử dụng độ chính xác mở rộng, điều quan trọng là đảm bảo rằng việc sử dụng nó minh bạch cho người dùng. Ví dụ: trên máy tính bỏ túi, nếu biểu diễn bên trong của giá trị hiển thị không được làm tròn đến cùng độ chính xác như hiển thị, thì kết quả của các thao tác tiếp theo sẽ phụ thuộc vào các chữ số bị ẩn và có vẻ như người dùng không thể đoán trước Để minh họa thêm về độ chính xác mở rộng, hãy xem xét vấn đề chuyển đổi giữa độ chính xác đơn và số thập phân của IEEE 754. Lý tưởng nhất là các số có độ chính xác đơn sẽ được in với đủ chữ số để khi đọc lại số thập phân, số có độ chính xác đơn có thể được phục hồi. Hóa ra 9 chữ số thập phân là đủ để khôi phục một số nhị phân chính xác duy nhất (xem phần ). Khi chuyển đổi một số thập phân trở lại biểu diễn nhị phân duy nhất của nó, một lỗi làm tròn nhỏ bằng 1 ulp là nghiêm trọng, vì nó sẽ đưa ra câu trả lời sai. Đây là một tình huống mà độ chính xác mở rộng là rất quan trọng đối với một thuật toán hiệu quả. Khi khả dụng mở rộng đơn, tồn tại một phương pháp rất đơn giản để chuyển đổi một số thập phân thành một số nhị phân chính xác duy nhất. Đầu tiên đọc trong 9 chữ số thập phân dưới dạng số nguyên N, bỏ qua dấu thập phân. Từ , p Nếu độ chính xác kép được hỗ trợ, thì thuật toán ở trên sẽ được chạy ở độ chính xác kép thay vì mở rộng đơn, nhưng để chuyển đổi độ chính xác kép thành số thập phân 17 chữ số và ngược lại sẽ yêu cầu định dạng mở rộng kép số mũVì số mũ có thể dương hoặc âm nên phải chọn phương pháp nào đó để biểu diễn dấu của nó. Hai phương pháp phổ biến để biểu diễn các số có dấu là dấu/độ lớn và phần bù hai. Dấu hiệu/độ lớn là hệ thống được sử dụng cho dấu hiệu của ý nghĩa và trong các định dạng IEEE. một bit được sử dụng để giữ dấu, các bit còn lại đại diện cho độ lớn của số. Biểu diễn bổ sung của hai thường được sử dụng trong số học số nguyên. Trong lược đồ này, một số trong phạm vi [-2p-1, 2p-1 - 1] được biểu diễn bằng số không âm nhỏ nhất đồng dư với nó theo modulo 2p Tiêu chuẩn nhị phân của IEEE không sử dụng một trong hai phương pháp này để biểu diễn số mũ mà thay vào đó sử dụng biểu diễn sai lệch. Trong trường hợp độ chính xác đơn, trong đó số mũ được lưu trữ trong 8 bit, độ lệch là 127 (đối với độ chính xác kép là 1023). Điều này có nghĩa là nếu giá trị của các bit lũy thừa được hiểu là một số nguyên không dấu, thì số mũ của số dấu phẩy động là- 127. Đây thường được gọi là số mũ không thiên vị để phân biệt với số mũ thiên vị Nhắc đến , độ chính xác đơn có emax = 127 và emin = -126. Lý do để có. emin. < emax sao cho nghịch đảo của số nhỏ nhất không bị tràn. Mặc dù đúng là số nghịch đảo của số lớn nhất sẽ tràn, nhưng tràn thường ít nghiêm trọng hơn tràn. Phần này giải thích rằng emin - 1 được sử dụng để đại diện cho 0 và sẽ giới thiệu cách sử dụng emax + 1. Trong độ chính xác đơn của IEEE, điều này có nghĩa là các số mũ sai lệch nằm trong khoảng từ emin - 1 = -127 và emax + 1 = 128, trong khi các số mũ không thiên vị nằm trong khoảng từ 0 đến 255, chính xác là các số không âm có thể được biểu diễn bằng 8 bit hoạt độngTiêu chuẩn IEEE yêu cầu kết quả của phép cộng, phép trừ, phép nhân và phép chia phải được làm tròn chính xác. Nghĩa là, kết quả phải được tính toán chính xác và sau đó làm tròn đến số dấu phẩy động gần nhất (sử dụng làm tròn số chẵn). Phần này đã chỉ ra rằng việc tính toán hiệu hoặc tổng chính xác của hai số dấu phẩy động có thể rất tốn kém khi số mũ của chúng khác nhau đáng kể. Phần đó đã giới thiệu các chữ số bảo vệ, cung cấp một cách thực tế để tính toán sự khác biệt trong khi vẫn đảm bảo rằng sai số tương đối là nhỏ. Tuy nhiên, tính toán với một chữ số bảo vệ sẽ không phải lúc nào cũng đưa ra câu trả lời giống như tính toán kết quả chính xác và sau đó làm tròn. Bằng cách đưa ra một chữ số bảo vệ thứ hai và một bit cố định thứ ba, sự khác biệt có thể được tính toán với chi phí chỉ cao hơn một chút so với một chữ số bảo vệ duy nhất, nhưng kết quả vẫn giống như nếu sự khác biệt được tính toán chính xác và sau đó được làm tròn [Goldberg 1990]. Do đó, tiêu chuẩn có thể được thực hiện một cách hiệu quả Một lý do để xác định hoàn toàn kết quả của các phép tính số học là để cải thiện tính di động của phần mềm. Khi một chương trình được di chuyển giữa hai máy và cả hai đều hỗ trợ số học IEEE, thì nếu có bất kỳ kết quả trung gian nào khác đi, thì đó phải là do lỗi phần mềm, không phải do sự khác biệt về số học. Một ưu điểm khác của đặc tả chính xác là nó giúp dễ dàng suy luận về dấu chấm động hơn. Chứng minh về dấu phẩy động đủ khó, không cần phải xử lý nhiều trường hợp phát sinh từ nhiều loại số học. Giống như các chương trình số nguyên có thể được chứng minh là đúng, các chương trình dấu phẩy động cũng vậy, mặc dù điều được chứng minh trong trường hợp đó là lỗi làm tròn của kết quả thỏa mãn các giới hạn nhất định. Định lý 4 là một ví dụ về chứng minh như vậy. Những bằng chứng này được thực hiện dễ dàng hơn nhiều khi các hoạt động được suy luận được chỉ định chính xác. Sau khi một thuật toán được chứng minh là đúng cho số học IEEE, nó sẽ hoạt động chính xác trên bất kỳ máy nào hỗ trợ tiêu chuẩn IEEE Brown [1981] đã đề xuất các tiên đề cho dấu phẩy động bao gồm hầu hết phần cứng dấu phẩy động hiện có. Tuy nhiên, bằng chứng trong hệ thống này không thể xác minh thuật toán của các phần và , yêu cầu các tính năng không có trên tất cả phần cứng. Hơn nữa, các tiên đề của Brown phức tạp hơn việc chỉ đơn giản xác định các thao tác được thực hiện chính xác và sau đó làm tròn. Do đó, việc chứng minh các định lý từ các tiên đề Brown thường khó hơn việc chứng minh chúng với giả định các phép toán được làm tròn chính xác Không có thỏa thuận hoàn toàn về những hoạt động mà một tiêu chuẩn dấu phẩy động sẽ bao gồm. Ngoài các phép toán cơ bản +, -, × và /, tiêu chuẩn IEEE cũng chỉ định rằng căn bậc hai, phần dư và chuyển đổi giữa số nguyên và dấu phẩy động được làm tròn chính xác. Nó cũng yêu cầu chuyển đổi giữa các định dạng bên trong và số thập phân được làm tròn chính xác (ngoại trừ các số rất lớn). Kulisch và Miranker [1986] đã đề xuất thêm sản phẩm bên trong vào danh sách các hoạt động được chỉ định chính xác. Họ lưu ý rằng khi các sản phẩm bên trong được tính toán theo số học của IEEE, câu trả lời cuối cùng có thể khá sai. Ví dụ: tổng là trường hợp đặc biệt của tích bên trong và tổng ((2 × 10-30 + 1030) - 1030) - 10-30 chính xác bằng 10-30, nhưng trên máy có số học IEEE, kết quả tính toán sẽ . Có thể tính toán các sản phẩm bên trong trong vòng 1 ulp với ít phần cứng hơn so với việc triển khai hệ số nhân nhanh [Kirchner và Kulish 1987]. Tất cả các hoạt động được đề cập trong tiêu chuẩn được yêu cầu phải được làm tròn chính xác ngoại trừ chuyển đổi giữa thập phân và nhị phân. Lý do là các thuật toán hiệu quả để làm tròn chính xác tất cả các phép toán đã biết, ngoại trừ chuyển đổi. Để chuyển đổi, các thuật toán hiệu quả nhất được biết đến tạo ra kết quả kém hơn một chút so với các thuật toán được làm tròn chính xác [Coonen 1984] Tiêu chuẩn IEEE không yêu cầu các hàm siêu việt phải được làm tròn chính xác do tình trạng tiến thoái lưỡng nan của người tạo bảng. Để minh họa, giả sử bạn đang tạo một bảng hàm mũ tới 4 vị trí. Sau đó, hết hạn (1. 626) = 5. 0835. Điều này có nên được làm tròn thành 5. 083 hoặc 5. 084? . 626) được tính toán cẩn thận hơn, nó trở thành 5. 08350. Và sau đó 5. 083500. Và sau đó 5. 0835000. Vì exp là siêu nghiệm, nên điều này có thể tiếp diễn tùy ý trong một khoảng thời gian dài trước khi phân biệt được liệu exp(1. 626) là 5. 083500. 0ddd hoặc 5. 0834999. 9ddd. Do đó, không thực tế khi xác định rằng độ chính xác của các hàm siêu việt giống như khi chúng được tính toán với độ chính xác vô hạn và sau đó được làm tròn. Một cách tiếp cận khác là chỉ định các hàm siêu việt theo thuật toán. Nhưng dường như không có một thuật toán nào hoạt động tốt trên tất cả các kiến trúc phần cứng. Xấp xỉ hợp lý, CORDIC và bảng lớn là ba kỹ thuật khác nhau được sử dụng để tính toán siêu việt trên các máy hiện đại. Mỗi cái phù hợp với một loại phần cứng khác nhau và hiện tại không có thuật toán đơn lẻ nào hoạt động được chấp nhận trên nhiều loại phần cứng hiện tại Số lượng đặc biệtTrên một số phần cứng dấu phẩy động, mọi mẫu bit biểu thị một số dấu phẩy động hợp lệ. Hệ thống IBM/370 là một ví dụ về điều này. Mặt khác, VAXTM dành riêng một số mẫu bit để biểu thị các số đặc biệt được gọi là toán hạng dành riêng. Ý tưởng này bắt nguồn từ CDC 6600, có các mẫu bit cho số lượng đặc biệt n = n/29 và if (n==0) return u0 Tiêu chuẩn IEEE tiếp tục theo truyền thống này và có NaN (Không phải là Số) và vô số. Không có bất kỳ đại lượng đặc biệt nào, không có cách nào tốt để xử lý các tình huống đặc biệt như lấy căn bậc hai của một số âm, ngoài việc hủy bỏ tính toán. Trong Hệ thống IBM/370 FORTRAN, hành động mặc định để đáp ứng việc tính căn bậc hai của một số âm như -4 dẫn đến việc in thông báo lỗi. Vì mỗi mẫu bit đại diện cho một số hợp lệ, nên giá trị trả về của căn bậc hai phải là một số dấu phẩy động. Trong trường hợp Hệ thống/370 FORTRAN, được trả về. Trong số học của IEEE, một NaN được trả về trong tình huống này Tiêu chuẩn IEEE chỉ định các giá trị đặc biệt sau (xem ). ± 0, số không chuẩn hóa, ± NaNTheo truyền thống, phép tính 0/0 hoặc đã được coi là một lỗi không thể khôi phục khiến quá trình tính toán bị dừng. Tuy nhiên, có những ví dụ hợp lý để tính toán tiếp tục trong tình huống như vậy. Hãy xem xét một chương trình con tìm các số 0 của một hàm f, chẳng hạn như if (n==0) return u1. Theo truyền thống, công cụ tìm số 0 yêu cầu người dùng nhập khoảng [a, b] mà hàm được xác định và trên đó công cụ tìm số 0 sẽ tìm kiếm. Đó là, chương trình con được gọi là if (n==0) return u2, if (n==0) return u3, if (n==0) return u4. Công cụ tìm số 0 hữu ích hơn sẽ không yêu cầu người dùng nhập thông tin bổ sung này. Công cụ tìm số 0 tổng quát hơn này đặc biệt thích hợp cho máy tính, trong đó việc nhập một hàm là điều tự nhiên và sau đó rất khó xử khi phải chỉ định miền. Tuy nhiên, thật dễ hiểu tại sao hầu hết các công cụ tìm số 0 đều yêu cầu miền. Công cụ tìm số 0 thực hiện công việc của nó bằng cách thăm dò hàm if (n==0) return u5 ở các giá trị khác nhau. Nếu nó thăm dò một giá trị bên ngoài miền của if (n==0) return u5, thì mã của if (n==0) return u5 có thể tính toán tốt 0/0 hoặc, và quá trình tính toán sẽ dừng lại, hủy bỏ quá trình tìm số 0 một cách không cần thiết Vấn đề này có thể tránh được bằng cách đưa ra một giá trị đặc biệt gọi là NaN và chỉ định rằng việc tính toán các biểu thức như 0/0 và tạo ra NaN, thay vì tạm dừng. Danh sách một số tình huống có thể gây ra NaN được đưa ra trong. Sau đó, khi if (n==0) return u1 thăm dò bên ngoài miền của if (n==0) return u5, mã cho if (n==0) return u5 sẽ trả về NaN và công cụ tìm số 0 có thể tiếp tục. Tức là, if (n==0) return u1 không bị "trừng phạt" vì đoán sai. Với ví dụ này, thật dễ dàng để biết kết quả của việc kết hợp NaN với một số dấu phẩy động thông thường sẽ là gì. Giả sử rằng tuyên bố cuối cùng của if (n==0) return u5 là n = n/213 n = n/214. Nếu d < 0, thì if (n==0) return u5 sẽ trả về một NaN. Vì d < 0, nên n = n/216 là một NaN và n = n/217 sẽ là một NaN, nếu tổng của một NaN và bất kỳ số nào khác là một NaN. Tương tự, nếu một toán hạng của phép chia là NaN, thì thương phải là NaN. Nói chung, bất cứ khi nào một NaN tham gia vào hoạt động dấu chấm động, kết quả là một NaN khácBẢNG D-3 Các thao tác tạo ra NaN+ n = n/218x n = n/218 0, n = n/218 y(when x < 0) Một cách tiếp cận khác để viết bộ giải số 0 không yêu cầu người dùng nhập miền là sử dụng tín hiệu. Trình tìm điểm không có thể cài đặt trình xử lý tín hiệu cho các ngoại lệ dấu phẩy động. Sau đó, nếu if (n==0) return u5 được đánh giá bên ngoài miền của nó và đưa ra một ngoại lệ, quyền kiểm soát sẽ được trả lại cho bộ giải zero. Vấn đề với cách tiếp cận này là mỗi ngôn ngữ có một phương thức xử lý tín hiệu khác nhau (nếu nó có một phương thức nào đó), và vì vậy nó không có hy vọng về tính di động Trong IEEE 754, NaN thường được biểu diễn dưới dạng số dấu phẩy động với số mũ emax + 1 và các ký hiệu khác không. Việc triển khai được tự do đưa thông tin phụ thuộc vào hệ thống vào ý nghĩa và. Do đó, không có một NaN duy nhất, mà là cả một gia đình NaN. Khi một NaN và một số dấu phẩy động thông thường được kết hợp, kết quả sẽ giống với toán hạng NaN. Do đó, nếu kết quả của một phép tính dài là NaN, thì thông tin phụ thuộc vào hệ thống trong ý nghĩa và sẽ là thông tin được tạo khi NaN đầu tiên trong phép tính được tạo. Trên thực tế, có một báo trước cho tuyên bố cuối cùng. Nếu cả hai toán hạng đều là NaN, thì kết quả sẽ là một trong những NaN đó, nhưng đó có thể không phải là NaN được tạo trước vô cựcGiống như NaN cung cấp một cách để tiếp tục tính toán khi gặp phải các biểu thức như 0/0 ora, infinity cung cấp một cách để tiếp tục khi xảy ra tràn. Điều này an toàn hơn nhiều so với việc chỉ trả về số lớn nhất có thể biểu thị. Ví dụ: xem xét máy tính, khi Việc chia 0 cho 0 dẫn đến một NaN. Tuy nhiên, một số khác không chia cho 0, trả về vô cùng. 1/0 = Quy tắc xác định kết quả của phép toán có toán hạng là vô hạn rất đơn giản. thay số vô cực bằng số hữu hạn x và lấy giới hạn là x Tương tự, 4 - Khi một biểu thức con ước tính thành NaN, giá trị của toàn bộ biểu thức cũng là một NaN. Tuy nhiên, trong trường hợp ± Không có chữ kýSố 0 được biểu thị bằng số mũ emin - 1 và ý nghĩa bằng 0. Vì bit dấu có thể nhận hai giá trị khác nhau, nên có hai số không, +0 và -0. Nếu có sự khác biệt khi so sánh +0 và -0, các phép thử đơn giản như n = n/2002 n = n/2003 n = n/2004 n = n/2005 sẽ có hành vi rất khó đoán, tùy thuộc vào dấu của n = n/2006. Do đó, tiêu chuẩn IEEE xác định phép so sánh sao cho +0 = -0, thay vì -0 < +0. Mặc dù luôn có thể bỏ qua dấu của số 0, nhưng tiêu chuẩn IEEE không làm như vậy. Khi phép nhân hoặc phép chia liên quan đến số 0 có dấu, quy tắc dấu thông thường được áp dụng để tính dấu của câu trả lời. Do đó 3·(+0) = +0 và +0/-3 = -0. Nếu số 0 không có dấu thì quan hệ 1/(1/x) = x sẽ không đúng khi x = ± Một ví dụ khác về việc sử dụng luồng dưới mối quan tâm bằng 0 có dấu và các hàm có gián đoạn ở 0, chẳng hạn như nhật ký. Trong số học của IEEE, việc xác định log 0 = - Có lẽ cách sử dụng số không có dấu thú vị nhất xảy ra trong số học phức tạp. Để lấy một ví dụ đơn giản, hãy xem xét phương trình. Điều này chắc chắn đúng khi z Quay lại. Nếu z =1 = -1 + i0 thì 1/z = 1/(-1 + i0) = [(-1- i0)]/[(-1 + i0)(-1 - i0)] = (-1 -- i0)/((-1)và như vậy, trong khi. Do đó, số học IEEE duy trì danh tính này cho tất cả z. Một số ví dụ phức tạp hơn được đưa ra bởi Kahan [1987]. Mặc dù việc phân biệt giữa +0 và -0 có những ưu điểm nhưng đôi khi có thể gây nhầm lẫn. Ví dụ: số 0 có dấu hủy mối quan hệ x = y số không chuẩn hóaXem xét các số dấu phẩy động chuẩn hóa với Thật dễ dàng để tưởng tượng việc viết đoạn mã, n = n/2002 n = n/2003 n = n/2009 n = n/2010 n = n/2011 n = n/2004 n = n/2013, và rất lâu sau đó, chương trình bị lỗi do một phép chia giả cho 0. Theo dõi các lỗi như thế này rất khó chịu và tốn thời gian. Ở mức độ triết học hơn, sách giáo khoa khoa học máy tính thường chỉ ra rằng mặc dù hiện tại việc chứng minh các chương trình lớn là đúng là không thực tế, nhưng việc thiết kế các chương trình với ý tưởng chứng minh chúng thường dẫn đến mã tốt hơn. Ví dụ: việc đưa ra các bất biến khá hữu ích, ngay cả khi chúng không được sử dụng như một phần của bằng chứng. Mã dấu phẩy động cũng giống như bất kỳ mã nào khác. nó giúp có những sự thật có thể chứng minh được để dựa vào. Ví dụ: khi phân tích công thức , sẽ rất hữu ích khi biết rằng x/2 Tiêu chuẩn IEEE sử dụng các số không chuẩn hóa, đảm bảo , cũng như các mối quan hệ hữu ích khác. Chúng là phần gây tranh cãi nhất của tiêu chuẩn và có lẽ là nguyên nhân gây ra sự chậm trễ lâu dài trong việc phê duyệt 754. Hầu hết các phần cứng hiệu suất cao tuyên bố là tương thích với IEEE đều không hỗ trợ trực tiếp các số không chuẩn hóa, mà thay vào đó là các bẫy khi tiêu thụ hoặc tạo ra các số không chuẩn và để phần mềm mô phỏng tiêu chuẩn IEEE. Ý tưởng đằng sau các số không chuẩn hóa có từ Goldberg [1967] và rất đơn giản. Khi số mũ là emin, ý nghĩa và không cần phải chuẩn hóa, sao cho khi Có một trở ngại nhỏ khi Nhắc lại ví dụ về HÌNH D-2 Xả về 0 so với dòng chảy dần minh họa các số không chuẩn hóa. Dòng số trên cùng trong hình hiển thị các số dấu phẩy động được chuẩn hóa. Lưu ý khoảng cách giữa 0 và số chuẩn hóa nhỏ nhất. Nếu kết quả của một phép tính dấu phẩy động rơi vào khoảng trống này, nó sẽ bị xóa thành 0. Dòng số dưới cùng cho biết điều gì sẽ xảy ra khi các bất thường được thêm vào tập hợp các số dấu phẩy động. "Gulf" được điền vào và khi kết quả của phép tính nhỏ hơn, nó được biểu thị bằng bất thường gần nhất. Khi các số không chuẩn hóa được thêm vào dòng số, khoảng cách giữa các số dấu phẩy động liền kề sẽ thay đổi theo cách thông thường. các khoảng cách liền kề có cùng độ dài hoặc khác nhau theo hệ số khoảng cách thay đổi đột ngột từ sang, đó là một yếu tố của, chứ không phải là sự thay đổi có trật tự theo hệ số của Nếu không có dòng chảy tràn dần, biểu thức đơn giản x - y có thể có sai số tương đối rất lớn đối với các đầu vào được chuẩn hóa, như đã thấy ở trên đối với x = 6. 87 × 10-97 và y = 6. 81 × 10-97. Các lỗi tương đối lớn có thể xảy ra ngay cả khi không bị hủy bỏ, như ví dụ sau cho thấy [Demmel 1984]. Xét phép chia hai số phức a + ib và c + id. Công thức hiển nhiên gặp vấn đề là nếu một trong hai thành phần của mẫu số c + id lớn hơn, thì công thức sẽ bị tràn, mặc dù kết quả cuối cùng có thể nằm trong phạm vi. Một phương pháp tốt hơn để tính toán các thương số là sử dụng công thức của Smith (11)Áp dụng công thức Smith cho (2 · 10-98 + i10-98)/(4 · 10-98 + i(2 · 10-98)) cho . 5 với dòng chảy từ từ. Nó mang lại 0. 4 với flush to zero, lỗi 100 ulps. Nó là điển hình cho các số không chuẩn hóa để đảm bảo giới hạn lỗi cho các đối số xuống còn 1. 0 x. Trình xử lý ngoại lệ, cờ và bẫyKhi một điều kiện đặc biệt như chia cho 0 hoặc tràn xảy ra trong số học IEEE, mặc định là cung cấp kết quả và tiếp tục. Điển hình của các kết quả mặc định là NaN cho 0/0 và Đôi khi việc tiếp tục thực thi khi đối mặt với các điều kiện ngoại lệ là không phù hợp. Phần đã đưa ra ví dụ về x/(x2 + 1). Khi x > thì mẫu số bằng vô cùng nên đáp số cuối cùng bằng 0, sai hoàn toàn. Mặc dù đối với công thức này, vấn đề có thể được giải quyết bằng cách viết lại thành 1/(x + x-1), nhưng việc viết lại có thể không phải lúc nào cũng giải quyết được vấn đề. Tiêu chuẩn IEEE khuyến nghị mạnh mẽ rằng việc triển khai cho phép cài đặt trình xử lý bẫy. Sau đó, khi một ngoại lệ xảy ra, trình xử lý bẫy được gọi thay vì đặt cờ. Giá trị được trả về bởi trình xử lý bẫy sẽ được sử dụng làm kết quả của thao tác. Trình xử lý bẫy có trách nhiệm xóa hoặc đặt cờ trạng thái; Tiêu chuẩn IEEE chia ngoại lệ thành 5 lớp. tràn, tràn, chia cho 0, hoạt động không hợp lệ và không chính xác. Có một cờ trạng thái riêng cho từng loại ngoại lệ. Ý nghĩa của ba trường hợp ngoại lệ đầu tiên là hiển nhiên. Hoạt động không hợp lệ bao gồm các tình huống được liệt kê trong và bất kỳ so sánh nào liên quan đến NaN. Kết quả mặc định của thao tác gây ra ngoại lệ không hợp lệ là trả về NaN, nhưng điều ngược lại là không đúng. Khi một trong các toán hạng của thao tác là NaN, kết quả là NaN nhưng không có ngoại lệ không hợp lệ nào được đưa ra trừ khi thao tác cũng đáp ứng một trong các điều kiện trong BẢNG D-4 Các ngoại lệ trong IEEE 754*Ngoại lệKết quả khi bẫy bị vô hiệuĐối số để bẫy luồng xử lý tràn±*x là kết quả chính xác của thao tác, Ngoại lệ không chính xác được đưa ra khi kết quả của phép toán dấu phẩy động không chính xác. Trong hệ thống Có một vấn đề triển khai liên quan đến thực tế là ngoại lệ không chính xác được đưa ra quá thường xuyên. Nếu phần cứng dấu phẩy động không có cờ của riêng nó mà thay vào đó ngắt hệ điều hành để báo hiệu một ngoại lệ dấu phẩy động, chi phí cho các ngoại lệ không chính xác có thể bị cấm. Có thể tránh được chi phí này bằng cách duy trì các cờ trạng thái bằng phần mềm. Lần đầu tiên một ngoại lệ được đưa ra, hãy đặt cờ phần mềm cho lớp thích hợp và yêu cầu phần cứng dấu phẩy động che dấu lớp ngoại lệ đó. Sau đó, tất cả các ngoại lệ tiếp theo sẽ chạy mà không làm gián đoạn hệ điều hành. Khi người dùng đặt lại cờ trạng thái đó, mặt nạ phần cứng sẽ được bật lại Người xử lý bẫyMột cách sử dụng rõ ràng cho trình xử lý bẫy là để tương thích ngược. Các mã cũ dự kiến sẽ bị hủy bỏ khi xảy ra ngoại lệ có thể cài đặt trình xử lý bẫy để hủy bỏ quy trình. Điều này đặc biệt hữu ích đối với các mã có vòng lặp như n = n/2006 ever becomes a NaN. Có một cách sử dụng thú vị hơn cho các trình xử lý bẫy xuất hiện khi tính toán các sản phẩm chẳng hạn như có khả năng bị tràn. Một giải pháp là sử dụng logarit và tính toán expinstead. Vấn đề với cách tiếp cận này là nó kém chính xác hơn và tốn kém hơn biểu thức đơn giản, ngay cả khi không có tràn. Có một giải pháp khác sử dụng bộ xử lý bẫy được gọi là đếm tràn/thừa để tránh cả hai vấn đề này [Sterbenz 1974] Ý tưởng là như sau. Có một bộ đếm toàn cầu được khởi tạo bằng 0. Bất cứ khi nào tràn sản phẩm một phần cho một số k, trình xử lý bẫy sẽ tăng bộ đếm lên một và trả về số lượng bị tràn với số mũ bao quanh. Trong độ chính xác đơn của IEEE 754, emax = 127, vì vậy nếu pk = 1. 45 × 2130, nó sẽ tràn và khiến trình xử lý bẫy được gọi, trình xử lý này sẽ đưa số mũ trở lại phạm vi, thay đổi pk thành 1. 45 × 2-62 (xem bên dưới). Tương tự, nếu pk chảy tràn, bộ đếm sẽ bị giảm đi và số mũ âm sẽ được quấn quanh thành một số dương. Khi tất cả các phép nhân được thực hiện, nếu bộ đếm bằng 0 thì tích cuối cùng là pn. Nếu bộ đếm dương, sản phẩm bị tràn, nếu bộ đếm âm, sản phẩm bị tràn. Nếu không có sản phẩm nào nằm ngoài phạm vi, trình xử lý bẫy sẽ không bao giờ được gọi và việc tính toán không phát sinh thêm chi phí. Ngay cả khi có tràn/thừa, phép tính vẫn chính xác hơn nếu nó được tính bằng logarit, bởi vì mỗi pk được tính từ pk - 1 bằng cách sử dụng phép nhân chính xác đầy đủ. Barnett [1987] thảo luận về một công thức trong đó độ chính xác đầy đủ của việc đếm thừa/thừa đã gây ra lỗi trong các bảng trước đó của công thức đó IEEE 754 chỉ định rằng khi một trình xử lý bẫy tràn hoặc bẫy tràn được gọi, nó sẽ được chuyển kết quả bao quanh làm đối số. Định nghĩa về bao quanh đối với tràn là kết quả được tính như thể với độ chính xác vô hạn, sau đó chia cho 2 Chế độ làm trònTrong tiêu chuẩn IEEE, làm tròn số xảy ra bất cứ khi nào một thao tác có kết quả không chính xác, vì (ngoại trừ chuyển đổi thập phân nhị phân) mỗi thao tác được tính toán chính xác và sau đó được làm tròn. Theo mặc định, làm tròn có nghĩa là làm tròn về phía gần nhất. Tiêu chuẩn yêu cầu cung cấp ba chế độ làm tròn khác, đó là làm tròn về 0, làm tròn về phía + Một ứng dụng của chế độ làm tròn xảy ra trong số học khoảng (một ứng dụng khác được đề cập trong ). Khi sử dụng phép tính khoảng, tổng của hai số x và y là một khoảng, trong đó x Khi phép tính dấu phẩy động được thực hiện bằng cách sử dụng số học khoảng, câu trả lời cuối cùng là một khoảng chứa kết quả chính xác của phép tính. Điều này không hữu ích lắm nếu khoảng thời gian hóa ra lớn (như thường xảy ra), vì câu trả lời đúng có thể nằm ở bất kỳ đâu trong khoảng thời gian đó. Số học khoảng thời gian có ý nghĩa hơn khi được sử dụng cùng với gói nhiều dấu phẩy động chính xác. Việc tính toán được thực hiện đầu tiên với một số độ chính xác p. Nếu số học khoảng cho thấy rằng câu trả lời cuối cùng có thể không chính xác, phép tính được thực hiện lại với độ chính xác cao hơn và cao hơn cho đến khi khoảng cuối cùng có kích thước hợp lý cờTiêu chuẩn IEEE có một số cờ và chế độ. Như đã thảo luận ở trên, có một cờ trạng thái cho mỗi trong số năm trường hợp ngoại lệ. tràn, tràn, chia cho 0, hoạt động không hợp lệ và không chính xác. Có bốn chế độ làm tròn. làm tròn về phía gần nhất, làm tròn về phía + Xem xét việc viết một chương trình con để tính xn, trong đó n là một số nguyên. Khi n > 0, một quy trình đơn giản như n = n/29 n = n/20 n = n/21 n = n/2 n = n/23 n = n/24 n = n/25 n = n/2 if (n==0) return u n = n/21 n = n/200 n = n/23 Nếu n < 0, thì cách tính xn chính xác hơn không phải là gọi n = n/2021 n = n/2022 mà là gọi n = n/2023 n = n/2022, bởi vì biểu thức đầu tiên nhân n đại lượng, mỗi đại lượng có sai số làm tròn từ phép chia (i. e. , 1/x). Trong biểu thức thứ hai đây là chính xác (i. e. , x) và phép chia cuối cùng chỉ mắc thêm một lỗi làm tròn. Thật không may, đây là một trở ngại nhỏ trong chiến lược này. Nếu n = n/2025 n = n/2022 tràn, thì trình xử lý bẫy tràn sẽ được gọi hoặc nếu không thì cờ trạng thái tràn sẽ được đặt. Điều này là không chính xác, bởi vì nếu x-n tràn dưới thì xn sẽ tràn hoặc nằm trong phạm vi. Nhưng vì tiêu chuẩn IEEE cho phép người dùng truy cập vào tất cả các cờ, nên chương trình con có thể dễ dàng sửa lỗi này. Nó chỉ đơn giản là tắt các bit kích hoạt bẫy tràn và bẫy tràn và lưu các bit trạng thái tràn và tràn. Sau đó, nó tính toán n = n/2023 n = n/2022. Nếu cả bit trạng thái tràn và tràn không được đặt, nó sẽ khôi phục chúng cùng với các bit kích hoạt bẫy. Nếu một trong các bit trạng thái được đặt, nó sẽ khôi phục các cờ và thực hiện lại phép tính bằng cách sử dụng n = n/2021 n = n/2022, điều này khiến các ngoại lệ chính xác xảy ra Một ví dụ khác về việc sử dụng cờ xảy ra khi tính toán arccos thông qua công thức arccos x = 2 arctanNếu arctan( khía cạnh hệ thốngViệc thiết kế hầu hết mọi khía cạnh của hệ thống máy tính đòi hỏi kiến thức về dấu phẩy động. Kiến trúc máy tính thường có các lệnh dấu phẩy động, trình biên dịch phải tạo các lệnh dấu phẩy động đó và hệ điều hành phải quyết định phải làm gì khi các điều kiện ngoại lệ được đưa ra cho các lệnh dấu phẩy động đó. Các nhà thiết kế hệ thống máy tính hiếm khi nhận được hướng dẫn từ các văn bản phân tích số, thường hướng đến người dùng và người viết phần mềm, không phải các nhà thiết kế máy tính. Để làm ví dụ về cách các quyết định thiết kế hợp lý có thể dẫn đến hành vi không mong muốn, hãy xem xét chương trình BASIC sau n = n/202 n = n/203 n = n/204 Khi được biên dịch và chạy bằng Borland's Turbo Basic trên PC IBM, chương trình sẽ in n = n/2031 n = n/2032. Ví dụ này sẽ được phân tích trong phần tiếp theo Bộ hướng dẫnThuật toán yêu cầu một đợt ngắn có độ chính xác cao hơn để tạo ra kết quả chính xác là điều khá phổ biến. Một ví dụ xảy ra trong công thức bậc hai ()/2a. Như đã thảo luận trong phần , khi b2 Việc tính toán b2 - 4ac với độ chính xác kép khi mỗi đại lượng a, b và c đều ở độ chính xác đơn sẽ dễ dàng nếu có một lệnh nhân lấy hai số có độ chính xác đơn và tạo ra kết quả chính xác kép. Để tạo ra tích được làm tròn chính xác của hai số có p chữ số, một bộ nhân cần tạo ra toàn bộ 2p bit của tích, mặc dù nó có thể loại bỏ các bit khi nó tiếp tục. Do đó, phần cứng để tính toán một tích có độ chính xác kép từ các toán hạng có độ chính xác đơn thường sẽ chỉ đắt hơn một chút so với hệ số nhân chính xác đơn và rẻ hơn nhiều so với hệ số nhân chính xác kép. Mặc dù vậy, các tập lệnh hiện đại có xu hướng chỉ cung cấp các lệnh tạo ra kết quả có độ chính xác tương tự như các toán hạng Nếu một lệnh kết hợp hai toán hạng chính xác đơn lẻ để tạo ra một sản phẩm có độ chính xác kép chỉ hữu ích cho công thức bậc hai, thì nó sẽ không đáng để thêm vào một tập lệnh. Tuy nhiên, hướng dẫn này có nhiều công dụng khác. Xét bài toán giải hệ phương trình tuyến tính, a11x1 + a12x2 + · · · + a1nxn= b1a21x1 + a22x2 + · · · + a2nxn= b2 · · ·an1x1 + an2x2 + · · ·+ annxn= bn có thể được viết dưới dạng ma trận là Ax = b, trong đó Giả sử rằng một giải pháp x (1) được tính toán bằng một số phương pháp, có lẽ là loại bỏ Gaussian. Có một cách đơn giản để cải thiện độ chính xác của kết quả được gọi là cải tiến lặp đi lặp lại. tính toán đầu tiên (12)rồi giải hệ (13) Ay =Lưu ý rằng nếu x(1) là nghiệm chính xác thì Ba bước , , và có thể được lặp lại, thay x(1) bằng x(2) và x(2) bằng x(3). Lập luận rằng x(i + 1) chính xác hơn x(i) chỉ là không chính thức. Để biết thêm thông tin, xem [Golub và Vân Loan 1989] Khi thực hiện cải tiến lặp lại, Tóm lại, các lệnh nhân hai số dấu phẩy động và trả về một tích có độ chính xác gấp đôi toán hạng tạo nên một bổ sung hữu ích cho tập lệnh dấu phẩy động. Một số ý nghĩa của điều này đối với trình biên dịch sẽ được thảo luận trong phần tiếp theo Ngôn ngữ và Trình biên dịchSự tương tác của trình biên dịch và dấu phẩy động được thảo luận trong Farnum [1988], và phần lớn nội dung thảo luận trong phần này được lấy từ bài báo đó mơ hồLý tưởng nhất là một định nghĩa ngôn ngữ nên xác định ngữ nghĩa của ngôn ngữ đủ chính xác để chứng minh các tuyên bố về chương trình. Mặc dù điều này thường đúng với phần nguyên của ngôn ngữ, nhưng các định nghĩa ngôn ngữ thường có vùng màu xám lớn khi nói đến dấu phẩy động. Có lẽ điều này là do thực tế là nhiều nhà thiết kế ngôn ngữ tin rằng không thể chứng minh được gì về dấu phẩy động, vì nó kéo theo lỗi làm tròn. Nếu vậy, các phần trước đã chứng minh sự ngụy biện trong lập luận này. Phần này thảo luận về một số vùng màu xám phổ biến trong các định nghĩa ngôn ngữ, bao gồm các đề xuất về cách giải quyết chúng Đáng chú ý là, một số ngôn ngữ không xác định rõ ràng rằng nếu n = n/2006 là một biến dấu phẩy động (có giá trị là n = n/2034), thì mọi lần xuất hiện của (giả sử) n = n/2035 phải có cùng giá trị. Ví dụ Ada, dựa trên mô hình của Brown, dường như ngụ ý rằng số học dấu phẩy động chỉ phải thỏa mãn các tiên đề của Brown, và do đó các biểu thức có thể có một trong nhiều giá trị có thể. Suy nghĩ về dấu phẩy động theo cách mờ nhạt này trái ngược hoàn toàn với mô hình IEEE, trong đó kết quả của mỗi phép toán dấu phẩy động được xác định chính xác. Trong mô hình IEEE, chúng ta có thể chứng minh rằng n = n/2036 ước lượng thành n = n/2037 (Định lý 7). Trong mô hình của Brown, chúng ta không thể Một sự mơ hồ khác trong hầu hết các định nghĩa ngôn ngữ liên quan đến những gì xảy ra khi tràn, tràn và các ngoại lệ khác. Tiêu chuẩn IEEE chỉ định chính xác hành vi của các ngoại lệ và do đó, các ngôn ngữ sử dụng tiêu chuẩn làm mẫu có thể tránh mọi sự mơ hồ về điểm này Một khu vực màu xám khác liên quan đến việc giải thích các dấu ngoặc đơn. Do lỗi làm tròn, các định luật kết hợp của đại số không nhất thiết đúng cho các số dấu phẩy động. Ví dụ: biểu thức n = n/2038 có đáp án hoàn toàn khác với n = n/2039 khi x = 1030, y = -1030 và z = 1 (trường hợp trước là 1, trường hợp sau là 0). Tầm quan trọng của việc bảo toàn dấu ngoặc đơn không thể được nhấn mạnh quá mức. Các thuật toán trình bày trong định lý 3, 4 và 6 đều phụ thuộc vào nó. Ví dụ, trong Định lý 6, công thức xh = mx - (mx - x) sẽ rút gọn thành xh = x nếu không có dấu ngoặc đơn, do đó phá hủy toàn bộ thuật toán. Một định nghĩa ngôn ngữ không yêu cầu dấu ngoặc đơn được vinh danh là vô ích đối với các phép tính dấu phẩy động Đánh giá biểu thức con được xác định không chính xác trong nhiều ngôn ngữ. Giả sử rằng n = n/2040 là độ chính xác kép, nhưng n = n/2006 và n = n/2042 là độ chính xác đơn. Vậy thì trong biểu thức n = n/2040 n = n/2044 n = n/2045 sản phẩm được thực hiện ở độ chính xác đơn hay kép? . trong n = n/2006 n = n/2044 n = n/2048 trong đó n = n/2049 và n = n/2050 là số nguyên, phép chia là phép toán số nguyên hay phép toán dấu phẩy động? . Đầu tiên là yêu cầu tất cả các biến trong một biểu thức có cùng kiểu. Đây là giải pháp đơn giản nhất, nhưng có một số nhược điểm. Trước hết, các ngôn ngữ như Pascal có các kiểu dải con cho phép trộn các biến dải con với các biến số nguyên, do đó, việc cấm trộn các biến chính xác đơn và kép là hơi kỳ lạ. Một vấn đề khác liên quan đến hằng số. Trong biểu thức n = n/2051, hầu hết các ngôn ngữ diễn giải 0. 1 là một hằng số chính xác duy nhất. Bây giờ, giả sử lập trình viên quyết định thay đổi khai báo của tất cả các biến dấu phẩy động từ độ chính xác đơn thành độ chính xác kép. Nếu 0. 1 vẫn được coi là một hằng số chính xác duy nhất, thì sẽ có lỗi thời gian biên dịch. Lập trình viên sẽ phải tìm kiếm và thay đổi mọi hằng số dấu phẩy động Cách tiếp cận thứ hai là cho phép các biểu thức hỗn hợp, trong trường hợp đó phải cung cấp các quy tắc để đánh giá biểu thức con. Có một số ví dụ hướng dẫn. Định nghĩa ban đầu của C yêu cầu mọi biểu thức dấu phẩy động được tính toán với độ chính xác kép [Kernighan và Ritchie 1978]. Điều này dẫn đến sự bất thường như ví dụ ở đầu phần này. Biểu thức n = n/2052 được tính toán với độ chính xác kép, nhưng nếu n = n/2053 là một biến có độ chính xác đơn, thì thương số được làm tròn thành độ chính xác đơn để lưu trữ. Vì 3/7 là một phân số nhị phân lặp lại, nên giá trị được tính toán của nó ở độ chính xác kép khác với giá trị được lưu trữ ở độ chính xác đơn. Do đó phép so sánh q = 3/7 không thành công. Điều này cho thấy rằng tính toán mọi biểu thức ở độ chính xác cao nhất hiện có không phải là một quy tắc tốt Một ví dụ hướng dẫn khác là các sản phẩm bên trong. Nếu tích bên trong có hàng nghìn số hạng, lỗi làm tròn trong tổng có thể trở nên đáng kể. Một cách để giảm lỗi làm tròn này là cộng dồn các tổng với độ chính xác kép (điều này sẽ được thảo luận chi tiết hơn trong phần ). Nếu n = n/2054 là một biến có độ chính xác kép và n = n/2055 và n = n/2056 là các mảng có độ chính xác đơn, thì vòng lặp tích bên trong sẽ giống như n = n/2054 n = n/2004 n = n/2054 n = n/2044 n = n/2061. Nếu phép nhân được thực hiện với độ chính xác đơn, thì phần lớn lợi thế của tích lũy độ chính xác kép sẽ bị mất đi, bởi vì sản phẩm bị cắt bớt thành độ chính xác đơn ngay trước khi được thêm vào biến chính xác kép Một quy tắc áp dụng cho cả hai ví dụ trước đó là tính toán một biểu thức với độ chính xác cao nhất của bất kỳ biến nào xuất hiện trong biểu thức đó. Sau đó, n = n/2053 n = n/2004 n = n/2052 sẽ được tính toán hoàn toàn với độ chính xác đơn và sẽ có giá trị boolean là true, trong khi đó, n = n/2054 n = n/2004 n = n/2054 n = n/2044 n = n/2061 sẽ được tính toán với độ chính xác kép, đạt được toàn bộ lợi thế của tích lũy độ chính xác kép. Tuy nhiên, quy tắc này quá đơn giản để bao gồm tất cả các trường hợp một cách rõ ràng. Nếu n = n/2070 và n = n/2071 là các biến có độ chính xác kép, thì biểu thức n = n/2042 n = n/2004 n = n/2006 n = n/2044 n = n/2076 chứa một biến có độ chính xác kép, nhưng việc tính tổng theo độ chính xác kép sẽ là vô nghĩa, bởi vì cả hai toán hạng đều có độ chính xác đơn, kết quả cũng vậy Một quy tắc đánh giá biểu thức con phức tạp hơn như sau. Trước tiên, gán cho mỗi thao tác một độ chính xác dự kiến, là độ chính xác tối đa của các toán hạng của nó. Phép gán này phải được thực hiện từ lá đến gốc của cây biểu thức. Sau đó thực hiện chuyền thứ hai từ gốc đến lá. Trong bước này, hãy chỉ định cho mỗi thao tác độ chính xác dự kiến tối đa và độ chính xác mà cấp độ gốc mong đợi. Trong trường hợp của n = n/2053 n = n/2004 n = n/2052, mỗi lá là độ chính xác duy nhất, vì vậy tất cả các thao tác được thực hiện với độ chính xác duy nhất. Trong trường hợp của n = n/2054 n = n/2004 n = n/2054 n = n/2044 n = n/2061, độ chính xác dự kiến của phép toán nhân là độ chính xác đơn, nhưng ở lần thứ hai, phép toán này được tăng lên độ chính xác kép vì phép toán mẹ của nó yêu cầu toán hạng có độ chính xác kép. Và trong n = n/2042 n = n/2004 n = n/2006 n = n/2044 n = n/2076, việc bổ sung được thực hiện với độ chính xác duy nhất. Farnum [1988] trình bày bằng chứng rằng thuật toán này không khó thực hiện Nhược điểm của quy tắc này là việc đánh giá một biểu thức con phụ thuộc vào biểu thức mà nó được nhúng vào. Điều này có thể có một số hậu quả khó chịu. Ví dụ: giả sử bạn đang gỡ lỗi chương trình và muốn biết giá trị của biểu thức con. Bạn không thể chỉ cần nhập biểu thức con vào trình gỡ lỗi và yêu cầu đánh giá nó, bởi vì giá trị của biểu thức con trong chương trình phụ thuộc vào biểu thức mà nó được nhúng vào. Nhận xét cuối cùng về biểu thức con. vì việc chuyển đổi hằng số thập phân thành nhị phân là một phép toán nên quy tắc đánh giá cũng ảnh hưởng đến việc giải thích hằng số thập phân. Điều này đặc biệt quan trọng đối với các hằng số như n = n/2090 không thể biểu diễn chính xác ở dạng nhị phân Một vùng màu xám tiềm năng khác xảy ra khi một ngôn ngữ bao gồm phép lũy thừa như một trong những hoạt động tích hợp của ngôn ngữ đó. Không giống như các phép tính số học cơ bản, giá trị của phép lũy thừa không phải lúc nào cũng rõ ràng [Kahan và Coonen 1982]. Nếu n = n/2091 là toán tử lũy thừa, thì chắc chắn n = n/2092 có giá trị -27. Tuy nhiên, n = n/2093 có vấn đề. Nếu toán tử ________ 3091 kiểm tra các lũy thừa nguyên, nó sẽ tính ________ 3093 là -3. 03 = -27. Mặt khác, nếu công thức xy = eylogx được sử dụng để xác định n = n/2091 cho các đối số thực, thì tùy thuộc vào hàm nhật ký, kết quả có thể là NaN (sử dụng định nghĩa tự nhiên của log(x) = n = n/2097 khi x < 0). Tuy nhiên, nếu hàm FORTRAN n = n/2098 được sử dụng thì câu trả lời sẽ là -27, vì tiêu chuẩn ANSI FORTRAN định nghĩa n = n/2099 là i Trên thực tế, tiêu chuẩn FORTRAN nói rằng Bất kỳ phép tính số học nào có kết quả không được xác định bằng toán học đều bị cấmThật không may, với sự ra đời của ± n = n/2093 là -27. Tiêu chuẩn IEEEPhần ," đã thảo luận về nhiều tính năng của tiêu chuẩn IEEE. Tuy nhiên, tiêu chuẩn IEEE không nói gì về cách truy cập các tính năng này từ ngôn ngữ lập trình. Do đó, thường có sự không phù hợp giữa phần cứng dấu phẩy động hỗ trợ tiêu chuẩn và ngôn ngữ lập trình như C, Pascal hoặc FORTRAN. Một số khả năng của IEEE có thể được truy cập thông qua thư viện các cuộc gọi chương trình con. Ví dụ: tiêu chuẩn IEEE yêu cầu căn bậc hai phải được làm tròn chính xác và hàm căn bậc hai thường được triển khai trực tiếp trong phần cứng. Chức năng này có thể dễ dàng truy cập thông qua một thói quen căn bậc hai của thư viện. Tuy nhiên, các khía cạnh khác của tiêu chuẩn không dễ thực hiện như chương trình con. Ví dụ: hầu hết các ngôn ngữ máy tính chỉ định nhiều nhất hai loại dấu phẩy động, trong khi tiêu chuẩn IEEE có bốn độ chính xác khác nhau (mặc dù các cấu hình được đề xuất là đơn cộng với mở rộng đơn hoặc mở rộng đơn, kép và mở rộng kép). Infinity cung cấp một ví dụ khác. Các hằng để biểu diễn ± Một tình huống tinh tế hơn là thao túng trạng thái liên quan đến tính toán, trong đó trạng thái bao gồm các chế độ làm tròn, bit kích hoạt bẫy, trình xử lý bẫy và cờ ngoại lệ. Một cách tiếp cận là cung cấp các chương trình con để đọc và ghi trạng thái. Ngoài ra, một cuộc gọi duy nhất có thể đặt nguyên tử một giá trị mới và trả về giá trị cũ thường hữu ích. Như các ví dụ trong phần này cho thấy, một mô hình sửa đổi trạng thái IEEE rất phổ biến là chỉ thay đổi nó trong phạm vi của một khối hoặc chương trình con. Do đó, lập trình viên phải tìm từng lối ra khỏi khối và đảm bảo trạng thái được khôi phục. Hỗ trợ ngôn ngữ để đặt trạng thái chính xác trong phạm vi của một khối sẽ rất hữu ích ở đây. Modula-3 là một ngôn ngữ triển khai ý tưởng này cho trình xử lý bẫy [Nelson 1991] Có một số điểm nhỏ cần được xem xét khi triển khai tiêu chuẩn IEEE trong một ngôn ngữ. Vì x - x = +0 với mọi x nên (+0) - (+0) = +0. Tuy nhiên, -(+0) = -0, do đó -x không được định nghĩa là 0 - x. Việc giới thiệu NaN có thể gây nhầm lẫn, vì một NaN không bao giờ bằng bất kỳ số nào khác (bao gồm cả NaN khác), vì vậy x = x không còn đúng nữa. Trên thực tế, biểu thức x n = n/2101 không được cung cấp. Hơn nữa, NaN không có thứ tự đối với tất cả các số khác, vì vậy x n = n/2102 trả về một trong các Mặc dù tiêu chuẩn IEEE xác định các hoạt động dấu phẩy động cơ bản để trả về NaN nếu bất kỳ toán hạng nào là NaN, đây có thể không phải lúc nào cũng là định nghĩa tốt nhất cho các hoạt động phức hợp. Ví dụ: khi tính toán hệ số tỷ lệ thích hợp để sử dụng trong việc vẽ đồ thị, giá trị lớn nhất của một tập hợp giá trị phải được tính toán. Trong trường hợp này, điều hợp lý là thao tác tối đa chỉ cần bỏ qua NaN Cuối cùng, làm tròn có thể là một vấn đề. Tiêu chuẩn IEEE xác định làm tròn rất chính xác và nó phụ thuộc vào giá trị hiện tại của các chế độ làm tròn. Điều này đôi khi xung đột với định nghĩa làm tròn ẩn trong chuyển đổi loại hoặc hàm n = n/2103 rõ ràng trong các ngôn ngữ. Điều này có nghĩa là các chương trình muốn sử dụng phương pháp làm tròn IEEE không thể sử dụng các ngôn ngữ gốc của ngôn ngữ tự nhiên và ngược lại, các ngôn ngữ gốc sẽ không hiệu quả để triển khai trên số lượng máy IEEE ngày càng tăng Trình tối ưu hóaVăn bản trình biên dịch có xu hướng bỏ qua chủ đề về dấu phẩy động. Ví dụ Aho et al. [1986] đề cập đến việc thay thế n = n/2104 bằng n = n/2105, khiến người đọc cho rằng nên thay thế n = n/2106 bằng n = n/2051. Tuy nhiên, hai biểu thức này không có cùng ngữ nghĩa trên máy nhị phân, vì 0. 1 không thể được biểu diễn chính xác ở dạng nhị phân. Sách giáo khoa này cũng gợi ý thay thế n = n/2108 bằng n = n/2109, mặc dù chúng ta đã thấy rằng hai biểu thức này có thể có các giá trị hoàn toàn khác nhau khi y n = n/2038 có thể có một câu trả lời hoàn toàn khác với n = n/2039, như đã thảo luận ở trên. Có một vấn đề liên quan mật thiết đến việc bảo toàn dấu ngoặc đơn được minh họa bằng đoạn mã sau n = n/205 n = n/206 : Điều này được thiết kế để đưa ra ước tính cho máy epsilon. Nếu trình biên dịch tối ưu hóa thông báo rằng eps + 1 > 1 Nhiều bài toán, chẳng hạn như tích phân số và nghiệm số của phương trình vi phân liên quan đến việc tính tổng với nhiều số hạng. Bởi vì mỗi bổ sung có khả năng gây ra một lỗi lớn như. 5 ulp, một tổng bao gồm hàng nghìn số hạng có thể có khá nhiều lỗi làm tròn. Một cách đơn giản để khắc phục điều này là lưu trữ phần tóm tắt một phần trong biến độ chính xác kép và thực hiện từng phép cộng bằng cách sử dụng độ chính xác kép. Nếu phép tính đang được thực hiện với độ chính xác đơn, thì việc tính tổng với độ chính xác kép sẽ dễ dàng trên hầu hết các hệ thống máy tính. Tuy nhiên, nếu phép tính đã được thực hiện với độ chính xác kép, thì việc nhân đôi độ chính xác không đơn giản như vậy. Một phương pháp đôi khi được ủng hộ là sắp xếp các số và cộng chúng từ nhỏ nhất đến lớn nhất. Tuy nhiên, có một phương pháp hiệu quả hơn nhiều giúp cải thiện đáng kể độ chính xác của các khoản tiền, đó là Định lý 8 (Công thức tổng Kahan)Giả sử điều đó được tính toán bằng thuật toán saun = n/207 n = n/208______309 n = n/210 n = n/211 n = n/212 n = n/213 n = n/214 Sau đó, tổng S được tính toán bằng với vị trí. Sử dụng công thức ngây thơ, tổng được tính bằng. Trình tối ưu hóa tin rằng số học dấu phẩy động tuân theo định luật đại số sẽ kết luận rằng C = [T-S] - Y = [(S+Y)-S] - Y = 0, khiến thuật toán hoàn toàn vô dụng. Những ví dụ này có thể được tóm tắt bằng cách nói rằng các trình tối ưu hóa phải cực kỳ thận trọng khi áp dụng các đồng nhất đại số chứa các số thực toán học cho các biểu thức liên quan đến các biến dấu phẩy động Một cách khác mà trình tối ưu hóa có thể thay đổi ngữ nghĩa của mã dấu phẩy động liên quan đến các hằng số. Trong biểu thức n = n/2112, có một phép toán chuyển đổi số thập phân thành nhị phân ngầm để chuyển đổi số thập phân thành hằng số nhị phân. Bởi vì hằng số này không thể được biểu diễn chính xác ở dạng nhị phân, ngoại lệ không chính xác sẽ được nêu ra. Ngoài ra, nên đặt cờ dòng dưới nếu biểu thức được đánh giá theo độ chính xác đơn. Vì hằng số không chính xác nên việc chuyển đổi chính xác thành nhị phân phụ thuộc vào giá trị hiện tại của các chế độ làm tròn IEEE. Do đó, một trình tối ưu hóa chuyển đổi n = n/2113 thành nhị phân tại thời điểm biên dịch sẽ thay đổi ngữ nghĩa của chương trình. Tuy nhiên, các hằng số như 27. 5 có thể biểu diễn chính xác ở độ chính xác nhỏ nhất hiện có có thể được chuyển đổi một cách an toàn tại thời điểm biên dịch, vì chúng luôn chính xác, không thể đưa ra bất kỳ ngoại lệ nào và không bị ảnh hưởng bởi các chế độ làm tròn. Các hằng số dự định được chuyển đổi tại thời điểm biên dịch nên được thực hiện với một khai báo hằng số, chẳng hạn như n = n/2114 n = n/2115 n = n/2004 n = n/2117 Loại bỏ biểu thức con phổ biến là một ví dụ khác về tối ưu hóa có thể thay đổi ngữ nghĩa dấu phẩy động, như được minh họa bằng đoạn mã sau n = n/215 n = n/216____217 Bất chấp những ví dụ này, vẫn có những tối ưu hóa hữu ích có thể được thực hiện trên mã dấu phẩy động. Trước hết, có các đẳng thức đại số hợp lệ cho các số dấu phẩy động. Một số ví dụ trong số học IEEE là x + y = y + x, 2 × x = x + x, 1 × x = x và 0. 5× x = x/2. Tuy nhiên, ngay cả những nhận dạng đơn giản này cũng có thể bị lỗi trên một số máy như siêu máy tính CDC và Cray. Lập lịch trình hướng dẫn và thay thế thủ tục nội tuyến là hai cách tối ưu hóa hữu ích tiềm năng khác Như một ví dụ cuối cùng, hãy xem xét biểu thức n = n/2070 n = n/2004 n = n/2045, trong đó n = n/2006 và n = n/2042 là các biến chính xác đơn và n = n/2070 là biến chính xác kép. Trên các máy có lệnh nhân hai số chính xác đơn lẻ để tạo ra số chính xác kép, n = n/2070 n = n/2004 n = n/2045 có thể được ánh xạ tới lệnh đó, thay vì được biên dịch thành một loạt lệnh chuyển đổi toán hạng thành gấp đôi rồi thực hiện nhân đôi thành gấp đôi Một số tác giả trình biên dịch xem các hạn chế cấm chuyển đổi (x + y) + z thành x + (y + z) là không liên quan, chỉ quan tâm đến các lập trình viên sử dụng các thủ thuật không thể chuyển đổi. Có lẽ họ đã nghĩ rằng các số dấu phẩy động mô hình các số thực và phải tuân theo các quy luật giống như các số thực. Vấn đề với ngữ nghĩa số thực là chúng cực kỳ tốn kém để thực hiện. Mỗi khi nhân hai số n bit thì tích sẽ có 2n bit. Mỗi khi hai số n bit có số mũ cách đều nhau được thêm vào, số bit trong tổng là n + khoảng cách giữa các số mũ. Tổng có thể lên tới (emax - emin) + n bit hoặc khoảng 2·emax + n bit. Một thuật toán bao gồm hàng nghìn thao tác (chẳng hạn như giải một hệ thống tuyến tính) sẽ sớm hoạt động trên các số có nhiều bit có nghĩa và chậm một cách vô vọng. Việc thực hiện các hàm thư viện như sin, cos lại càng khó hơn vì giá trị của các hàm siêu việt này không phải là số hữu tỉ. Số học số nguyên chính xác thường được cung cấp bởi các hệ thống lisp và rất hữu ích cho một số vấn đề. Tuy nhiên, số học dấu phẩy động chính xác hiếm khi hữu ích Thực tế là có những thuật toán hữu ích (như công thức tính tổng Kahan) khai thác thực tế là (x + y) + z giữ (cũng như các giới hạn tương tự cho -, × và /). Vì các giới hạn này áp dụng cho hầu hết mọi phần cứng thương mại, nên sẽ thật ngu ngốc nếu các lập trình viên số bỏ qua các thuật toán như vậy và sẽ là vô trách nhiệm đối với người viết trình biên dịch khi phá hủy các thuật toán này bằng cách giả vờ rằng các biến dấu phẩy động có ngữ nghĩa số thực. Xử lý ngoại lệCác chủ đề được thảo luận cho đến nay chủ yếu liên quan đến ý nghĩa hệ thống về độ chính xác và độ chính xác. Trình xử lý bẫy cũng đưa ra một số vấn đề hệ thống thú vị. Tiêu chuẩn IEEE khuyến nghị mạnh mẽ rằng người dùng có thể chỉ định trình xử lý bẫy cho từng loại trong số năm loại ngoại lệ và phần , đã đưa ra một số ứng dụng của trình xử lý bẫy do người dùng xác định. Trong trường hợp phép toán không hợp lệ và phép chia cho ngoại lệ bằng 0, trình xử lý phải được cung cấp toán hạng, nếu không, kết quả được làm tròn chính xác. Tùy thuộc vào ngôn ngữ lập trình đang được sử dụng, trình xử lý bẫy cũng có thể truy cập các biến khác trong chương trình. Đối với tất cả các trường hợp ngoại lệ, trình xử lý bẫy phải có khả năng xác định hoạt động nào đang được thực hiện và độ chính xác của đích đến Tiêu chuẩn IEEE giả định rằng các hoạt động là nối tiếp về mặt khái niệm và khi xảy ra ngắt, có thể xác định hoạt động và các toán hạng của nó. Trên các máy có đường ống hoặc nhiều đơn vị số học, khi một ngoại lệ xảy ra, có thể không đủ nếu chỉ yêu cầu trình xử lý bẫy kiểm tra bộ đếm chương trình. Hỗ trợ phần cứng để xác định chính xác hoạt động nào bị mắc kẹt có thể cần thiết Một vấn đề khác được minh họa bằng đoạn chương trình sau n = n/218 n = n/219____00 n = n/21 Giả sử phép nhân thứ hai đưa ra một ngoại lệ và trình xử lý bẫy muốn sử dụng giá trị của if (n==0) return u3. Trên phần cứng có thể thực hiện cộng và nhân song song, trình tối ưu hóa có thể sẽ di chuyển thao tác cộng lên trước phép nhân thứ hai, để phép cộng có thể tiến hành song song với phép nhân đầu tiên. Do đó, khi bẫy nhân thứ hai, if (n==0) return u3 n = n/2004 n = n/2132 n = n/2044 n = n/2134 đã được thực hiện, có khả năng thay đổi kết quả của if (n==0) return u3. Sẽ không hợp lý nếu trình biên dịch tránh loại tối ưu hóa này, bởi vì mọi hoạt động của dấu phẩy động đều có khả năng mắc bẫy và do đó hầu như tất cả các tối ưu hóa lập lịch trình hướng dẫn sẽ bị loại bỏ. Vấn đề này có thể tránh được bằng cách cấm trình xử lý bẫy truy cập trực tiếp vào bất kỳ biến nào của chương trình. Thay vào đó, trình xử lý có thể được cung cấp toán hạng hoặc kết quả dưới dạng đối số Nhưng vẫn còn những vấn đề. trong đoạn hai hướng dẫn cũng có thể được thực hiện song song. Nếu bẫy nhân, đối số của nó n = n/2011 có thể đã bị ghi đè bởi phép cộng, đặc biệt vì phép cộng thường nhanh hơn phép nhân. Các hệ thống máy tính hỗ trợ tiêu chuẩn IEEE phải cung cấp một số cách để lưu giá trị của n = n/2011, trong phần cứng hoặc bằng cách yêu cầu trình biên dịch tránh tình huống như vậy ngay từ đầu W. Kahan đã đề xuất sử dụng thay thế trước thay vì xử lý bẫy để tránh những vấn đề này. Trong phương pháp này, người dùng chỉ định một ngoại lệ và giá trị mà anh ta muốn được sử dụng làm kết quả khi ngoại lệ xảy ra. Ví dụ: giả sử rằng trong mã tính toán (sin x)/x, người dùng quyết định rằng x = 0 rất hiếm nên sẽ cải thiện hiệu suất để tránh kiểm tra x = 0 và thay vào đó xử lý trường hợp này khi 0/ . Sử dụng trình xử lý bẫy IEEE, người dùng sẽ viết trình xử lý trả về giá trị 1 và cài đặt nó trước khi tính sin x/x. Sử dụng thay thế trước, người dùng sẽ chỉ định rằng khi xảy ra thao tác không hợp lệ, giá trị 1 sẽ được sử dụng. Kahan gọi đây là sự thay thế trước, bởi vì giá trị được sử dụng phải được chỉ định trước khi xảy ra ngoại lệ. Khi sử dụng trình xử lý bẫy, giá trị được trả về có thể được tính khi bẫy xảy ra Ưu điểm của thay thế trước là nó có triển khai phần cứng đơn giản. Ngay sau khi loại ngoại lệ đã được xác định, nó có thể được sử dụng để lập chỉ mục cho bảng chứa kết quả mong muốn của thao tác. Mặc dù thay thế trước có một số thuộc tính hấp dẫn, nhưng việc chấp nhận rộng rãi tiêu chuẩn IEEE khiến nó khó có thể được các nhà sản xuất phần cứng triển khai rộng rãi các chi tiếtMột số tuyên bố đã được đưa ra trong bài báo này liên quan đến các thuộc tính của số học dấu phẩy động. Bây giờ chúng tôi tiến hành chứng minh rằng dấu phẩy động không phải là ma thuật đen, mà đúng hơn là một chủ đề đơn giản mà các tuyên bố của nó có thể được xác minh bằng toán học. Phần này được chia thành ba phần. Phần đầu tiên trình bày giới thiệu về phân tích lỗi và cung cấp thông tin chi tiết cho phần. Phần thứ hai khám phá chuyển đổi nhị phân sang thập phân, điền vào một số khoảng trống từ phần. Phần thứ ba thảo luận về công thức tính tổng Kahan, được sử dụng làm ví dụ trong phần Lỗi làm trònTrong cuộc thảo luận về lỗi làm tròn, người ta đã nói rằng một chữ số bảo vệ duy nhất là đủ để đảm bảo rằng phép cộng và phép trừ sẽ luôn chính xác (Định lý 2). Bây giờ chúng tôi tiến hành xác minh thực tế này. Định lý 2 có hai phần, một phần cho phép trừ và một phần cho phép cộng. Phần của phép trừ là Định lý 9Nếu x và y là các số dấu phẩy động dương ở định dạng có tham số Bằng chứngHoán đổi x và y nếu cần sao cho x > y. Cũng vô hại khi chia tỷ lệ x và y sao cho x được biểu thị bằng x0. x1. xp - 1 ×Từ định nghĩa của chữ số bảo vệ, giá trị tính toán của x - y là x - được làm tròn thành một số dấu phẩy động, nghĩa là (x -) + Sự khác biệt chính xác là x - y, vì vậy sai số là (x - y) - (x -+ Thứ hai, nếu x -< 1 thì trong trường hợp này . Trường hợp cuối cùng là khi x - y < 1 nhưng x - Khi Định lý 10Nếu x Bằng chứngThuật toán cộng với k chữ số bảo vệ tương tự như thuật toán trừ. Nếu xTổng ít nhất là Rõ ràng là kết hợp hai định lý này sẽ cho Định lý 2. Định lý 2 đưa ra sai số tương đối khi thực hiện một thao tác. So sánh lỗi làm tròn của x2 - y2 và (x + y) (x - y) yêu cầu biết lỗi tương đối của nhiều phép toán. Sai số tương đối của xy là Tương tự (20) xGiả sử rằng phép nhân được thực hiện bằng cách tính tích chính xác rồi làm tròn, sai số tương đối nhiều nhất là. 5 ul, vì vậy (21) ucho bất kỳ số dấu phẩy động nào u và v. Đặt ba phương trình này lại với nhau (đặt u = xy và v = x Vì vậy, lỗi tương đối phát sinh khi tính toán (x - y) (x + y) là (23)Lỗi tương đối này bằng Một phân tích tương tự của (x = ((x2 - y2) (1 + Khi x và y ở gần nhau, thuật ngữ lỗi ( Tiếp theo chúng ta chuyển sang phân tích công thức tính diện tích tam giác. Để ước tính lỗi tối đa có thể xảy ra khi tính toán với , thực tế sau đây sẽ cần thiết Định lý 11Nếu phép trừ được thực hiện với một chữ số bảo vệ và y/2Bằng chứngLưu ý rằng nếu x và y có cùng số mũ thì chắc chắn xy chính xác. Mặt khác, từ điều kiện của định lý, các số mũ có thể khác nhau nhiều nhất 1. Chia tỷ lệ và hoán đổi x và y nếu cần sao cho 0Khi Định lý 12Nếu phép trừ sử dụng chữ số bảo vệ và nếu a, b và c là các cạnh của tam giác (aBằng chứngHãy xem xét từng yếu tố một. Từ Định lý 10, band thus(a + b + c) (1 - 2 This means that there is an Số hạng tiếp theo liên quan đến phép trừ có khả năng gây thảm họa của c và a n = n/2132, vì ab có thể có lỗi làm tròn. Bởi vì a, b và c là các cạnh của một tam giác, a Số hạng thứ ba là tổng của hai đại lượng dương chính xác, vì vậy(26) (c Cuối cùng, số hạng cuối cùng là (27) (a sử dụng cả Định lý 9 và Định lý 10. Nếu phép nhân được giả định là làm tròn chính xác, sao cho x whereE = (1 + An upper bound for E is (1 + 2 Định lý 12 chắc chắn chỉ ra rằng không có sự triệt tiêu thảm khốc trong công thức. Vì vậy, mặc dù không cần thiết phải chứng minh công thức là ổn định về mặt số, nhưng việc có một giới hạn cho toàn bộ công thức là thỏa mãn, đó là điều mà Định lý 3 đưa ra Chứng minh Định lý 3Letq = (a + (b + c)) (c - (a - b)) (c + (a - b)) (a + (b - c))andQ = (a Sau đó, Định lý 12 chứng tỏ rằng Q = q(1 + được cung cấp với. Để làm cho lời giải thích heuristic ngay sau phát biểu của Định lý 4 trở nên chính xác, định lý tiếp theo mô tả mức độ gần đúng của µ(x) với một hằng số Định lý 13Nếu µ(x) = ln(1 + x)/x thì với 0Bằng chứngLưu ý rằng µ(x) = 1 - x/2 + x2/3 -. là một chuỗi xen kẽ với các số hạng giảm dần, vì vậy với xChứng minh Định lý 4Vì chuỗi Taylor cho lnlà một chuỗi xen kẽ, 0 < x - ln(1 + x) < x2/2, sai số tương đối phát sinh khi tính gần đúng ln(1 + . Nếu 1 ở đâu. đối với một số Là Dễ dàng kiểm tra xem nếu với. Một ví dụ thú vị về phân tích lỗi sử dụng công thức , , và xảy ra trong công thức bậc hai. Phần , đã giải thích cách viết lại phương trình sẽ loại bỏ khả năng hủy bỏ gây ra bởi phép toán ±. Nhưng có một khả năng triệt tiêu khác có thể xảy ra khi tính toán d = b2 - 4ac. Điều này không thể được loại bỏ bằng cách sắp xếp lại công thức đơn giản. Nói một cách đại khái, khi b2 Nếu b2 Bằng chứng. Viết (b sự bất bình đẳng chỉ ra rằng ,ở đâu ,vì vậy lỗi tuyệt đối ina là về. Vì Cuối cùng, chúng ta chuyển sang chứng minh Định lý 6. Nó dựa trên thực tế sau đây, được chứng minh trong phần Định lý 14Cho 0 < k < p và đặt m =Chứng minh Định lý 6Theo Định lý 14, xh là x được làm tròn thành p - k =số. Nếu không có thực hiện thì chắc chắn xh có thể được biểu diễn bằng các chữ số có nghĩa. Giả sử có một thực hiện. Nếu x = x0. x1. xp - 1 ×Định lý 6 đưa ra cách biểu diễn tích của hai số chính xác đang hoạt động chính xác dưới dạng tổng. Có một công thức đồng hành để biểu thị một tổng chính xác. Nếu. x. Chuyển đổi nhị phân sang thập phânVì độ chính xác đơn có p = 24 và 224 < 108, bạn có thể mong đợi rằng việc chuyển đổi số nhị phân thành 8 chữ số thập phân sẽ đủ để khôi phục số nhị phân ban đầu. Tuy nhiên, đây không phải là trường hợp Định lý 15Khi một số nhị phân có độ chính xác đơn của IEEE được chuyển đổi thành số thập phân có tám chữ số gần nhất, không phải lúc nào cũng có thể khôi phục duy nhất số nhị phân từ số thập phân. Tuy nhiên, nếu chín chữ số thập phân được sử dụng, thì việc chuyển đổi số thập phân thành số nhị phân gần nhất sẽ phục hồi số dấu phẩy động ban đầuBằng chứngCác số nhị phân có độ chính xác đơn nằm trong nửa khoảng mở [103, 210) = [1000, 1024) có 10 bit ở bên trái điểm nhị phân và 14 bit ở bên phải điểm nhị phân. Như vậy có (210 - 103)214 = 393.216 số nhị phân khác nhau trong khoảng đó. Nếu số thập phân được biểu diễn bằng 8 chữ số thì có (210 - 103)104 = 240.000 số thập phân trong cùng một khoảng. Không có cách nào mà 240.000 số thập phân có thể đại diện cho 393.216 số nhị phân khác nhau. Vì vậy, 8 chữ số thập phân không đủ để biểu thị duy nhất từng số nhị phân chính xác duy nhất. Để chỉ ra rằng 9 chữ số là đủ, nó đủ để chỉ ra rằng khoảng cách giữa các số nhị phân luôn lớn hơn khoảng cách giữa các số thập phân. Điều này sẽ đảm bảo rằng với mỗi số thập phân N, khoảng[N -ulp, N +ulp]chứa nhiều nhất một số nhị phân. Do đó, mỗi số nhị phân làm tròn thành một số thập phân duy nhất, đến lượt nó làm tròn thành một số nhị phân duy nhất. Để chỉ ra rằng khoảng cách giữa các số nhị phân luôn lớn hơn khoảng cách giữa các số thập phân, hãy xem xét một khoảng [10n, 10n + 1]. Trong khoảng này, khoảng cách giữa các số thập phân liên tiếp là 10(n + 1) - 9. Trên [10n, 2m], trong đó m là số nguyên nhỏ nhất sao cho 10n < 2m, khoảng cách giữa các số nhị phân là 2m - 24 và khoảng cách càng lớn dần trong khoảng. Do đó, chỉ cần kiểm tra rằng 10(n + 1) - 9 < 2m - 24 là đủ. Nhưng thực tế, vì 10n < 2m nên 10(n + 1) - 9 = 10n10-8 < 2m10-8 < 2m2-24. z Đối số tương tự được áp dụng cho độ chính xác kép cho thấy cần có 17 chữ số thập phân để khôi phục số có độ chính xác kép Chuyển đổi nhị phân-thập phân cũng cung cấp một ví dụ khác về việc sử dụng cờ. Nhớ lại từ phần , rằng để khôi phục số nhị phân từ phần mở rộng thập phân của nó, chuyển đổi thập phân sang nhị phân phải được tính toán chính xác. Việc chuyển đổi đó được thực hiện bằng cách nhân các đại lượng N với 10. P. (cả hai đều chính xác nếu p <13) ở độ chính xác mở rộng đơn và sau đó làm tròn số này thành độ chính xác đơn (hoặc chia nếu p <0; cả hai trường hợp đều giống nhau). Tất nhiên việc tính toán N · 10. P. không thể chính xác; . P. ) phải chính xác, trong đó làm tròn từ độ chính xác mở rộng đơn đến độ chính xác đơn. Để biết tại sao nó có thể không chính xác, hãy lấy trường hợp đơn giản là = 10, p = 2 cho đơn lẻ và p = 3 cho mở rộng đơn lẻ. Nếu sản phẩm là 12. 51, thì số này sẽ được làm tròn thành 12. 5 như một phần của thao tác nhân mở rộng đơn lẻ. Làm tròn đến độ chính xác duy nhất sẽ cho 12. Nhưng câu trả lời đó không chính xác, bởi vì làm tròn sản phẩm đến độ chính xác duy nhất sẽ cho 13. Lỗi là do làm tròn hai lần. Bằng cách sử dụng cờ IEEE, có thể tránh làm tròn hai lần như sau. Lưu giá trị hiện tại của cờ không chính xác, rồi đặt lại. Đặt chế độ làm tròn thành làm tròn về 0. Sau đó thực hiện phép nhân N · 10. P. Lưu trữ giá trị mới của cờ không chính xác trong n = n/2139 và khôi phục chế độ làm tròn và cờ không chính xác. Nếu n = n/2139 là 0 thì N · 10. P. là chính xác, nên tròn(N · 10. P. ) sẽ chính xác đến bit cuối cùng. Nếu n = n/2139 là 1, thì một số chữ số đã bị cắt bớt, vì làm tròn số 0 luôn bị cắt bớt. Ý nghĩa của sản phẩm sẽ giống như 1. b1. b22b23. b31. Lỗi làm tròn kép có thể xảy ra nếu b23. b31 = 10. 0. Một cách đơn giản để giải thích cho cả hai trường hợp là thực hiện một n = n/2142 hợp lý của n = n/2139 với b31. Sau đó làm tròn (N · 10. P. ) sẽ được tính toán chính xác trong mọi trường hợp Lỗi trong tổng kếtPhần , đã đề cập đến vấn đề tính toán chính xác các khoản tiền rất dài. Cách tiếp cận đơn giản nhất để cải thiện độ chính xác là tăng gấp đôi độ chính xác. Để có ước tính sơ bộ về việc nhân đôi độ chính xác sẽ cải thiện độ chính xác của một phép cộng bao nhiêu, hãy đặt s1 = x1, s2 = s1 Đẳng thức đầu tiên của cho thấy rằng giá trị được tính toán của of giống như thể một phép tính tổng chính xác được thực hiện trên các giá trị bị xáo trộn của xj. Số hạng đầu x1 bị nhiễu bởi n Để có lời giải thích trực quan về lý do tại sao công thức tính tổng Kahan hoạt động, hãy xem sơ đồ sau của quy trình Mỗi khi thêm một lệnh tổng, sẽ có một hệ số hiệu chỉnh C sẽ được áp dụng cho vòng lặp tiếp theo. Vì vậy, trước tiên hãy trừ hiệu chỉnh C được tính trong vòng lặp trước từ Xj, cho tổng kết quả đã sửa Y. Sau đó thêm summand này vào tổng đang chạy S. Các bit bậc thấp của Y (cụ thể là Yl) bị mất trong tổng. Tiếp theo tính toán các bit bậc cao của Y bằng cách tính toán T - S. Khi Y bị trừ đi, các bit bậc thấp của Y sẽ được phục hồi. Đây là những bit đã bị mất trong tổng đầu tiên trong sơ đồ. Chúng trở thành hệ số điều chỉnh cho vòng lặp tiếp theo. Một chứng minh chính thức của Định lý 8, lấy từ Knuth [1981] trang 572, xuất hiện trong phần. " Tóm lượcKhông có gì lạ khi các nhà thiết kế hệ thống máy tính bỏ qua các phần của hệ thống liên quan đến dấu chấm động. Điều này có lẽ là do thực tế là dấu phẩy động được chú ý rất ít (nếu có) trong chương trình khoa học máy tính. Đến lượt nó, điều này đã gây ra niềm tin rõ ràng phổ biến rằng dấu phẩy động không phải là một chủ đề có thể định lượng được, và do đó, không cần phải lo lắng về các chi tiết của phần cứng và phần mềm xử lý nó Bài báo này đã chứng minh rằng có thể lập luận chặt chẽ về dấu phẩy động. Ví dụ: các thuật toán dấu phẩy động liên quan đến hủy bỏ có thể được chứng minh là có lỗi tương đối nhỏ nếu phần cứng bên dưới có chữ số bảo vệ và có một thuật toán hiệu quả để chuyển đổi nhị phân-thập phân có thể được chứng minh là không thể đảo ngược, với điều kiện là độ chính xác mở rộng là . Nhiệm vụ xây dựng phần mềm dấu phẩy động đáng tin cậy được thực hiện dễ dàng hơn nhiều khi hệ thống máy tính cơ bản hỗ trợ dấu phẩy động. Ngoài hai ví dụ vừa được đề cập (số bảo vệ và độ chính xác mở rộng), phần của bài báo này có các ví dụ khác nhau, từ thiết kế tập lệnh đến tối ưu hóa trình biên dịch minh họa cách hỗ trợ dấu phẩy động tốt hơn. Sự chấp nhận ngày càng tăng của tiêu chuẩn dấu chấm động IEEE có nghĩa là các mã sử dụng các tính năng của tiêu chuẩn ngày càng trở nên di động hơn. Phần , đã đưa ra nhiều ví dụ minh họa cách sử dụng các tính năng của tiêu chuẩn IEEE để viết mã dấu phẩy động thực tế Sự nhìn nhậnBài viết này được lấy cảm hứng từ một khóa học do W. Kahan tại Sun Microsystems từ tháng 5 đến tháng 7 năm 1988, được tổ chức rất khéo léo bởi David Hough của Sun. Hy vọng của tôi là cho phép những người khác tìm hiểu về sự tương tác của hệ thống máy tính và dấu chấm động mà không cần phải thức dậy kịp thời để tham dự 8. 00 một. m. bài giảng. Xin cảm ơn Kahan và nhiều đồng nghiệp của tôi tại Xerox PARC (đặc biệt là John Gilbert) đã đọc bản thảo của bài báo này và đưa ra nhiều nhận xét hữu ích. Nhận xét từ Paul Hilfinger và một trọng tài ẩn danh cũng giúp cải thiện phần trình bày Người giới thiệuỒ, Alfred V. , Sethi, R. , và Ullman J. Đ. 1986. Trình biên dịch. Nguyên tắc, Kỹ thuật và Công cụ, Addison-Wesley, Reading, MA ANSI 1978. Ngôn ngữ lập trình tiêu chuẩn quốc gia Mỹ FORTRAN, tiêu chuẩn ANSI X3. 9-1978, Viện Tiêu chuẩn Quốc gia Mỹ, New York, NY Barnett, David 1987. Môi trường dấu phẩy động di động, bản thảo chưa xuất bản Nâu, W. S. 1981. Một mô hình tính toán dấu phẩy động đơn giản nhưng thực tế, ACM Trans. về môn Toán. Phần mềm 7(4), trang. 445-480 Cody, W. J et. tất cả. 1984. Tiêu chuẩn không phụ thuộc vào cơ số và độ dài từ được đề xuất cho Số học dấu phẩy động, IEEE Micro 4(4), trang. 86-100 Cody, W. J. 1988. Tiêu chuẩn dấu phẩy động -- Lý thuyết và thực hành, trong "Độ tin cậy trong máy tính. vai trò của các phương pháp khoảng thời gian trong tính toán khoa học", ed. bởi Ramon E. Moore, trang. 99-107, Nhà xuất bản học thuật, Boston, MA Coonen, Jerome 1984. Đóng góp cho một tiêu chuẩn được đề xuất cho số học dấu phẩy động nhị phân, Luận án tiến sĩ, Đại học. California,Berkeley Dekker, T. J. 1971. Một kỹ thuật dấu phẩy động để mở rộng độ chính xác có sẵn, số. môn Toán. 18(3), trang. 224-242 Demmel, James 1984. Underflow và Độ tin cậy của Phần mềm Số, SIAM J. Khoa học. thống kê. máy tính. 5(4), trang. 887-919 Farnum, Charles 1988. Hỗ trợ trình biên dịch cho tính toán dấu phẩy động, Thực hành và trải nghiệm phần mềm, 18(7), trang. 701-709 Forsythe, G. e. và Moler, C. b. 1967. Giải pháp máy tính của hệ thống đại số tuyến tính, Prentice-Hall, Englewood Cliffs, NJ Goldberg, tôi. Bennett 1967. 27 bit không đủ cho độ chính xác 8 chữ số, giao tiếp. của ACM. 10(2), trang 105-106 Goldberg, David 1990. Số học máy tính, trong "Kiến trúc máy tính. Một cách tiếp cận định lượng", bởi David Patterson và John L. Hennessy, Phụ lục A, Morgan Kaufmann, Los Altos, CA Golub, gen H. và Vân Loan, Charles F. 1989. Tính toán ma trận, tái bản lần thứ 2, Nhà xuất bản Đại học Johns Hopkins, Baltimore Maryland Graham, Ronald L. , Knuth, Donald E. và Patashnik, Oren. 1989. Toán cụ thể, Addison-Wesley, Reading, MA, p. 162 Hewlett Packard 1982. Sổ tay chức năng nâng cao HP-15C IEEE 1987. Tiêu chuẩn IEEE 754-1985 cho Số học dấu phẩy động nhị phân, IEEE, (1985). In lại trong SIGPLAN 22(2) trang. 9-25 Kahan, W. 1972. Khảo sát về phân tích lỗi, trong Xử lý thông tin 71, Tập 2, trang. 1214 - 1239 (Ljubljana, Nam Tư), Bắc Hà Lan, Amsterdam Kahan, W. 1986. Tính diện tích và góc của tam giác hình kim, bản thảo chưa xuất bản Kahan, W. 1987. Các phép cắt nhánh cho các hàm cơ bản phức tạp, trong "The State of the Art in Numerical Analysis", ed. bởi M. J. D. Powell và A. Iserles (Đại học Birmingham, Anh), Chương 7, Nhà xuất bản Đại học Oxford, New York Kahan, W. 1988. Các bài giảng chưa được công bố tại Sun Microsystems, Mountain View, CA Kahan, W. và Coonen, Jerome T. 1982. Tính trực giao gần của cú pháp, ngữ nghĩa và chẩn đoán trong môi trường lập trình số, trong "Mối quan hệ giữa tính toán số và ngôn ngữ lập trình", biên tập. bởi J. k. Reid, trang. 103-115, Bắc Hà Lan, Amsterdam Kahan, W. và LeBlanc, E. 1985. Sự bất thường trong Gói Acrith của IBM, Proc. Hội nghị chuyên đề IEEE lần thứ 7 về số học máy tính (Urbana, Illinois), trang. 322-331 Kernighan, Brian W. và Ritchie, Dennis M. 1978. Ngôn ngữ lập trình C, Prentice-Hall, Englewood Cliffs, NJ Kirchner, R. và Kulisch, U. 1987. Số học cho Bộ xử lý Vector, Proc. Hội nghị chuyên đề IEEE lần thứ 8 về số học máy tính (Como, Ý), trang. 256-269 Knuth, Donald E. , 1981. Nghệ thuật lập trình máy tính, Tập II, Phiên bản thứ hai, Addison-Wesley, Reading, MA Kulisch, U. W. , và Miranker, W. L. 1986. Số học của máy tính kỹ thuật số. Một cách tiếp cận mới, Đánh giá SIAM 28(1), trang 1-36 Matula, D. W. và Kornerup, P. 1985. Số học hợp lý chính xác hữu hạn. Hệ thống số gạch chéo, IEEE Trans. trên may tinh. C-34(1), trang 3-18 Nelson, G. 1991. Lập trình hệ thống với Modula-3, Prentice-Hall, Englewood Cliffs, NJ Reiser, John F. và Knuth, Donald E. 1975. Evading the Drift in Floating-point Addition, Xử lý thông tin Letters 3(3), trang 84-87 Sterbenz, Miếng vá. 1974. Tính toán dấu chấm động, Prentice-Hall, Englewood Cliffs, NJ Swartzlander, Bá tước E. và Alexopoulos, Aristides G. 1975. Hệ thống số ký hiệu/logarit, IEEE Trans. máy tính. C-24(12), trang. 1238-1242 Walther, J. S. , 1971. Một thuật toán thống nhất cho các chức năng cơ bản, Kỷ yếu của AFIP Spring Joint Computer Conf. 38, trang. 379-385 Định lý 14 và Định lý 8Phần này chứa hai trong số các bằng chứng kỹ thuật đã bị bỏ qua trong văn bản Định lý 14Cho 0 < k < p và đặt m =Bằng chứngChứng minh chia thành hai trường hợp, tùy thuộc vào việc tính toán mx =n = n/2144aa. aabb. bb ______2145trong đó x được chia thành hai phần. Các chữ số k bậc thấp được đánh dấu n = n/2132 và các chữ số p - k bậc cao được đánh dấu if (n==0) return u3. Để tính m n = n/2132) vì vậy(32) m n = n/2150 làm tròn thành a + 1, r = 0 nếu ngược lại. The value of r is 1 if n = n/2149 is greater thanand 0 otherwise. More precisely(33) r = 1 if n = n/2150 rounds to a + 1, r = 0 otherwise. Tính tiếp theo m n = n/2151 là chữ số có được từ việc thêm n = n/2152 vào chữ số có thứ tự thấp nhất n = n/2132. n = n/2154bb. bb n = n/2155Nếu n = n/2149 n = n/2149 >then r = 1, and 1 is subtracted from n = n/2151 because of the borrow, so the result is n = n/2149 =. Nếu r = 0 thì n = n/2151 là số chẵn, n = n/2162 là số lẻ và chênh lệch được làm tròn lên, cho kết quả n = n/2151 là số lẻ, n = n/2162 là số chẵn, sự khác biệt được làm tròn xuống, do đó, một lần nữa sự khác biệt là Kết hợp các phương trình và cho (m n = n/2165 bb...bb ______2166Quy tắc tính r, phương trình (33), cũng giống như quy tắc làm tròn n = n/2167 n = n/2168 thành p - k. Do đó, tính toán mx - (mx - x) ở độ chính xác số học dấu phẩy động chính xác bằng cách làm tròn x đến p - k vị trí, trong trường hợp khi x + n = n/2144aa. aabb. bb n = n/2170Như vậy, m n = n/2171 w n = n/2172Làm tròn cho (m n = n/2149 > or if n = n/2149 =and b0 = 1. Finally,(m = x - x mod( Và một lần nữa, r = 1 chính xác khi làm tròn n = n/2175 thành p - k vị trí liên quan đến việc làm tròn. Như vậy Định lý 14 được chứng minh trong mọi trường hợp. z Định lý 8 (Công thức tổng Kahan)Giả sử nó được tính toán bằng thuật toán sau_______02n = n/208_______04 n = n/25 n = n/26 n = n/27 n = n/28 n = n/29 Sau đó, tổng S được tính toán bằng S = Bằng chứngĐầu tiên hãy nhớ lại ước tính sai số cho công thức đơn giảnS1 = + To get the general formula for Sk and Ck, expand the definitions of sk and ck, ignoring all terms involving xi with i > 1 to getsk = (sk - 1 + yk)(1 + S2 = 1 + and in general it is easy to check by induction thatCk = Sk = 1 + Cuối cùng, điều mong muốn là hệ số của x1 trong sk. Để có giá trị này, hãy đặt xn + 1 = 0, đặt tất cả các chữ cái Hy Lạp có chỉ số dưới của n + 1 bằng 0 và tính sn + 1. Khi đó sn + 1 = sn - cn và hệ số của x1 trong sn nhỏ hơn hệ số trong sn + 1, tức là Sn = 1 + Sự khác biệt giữa các triển khai IEEE 754Lưu ý - Phần này không phải là một phần của bài báo đã xuất bản. Nó đã được thêm vào để làm rõ một số điểm nhất định và sửa chữa những hiểu lầm có thể xảy ra về tiêu chuẩn IEEE mà người đọc có thể suy ra từ bài báo. Tài liệu này không phải do David Goldberg viết, nhưng nó xuất hiện ở đây với sự cho phép của ông Bài báo trước đã chỉ ra rằng số học dấu phẩy động phải được triển khai cẩn thận, vì các lập trình viên có thể phụ thuộc vào các thuộc tính của nó để đảm bảo tính đúng đắn và chính xác của chương trình của họ. Đặc biệt, tiêu chuẩn IEEE yêu cầu triển khai cẩn thận và chỉ có thể viết các chương trình hữu ích hoạt động chính xác và mang lại kết quả chính xác trên các hệ thống tuân thủ tiêu chuẩn. Người đọc có thể muốn kết luận rằng các chương trình như vậy sẽ có thể di chuyển được đến tất cả các hệ thống của IEEE. Thật vậy, phần mềm di động sẽ dễ viết hơn nếu nhận xét "Khi một chương trình được di chuyển giữa hai máy và cả hai đều hỗ trợ số học IEEE, thì nếu bất kỳ kết quả trung gian nào khác đi, thì đó phải là do lỗi phần mềm, không phải do sự khác biệt về số học," là Thật không may, tiêu chuẩn IEEE không đảm bảo rằng cùng một chương trình sẽ mang lại kết quả giống hệt nhau trên tất cả các hệ thống phù hợp. Hầu hết các chương trình sẽ thực sự tạo ra các kết quả khác nhau trên các hệ thống khác nhau vì nhiều lý do. Đầu tiên, hầu hết các chương trình liên quan đến việc chuyển đổi số giữa định dạng thập phân và nhị phân và tiêu chuẩn IEEE không chỉ định đầy đủ độ chính xác mà các chuyển đổi đó phải được thực hiện. Mặt khác, nhiều chương trình sử dụng các chức năng cơ bản do thư viện hệ thống cung cấp và tiêu chuẩn hoàn toàn không chỉ định các chức năng này. Tất nhiên, hầu hết các lập trình viên đều biết rằng các tính năng này nằm ngoài phạm vi của tiêu chuẩn IEEE. Nhiều lập trình viên có thể không nhận ra rằng ngay cả một chương trình chỉ sử dụng các định dạng số và hoạt động theo tiêu chuẩn IEEE có thể tính toán các kết quả khác nhau trên các hệ thống khác nhau. Trên thực tế, các tác giả của tiêu chuẩn dự định cho phép các triển khai khác nhau thu được các kết quả khác nhau. Ý định của họ thể hiện rõ trong định nghĩa về thuật ngữ đích trong tiêu chuẩn IEEE 754. "Đích có thể được chỉ định rõ ràng bởi người dùng hoặc được cung cấp ngầm bởi hệ thống (ví dụ: kết quả trung gian trong các biểu thức con hoặc đối số cho các thủ tục). Một số ngôn ngữ đặt kết quả tính toán trung gian ở đích ngoài tầm kiểm soát của người dùng. Tuy nhiên, tiêu chuẩn này xác định kết quả của một hoạt động theo định dạng của đích đó và các giá trị của toán hạng. " (IEEE 754-1985, tr. 7) Nói cách khác, tiêu chuẩn IEEE yêu cầu mỗi kết quả phải được làm tròn chính xác theo độ chính xác của đích mà nó sẽ được đặt vào, nhưng tiêu chuẩn không yêu cầu độ chính xác của đích đó được xác định bởi chương trình của người dùng. Do đó, các hệ thống khác nhau có thể đưa kết quả của chúng đến các đích với độ chính xác khác nhau, khiến cùng một chương trình tạo ra các kết quả khác nhau (đôi khi rất đáng kể), mặc dù các hệ thống đó đều tuân theo tiêu chuẩn Một số ví dụ trong bài báo trước phụ thuộc vào một số kiến thức về cách làm tròn số học dấu phẩy động. Để dựa vào các ví dụ như thế này, một lập trình viên phải có khả năng dự đoán cách một chương trình sẽ được diễn giải và đặc biệt, trên hệ thống IEEE, độ chính xác của đích đến của mỗi phép toán số học có thể là bao nhiêu. Than ôi, lỗ hổng trong định nghĩa đích của tiêu chuẩn IEEE làm suy yếu khả năng của lập trình viên để biết chương trình sẽ được diễn giải như thế nào. Do đó, một số ví dụ nêu trên, khi được triển khai dưới dạng các chương trình di động rõ ràng bằng ngôn ngữ cấp cao, có thể không hoạt động chính xác trên các hệ thống IEEE thường cung cấp kết quả tới đích với độ chính xác khác với mong đợi của lập trình viên. Các ví dụ khác có thể hoạt động, nhưng việc chứng minh rằng chúng hoạt động có thể nằm ngoài khả năng của một lập trình viên bình thường Trong phần này, chúng tôi phân loại các triển khai số học IEEE 754 hiện có dựa trên độ chính xác của các định dạng đích mà chúng thường sử dụng. Sau đó, chúng tôi xem xét một số ví dụ từ bài báo để chỉ ra rằng việc cung cấp kết quả với độ chính xác rộng hơn mong đợi của chương trình có thể khiến chương trình tính toán kết quả sai mặc dù nó có thể đúng khi sử dụng độ chính xác dự kiến. Chúng tôi cũng xem lại một trong những bằng chứng trong bài báo để minh họa nỗ lực trí tuệ cần thiết để đối phó với độ chính xác ngoài dự kiến ngay cả khi nó không làm mất hiệu lực chương trình của chúng tôi. Những ví dụ này cho thấy rằng bất chấp tất cả những gì tiêu chuẩn IEEE quy định, sự khác biệt mà tiêu chuẩn này cho phép giữa các triển khai khác nhau có thể ngăn chúng ta viết phần mềm số hiệu quả, di động có hành vi mà chúng ta có thể dự đoán chính xác. Sau đó, để phát triển phần mềm như vậy, trước tiên chúng ta phải tạo ra các ngôn ngữ lập trình và môi trường hạn chế tính biến đổi mà tiêu chuẩn IEEE cho phép và cho phép các lập trình viên thể hiện ngữ nghĩa dấu phẩy động mà chương trình của họ phụ thuộc vào. Triển khai IEEE 754 hiện tạiViệc triển khai số học IEEE 754 hiện tại có thể được chia thành hai nhóm được phân biệt theo mức độ chúng hỗ trợ các định dạng dấu phẩy động khác nhau trong phần cứng. Các hệ thống dựa trên mở rộng, được minh họa bởi dòng bộ xử lý Intel x86, cung cấp hỗ trợ đầy đủ cho định dạng độ chính xác kép mở rộng nhưng chỉ hỗ trợ một phần cho độ chính xác đơn và kép. chúng cung cấp các hướng dẫn để tải hoặc lưu trữ dữ liệu ở độ chính xác đơn và kép, chuyển đổi dữ liệu nhanh chóng sang hoặc từ định dạng kép mở rộng và chúng cung cấp các chế độ đặc biệt (không phải mặc định) trong đó kết quả của các phép toán số học được làm tròn thành đơn . (Bộ xử lý sê-ri Motorola 68000 làm tròn kết quả cho cả độ chính xác và phạm vi của định dạng đơn hoặc kép trong các chế độ này. Intel x86 và bộ xử lý tương thích làm tròn kết quả thành độ chính xác của định dạng đơn hoặc kép nhưng vẫn giữ nguyên phạm vi như định dạng kép mở rộng. ) Các hệ thống đơn/kép, bao gồm hầu hết các bộ xử lý RISC, cung cấp hỗ trợ đầy đủ cho các định dạng chính xác đơn và kép nhưng không hỗ trợ định dạng chính xác kép mở rộng tuân thủ IEEE. (Kiến trúc IBM POWER chỉ cung cấp hỗ trợ một phần cho độ chính xác đơn, nhưng với mục đích của phần này, chúng tôi phân loại nó là hệ thống đơn/kép. ) Để xem cách tính toán có thể hoạt động khác nhau trên hệ thống dựa trên mở rộng so với trên hệ thống đơn/kép, hãy xem xét phiên bản C của ví dụ từ phần n = n/230 n = n/231 n = n/232 n = n/233 n = n/234 n = n/235 n = n/29 Đây là hằng số 3. 0 và 7. 0 được hiểu là số dấu phẩy động có độ chính xác kép và biểu thức 3. 0/7. 0 kế thừa kiểu dữ liệu n = n/2176. Trên một hệ thống đơn/kép, biểu thức sẽ được đánh giá với độ chính xác kép vì đó là định dạng hiệu quả nhất để sử dụng. Do đó, n = n/2053 sẽ được gán giá trị 3. 0/7. 0 được làm tròn chính xác để tăng gấp đôi độ chính xác. Trong dòng tiếp theo, biểu thức 3. 0/7. 0 một lần nữa sẽ được đánh giá với độ chính xác kép và tất nhiên kết quả sẽ bằng với giá trị vừa được gán cho n = n/2053, vì vậy chương trình sẽ in "Bằng" như mong đợi Trên một hệ thống dựa trên mở rộng, mặc dù biểu thức 3. 0/7. 0 có loại n = n/2176, thương số sẽ được tính trong một thanh ghi ở định dạng kép mở rộng và do đó ở chế độ mặc định, nó sẽ được làm tròn thành độ chính xác kép mở rộng. Tuy nhiên, khi giá trị kết quả được gán cho biến n = n/2053, thì nó có thể được lưu trữ trong bộ nhớ và vì n = n/2053 được khai báo là n = n/2176, nên giá trị sẽ được làm tròn thành độ chính xác gấp đôi. Trong dòng tiếp theo, biểu thức 3. 0/7. 0 một lần nữa có thể được đánh giá ở độ chính xác mở rộng mang lại kết quả khác với giá trị độ chính xác kép được lưu trữ trong n = n/2053, khiến chương trình in ra "Không bằng". Tất nhiên, các kết quả khác cũng có thể xảy ra. trình biên dịch có thể quyết định lưu trữ và do đó làm tròn giá trị của biểu thức 3. 0/7. 0 ở dòng thứ hai trước khi so sánh nó với n = n/2053 hoặc nó có thể giữ n = n/2053 trong sổ đăng ký với độ chính xác mở rộng mà không cần lưu trữ. Trình biên dịch tối ưu hóa có thể đánh giá biểu thức 3. 0/7. 0 tại thời điểm biên dịch, có lẽ ở độ chính xác kép hoặc có thể ở độ chính xác kép mở rộng. (Với một trình biên dịch x86, chương trình sẽ in "Bằng" khi được biên dịch với tối ưu hóa và "Không bằng" khi được biên dịch để gỡ lỗi. ) Cuối cùng, một số trình biên dịch cho các hệ thống dựa trên mở rộng tự động thay đổi chế độ làm tròn độ chính xác để khiến các hoạt động tạo ra kết quả trong các thanh ghi để làm tròn các kết quả đó thành độ chính xác đơn hoặc kép, mặc dù có thể với phạm vi rộng hơn. Do đó, trên các hệ thống này, chúng tôi không thể dự đoán hành vi của chương trình chỉ bằng cách đọc mã nguồn của nó và áp dụng hiểu biết cơ bản về số học IEEE 754. Chúng tôi cũng không thể buộc tội phần cứng hoặc trình biên dịch không cung cấp môi trường tuân thủ IEEE 754; Cạm bẫy trong tính toán trên các hệ thống dựa trên mở rộngSự khôn ngoan thông thường cho rằng các hệ thống dựa trên mở rộng phải tạo ra kết quả ít nhất là chính xác, nếu không muốn nói là chính xác hơn kết quả được cung cấp trên hệ thống đơn/kép, vì hệ thống trước luôn cung cấp độ chính xác ít nhất bằng và thường cao hơn hệ thống sau. Các ví dụ tầm thường như chương trình C ở trên cũng như các chương trình phức tạp hơn dựa trên các ví dụ được thảo luận bên dưới cho thấy sự khôn ngoan này tốt nhất là ngây thơ. một số chương trình rõ ràng là di động, thực sự là di động trên các hệ thống đơn/kép, cung cấp kết quả không chính xác trên các hệ thống dựa trên mở rộng chính xác do trình biên dịch và phần cứng đôi khi cung cấp độ chính xác cao hơn mong đợi của chương trình Các ngôn ngữ lập trình hiện tại khiến chương trình khó xác định độ chính xác mà nó mong đợi. Như phần này đã đề cập, nhiều ngôn ngữ lập trình không chỉ định rằng mỗi lần xuất hiện của một biểu thức như n = n/2035 trong cùng một ngữ cảnh sẽ đánh giá cùng một giá trị. Một số ngôn ngữ, chẳng hạn như Ada, bị ảnh hưởng về mặt này bởi các biến thể giữa các số học khác nhau trước khi có tiêu chuẩn IEEE. Gần đây hơn, các ngôn ngữ như ANSI C đã bị ảnh hưởng bởi các hệ thống dựa trên mở rộng phù hợp với tiêu chuẩn. Trên thực tế, tiêu chuẩn ANSI C rõ ràng cho phép trình biên dịch đánh giá một biểu thức dấu phẩy động với độ chính xác rộng hơn mức thường được kết hợp với loại của nó. Do đó, giá trị của biểu thức n = n/2035 có thể khác nhau tùy thuộc vào nhiều yếu tố. liệu biểu thức được gán ngay cho một biến hay xuất hiện dưới dạng biểu thức con trong biểu thức lớn hơn; Các tiêu chuẩn ngôn ngữ không hoàn toàn đổ lỗi cho sự thất thường của việc đánh giá biểu thức. Các hệ thống dựa trên mở rộng chạy hiệu quả nhất khi các biểu thức được đánh giá trong các thanh ghi độ chính xác mở rộng bất cứ khi nào có thể, tuy nhiên các giá trị phải được lưu trữ được lưu trữ ở độ chính xác hẹp nhất được yêu cầu. Hạn chế một ngôn ngữ để yêu cầu đánh giá n = n/2035 với cùng một giá trị ở mọi nơi sẽ áp dụng hình phạt hiệu suất đối với các hệ thống đó. Thật không may, việc cho phép các hệ thống đó đánh giá n = n/2035 khác nhau trong các ngữ cảnh tương đương về mặt cú pháp sẽ tự áp đặt hình phạt đối với các lập trình viên của phần mềm số chính xác bằng cách ngăn họ dựa vào cú pháp của chương trình để thể hiện ngữ nghĩa dự định của họ Các chương trình thực tế có phụ thuộc vào giả định rằng một biểu thức đã cho luôn đánh giá cùng một giá trị không? _______537____538____539____540n = n/241 n = n/242____543 n = n/244 n = n/2190 n = n/2044 n = n/2006, is evaluated in extended precision. In that case, if n = n/2006 is small but not quite small enough that n = n/2190 n = n/2044 n = n/2006 rounds to n = n/2190 in single precision, then the value returned by n = n/203 can exceed the correct value by nearly as much as n = n/2006, and again the relative error can approach one. For a concrete example, take n = n/2006 to be 2-24 + 2-47, so n = n/2006 is the smallest single precision number such that n = n/2190 n = n/2044 n = n/2006 rounds up to the next larger number, 1 + 2-23. Then n = n/220 n = n/2044 n = n/222 is approximately 2-23. Because the denominator in the expression in the sixth line is evaluated in extended precision, it is computed exactly and delivers n = n/2006, so n = n/203 returns approximately 2-23, which is nearly twice as large as the exact value. (This actually happens with at least one compiler. When the preceding code is compiled by the Sun WorkShop Compilers 4.2.1 Fortran 77 compiler for x86 systems using the n = n/225 optimization flag, the generated code computes n = n/2190 n = n/2044 n = n/2006 exactly as described. As a result, the function delivers zero for n = n/229 and n = n/230 for n = n/231.) Để thuật toán của Định lý 4 hoạt động chính xác, biểu thức n = n/2190 n = n/2044 n = n/2006 phải được đánh giá theo cùng một cách mỗi khi nó xuất hiện; . Tất nhiên, vì n = n/238 là một hàm nội tại chung trong Fortran, trình biên dịch có thể đánh giá biểu thức n = n/2190 n = n/2044 n = n/2006 với độ chính xác mở rộng xuyên suốt, tính logarit của nó với cùng độ chính xác, nhưng rõ ràng chúng ta không thể cho rằng trình biên dịch sẽ làm như vậy. (Người ta cũng có thể tưởng tượng một ví dụ tương tự liên quan đến hàm do người dùng định nghĩa. Trong trường hợp đó, một trình biên dịch vẫn có thể giữ đối số ở độ chính xác mở rộng mặc dù hàm trả về một kết quả chính xác duy nhất, nhưng rất ít nếu có bất kỳ trình biên dịch Fortran hiện có nào làm được điều này. ) Do đó, chúng tôi có thể cố gắng đảm bảo rằng n = n/2190 n = n/2044 n = n/2006 được đánh giá một cách nhất quán bằng cách gán nó cho một biến. Thật không may, nếu chúng ta khai báo biến n = n/245 đó, thì chúng ta vẫn có thể bị trình biên dịch làm hỏng khi thay thế một giá trị được lưu trong sổ đăng ký với độ chính xác mở rộng cho một lần xuất hiện của biến và một giá trị được lưu trong bộ nhớ với độ chính xác duy nhất cho một lần xuất hiện khác. Thay vào đó, chúng ta cần khai báo biến có kiểu tương ứng với định dạng chính xác mở rộng. FORTRAN 77 tiêu chuẩn không cung cấp cách để thực hiện việc này và trong khi Fortran 95 cung cấp cơ chế n = n/246 để mô tả các định dạng khác nhau, nó không yêu cầu rõ ràng việc triển khai đánh giá các biểu thức với độ chính xác mở rộng để cho phép các biến được khai báo với độ chính xác đó. Nói tóm lại, không có cách di động nào để viết chương trình này bằng Fortran tiêu chuẩn được đảm bảo để ngăn biểu thức n = n/2190 n = n/2044 n = n/2006 bị đánh giá theo cách làm mất hiệu lực bằng chứng của chúng tôi Một số thuật toán phụ thuộc vào làm tròn chính xác có thể thất bại với làm tròn kép. Trên thực tế, ngay cả một số thuật toán không yêu cầu làm tròn chính xác và hoạt động chính xác trên nhiều loại máy không tuân thủ IEEE 754 cũng có thể thất bại khi làm tròn hai lần. Hữu ích nhất trong số này là các thuật toán di động để thực hiện nhiều phép tính chính xác mô phỏng được đề cập trong phần. Ví dụ: quy trình được mô tả trong Định lý 6 để tách một số dấu phẩy động thành các phần cao và thấp không hoạt động chính xác trong số học làm tròn kép. cố gắng chia số chính xác kép 252 + 3 × 226 - 1 thành hai phần, mỗi phần có tối đa 26 bit. Khi mỗi thao tác được làm tròn chính xác thành độ chính xác gấp đôi, phần có thứ tự cao là 252 + 227 và phần có thứ tự thấp là 226 - 1, nhưng khi mỗi thao tác được làm tròn trước thành độ chính xác gấp đôi mở rộng rồi đến độ chính xác gấp đôi, quy trình sẽ tạo ra giá trị cao . Số thứ hai chiếm 27 bit, vì vậy bình phương của nó không thể được tính chính xác với độ chính xác gấp đôi. Tất nhiên, vẫn có thể tính bình phương của số này với độ chính xác gấp đôi mở rộng, nhưng thuật toán kết quả sẽ không còn khả dụng cho các hệ thống đơn/kép. Ngoài ra, các bước sau trong thuật toán nhân chính xác bội giả định rằng tất cả các tích từng phần đã được tính toán với độ chính xác kép. Xử lý chính xác hỗn hợp các biến kép kép và mở rộng sẽ khiến việc triển khai trở nên đắt đỏ hơn đáng kể Tương tự như vậy, các thuật toán di động để thêm nhiều số chính xác được biểu thị dưới dạng mảng các số chính xác kép có thể không thành công trong phép tính làm tròn hai lần. Các thuật toán này thường dựa trên một kỹ thuật tương tự như công thức tính tổng của Kahan. Như lời giải thích không chính thức của công thức tính tổng được đưa ra trên gợi ý, nếu n = n/250 và n = n/2042 là các biến dấu phẩy động với. n = n/250. n = n/2042. và chúng tôi tính toán. ________ 545 ________ 546 sau đó trong hầu hết các phép tính, ________ 054 khôi phục chính xác lỗi làm tròn xảy ra trong máy tính ________ 055. Tuy nhiên, kỹ thuật này không hoạt động trong số học làm tròn hai lần. nếu n = n/250 = 252 + 1 và n = n/2042 = 1/2 - 2-54, thì n = n/250 n = n/2044 n = n/2042 làm tròn đầu tiên thành 252 + 3/2 với độ chính xác kép mở rộng và giá trị này làm tròn thành 252 + 2 với độ chính xác kép theo các mối quan hệ . Một lần nữa, ở đây, có thể khôi phục lỗi làm tròn bằng cách tính tổng ở độ chính xác kép mở rộng, nhưng sau đó chương trình sẽ phải thực hiện thêm công việc để giảm kết quả cuối cùng trở lại độ chính xác gấp đôi và việc làm tròn kép có thể ảnh hưởng đến quá trình này, . Vì lý do này, mặc dù các chương trình di động để mô phỏng nhiều phép tính chính xác bằng các phương pháp này hoạt động chính xác và hiệu quả trên nhiều loại máy, nhưng chúng không hoạt động như quảng cáo trên các hệ thống dựa trên mở rộng Cuối cùng, một số thuật toán thoạt nhìn có vẻ phụ thuộc vào việc làm tròn chính xác trên thực tế có thể hoạt động chính xác với phép làm tròn hai lần. Trong những trường hợp này, chi phí đối phó với việc làm tròn hai lần không nằm ở việc triển khai mà nằm ở việc xác minh rằng thuật toán có hoạt động như quảng cáo hay không. Để minh họa, ta chứng minh biến thể sau của Định lý 7 Định lý 7'Nếu m và n là các số nguyên có thể biểu diễn theo độ chính xác kép của IEEE 754 với. m. < 252 và n có dạng đặc biệt n = 2i + 2j, sau đó (mn)Bằng chứngGiả sử không mất mát rằng m > 0. Đặt q = mn. Chia tỷ lệ theo lũy thừa hai, chúng ta có thể xem xét một cài đặt tương đương trong đó 252 Gọi e là lỗi làm tròn trong phép tính q, sao cho q = m/n + e và giá trị được tính q Trong số học làm tròn hai lần, vẫn có thể xảy ra trường hợp q là thương được làm tròn chính xác (mặc dù nó thực sự đã được làm tròn hai lần), vì vậy. e. < 1/2 như trên. Trong trường hợp này, chúng tôi có thể kháng cáo các lập luận của đoạn trước miễn là chúng tôi xem xét thực tế rằng q Cuối cùng, chúng ta còn lại để xem xét các trường hợp trong đó q không phải là thương được làm tròn chính xác do làm tròn hai lần. Trong những trường hợp này, chúng ta có. e. < 1/2 + 2-(d + 1) trong trường hợp xấu nhất, trong đó d là số bit thừa ở định dạng kép mở rộng. (Tất cả các hệ thống dựa trên mở rộng hiện có đều hỗ trợ định dạng kép mở rộng với chính xác 64 bit có nghĩa; đối với định dạng này, d = 64 - 53 = 11. ) Vì làm tròn hai lần chỉ tạo ra kết quả làm tròn không chính xác khi làm tròn thứ hai được xác định theo quy tắc làm tròn về số chẵn, nên q phải là một số nguyên chẵn. Do đó, nếu n có dạng 1/2 + 2-(k + 1), thì ne = nq - m là bội số nguyên của 2-k và ne. < (1/2 + 2-(k + 1))(1/2 + 2-(d + 1)) = 1/4 + 2-(k + 2) + 2-(d + 2) + 2-Nếu k Nếu k Bằng chứng trước cho thấy tích chỉ có thể làm tròn hai lần nếu thương thực hiện, và thậm chí sau đó, nó làm tròn thành kết quả đúng. Bằng chứng cũng chỉ ra rằng việc mở rộng lập luận của chúng ta để bao gồm khả năng làm tròn hai lần có thể là một thách thức ngay cả đối với một chương trình chỉ có hai phép tính dấu phẩy động. Đối với một chương trình phức tạp hơn, có thể không thể tính toán một cách có hệ thống các tác động của phép làm tròn hai lần, chưa kể đến các kết hợp tổng quát hơn của phép tính chính xác kép mở rộng và kép Hỗ trợ ngôn ngữ lập trình cho độ chính xác mở rộngKhông nên dùng các ví dụ trước để gợi ý rằng bản thân độ chính xác mở rộng là có hại. Nhiều chương trình có thể được hưởng lợi từ độ chính xác mở rộng khi lập trình viên có thể sử dụng nó một cách có chọn lọc. Thật không may, các ngôn ngữ lập trình hiện tại không cung cấp đủ phương tiện để lập trình viên chỉ định thời điểm và cách sử dụng độ chính xác mở rộng. Để chỉ ra những hỗ trợ nào là cần thiết, chúng tôi xem xét các cách mà chúng tôi có thể muốn quản lý việc sử dụng độ chính xác mở rộng Trong một chương trình di động sử dụng độ chính xác kép làm độ chính xác làm việc danh nghĩa của nó, có năm cách chúng ta có thể muốn kiểm soát việc sử dụng độ chính xác rộng hơn
Không có ngôn ngữ hiện tại nào hỗ trợ tất cả năm tùy chọn này. Trên thực tế, một số ngôn ngữ đã cố gắng cung cấp cho lập trình viên khả năng kiểm soát việc sử dụng độ chính xác mở rộng. Một ngoại lệ đáng chú ý là ISO/IEC 9899. Ngôn ngữ lập trình 1999 - Tiêu chuẩn C, phiên bản mới nhất của ngôn ngữ C, hiện đang ở giai đoạn chuẩn hóa cuối cùng Tiêu chuẩn C99 cho phép triển khai đánh giá các biểu thức ở định dạng rộng hơn định dạng thường được liên kết với loại của chúng, nhưng tiêu chuẩn C99 khuyến nghị sử dụng một trong ba phương pháp đánh giá biểu thức duy nhất. Ba phương pháp được đề xuất được đặc trưng bởi mức độ mà các biểu thức được "thăng cấp" thành các định dạng rộng hơn và việc triển khai được khuyến khích xác định phương pháp nào nó sử dụng bằng cách xác định macro tiền xử lý n = n/262. nếu n = n/262 là 0, mỗi biểu thức được đánh giá theo định dạng tương ứng với loại của nó; . (Việc triển khai được phép đặt n = n/262 thành -1 để chỉ ra rằng phương pháp đánh giá biểu thức là không thể xác định được. ) Tiêu chuẩn C99 cũng yêu cầu tệp tiêu đề n = n/272 xác định các loại n = n/273 và n = n/274, có độ rộng tối thiểu tương ứng là n = n/265 và n = n/2176 và nhằm khớp với các loại được sử dụng để đánh giá các biểu thức n = n/265 và n = n/2176. Ví dụ: nếu n = n/262 là 2, cả n = n/273 và n = n/274 đều là n = n/270. Cuối cùng, tiêu chuẩn C99 yêu cầu tệp tiêu đề n = n/272 xác định các macro tiền xử lý chỉ định phạm vi và độ chính xác của các định dạng tương ứng với từng loại dấu phẩy động Sự kết hợp các tính năng được yêu cầu hoặc khuyến nghị bởi tiêu chuẩn C99 hỗ trợ một số trong năm tùy chọn được liệt kê ở trên nhưng không phải tất cả. Ví dụ: nếu một triển khai ánh xạ loại n = n/270 sang định dạng kép mở rộng và xác định n = n/262 là 2, thì lập trình viên có thể giả định một cách hợp lý rằng độ chính xác mở rộng tương đối nhanh, vì vậy các chương trình như ví dụ định mức Euclide có thể chỉ cần sử dụng các biến trung gian loại n = n/270 ( . Mặt khác, việc triển khai tương tự phải giữ các biểu thức ẩn danh ở độ chính xác mở rộng ngay cả khi chúng được lưu trữ trong bộ nhớ (e. g. , khi trình biên dịch phải tràn các thanh ghi dấu phẩy động) và nó phải lưu trữ kết quả của các biểu thức được gán cho các biến được khai báo n = n/2176 để chuyển đổi chúng thành độ chính xác kép ngay cả khi chúng có thể được giữ trong các thanh ghi. Do đó, cả loại n = n/2176 và loại n = n/274 đều không thể được biên dịch để tạo mã nhanh nhất trên phần cứng dựa trên mở rộng hiện tại Tương tự như vậy, tiêu chuẩn C99 cung cấp các giải pháp cho một số vấn đề được minh họa bằng các ví dụ trong phần này nhưng không phải tất cả. Phiên bản tiêu chuẩn C99 của hàm n = n/291 được đảm bảo hoạt động chính xác nếu biểu thức n = n/2190 n = n/2044 n = n/2006 được gán cho một biến (thuộc bất kỳ loại nào) và biến đó được sử dụng xuyên suốt. Tuy nhiên, một chương trình tiêu chuẩn C99 di động, hiệu quả để chia một số có độ chính xác kép thành các phần cao và thấp, tuy nhiên, khó khăn hơn. làm cách nào chúng tôi có thể phân tách ở đúng vị trí và tránh làm tròn hai lần nếu chúng tôi không thể đảm bảo rằng các biểu thức n = n/2176 được làm tròn chính xác để đạt được độ chính xác gấp đôi? . Định lý 14 nói rằng chúng ta có thể tách ở bất kỳ vị trí bit nào miễn là chúng ta biết độ chính xác của phép tính cơ bản, và n = n/262 và macro tham số môi trường sẽ cung cấp cho chúng ta thông tin này Đoạn sau đây cho thấy một triển khai có thể n = n/247 n = n/247 n = n/249 n = n/250 n = n/251 n = n/252 n = n/253 n = n/254 n = n/255 n = n/256 n = n/257 n = n/258 n = n/259 n = n/20 n = n/21 Tất nhiên, để tìm ra giải pháp này, lập trình viên phải biết rằng biểu thức n = n/2176 có thể được đánh giá với độ chính xác mở rộng, rằng vấn đề làm tròn hai lần sau đó có thể khiến thuật toán gặp trục trặc và độ chính xác mở rộng đó có thể được sử dụng thay thế theo Định lý 14. Một giải pháp rõ ràng hơn chỉ đơn giản là xác định rằng mỗi biểu thức được làm tròn chính xác để tăng gấp đôi độ chính xác. Trên các hệ thống dựa trên mở rộng, điều này chỉ yêu cầu thay đổi chế độ chính xác làm tròn, nhưng thật không may, tiêu chuẩn C99 không cung cấp cách di động để thực hiện việc này. (Các bản nháp đầu tiên của Chỉnh sửa Dấu phẩy động C, tài liệu làm việc chỉ định các thay đổi được thực hiện đối với tiêu chuẩn C90 để hỗ trợ dấu phẩy động, khuyến nghị rằng việc triển khai trên các hệ thống có chế độ chính xác làm tròn cung cấp các hàm n = n/299 và n = n/2300 để nhận và đặt . Đề xuất này đã bị xóa trước khi các thay đổi được thực hiện đối với tiêu chuẩn C99. ) Thật trùng hợp, cách tiếp cận của tiêu chuẩn C99 để hỗ trợ tính di động giữa các hệ thống có khả năng số học số nguyên khác nhau gợi ý một cách tốt hơn để hỗ trợ các kiến trúc dấu phẩy động khác nhau. Mỗi triển khai tiêu chuẩn C99 cung cấp tệp tiêu đề n = n/272 xác định các loại số nguyên mà triển khai hỗ trợ, được đặt tên theo kích thước và hiệu quả của chúng. ví dụ: n = n/2304 là loại số nguyên có độ rộng chính xác là 32 bit, n = n/2305 là loại số nguyên nhanh nhất có độ rộng tối thiểu 16 bit của triển khai và n = n/2306 là loại số nguyên rộng nhất được hỗ trợ. Người ta có thể tưởng tượng một sơ đồ tương tự cho các loại dấu phẩy động. ví dụ: n = n/2307 có thể đặt tên cho loại dấu phẩy động với độ chính xác chính xác là 53 bit nhưng có thể có phạm vi rộng hơn, n = n/2308 có thể đặt tên cho loại triển khai nhanh nhất với độ chính xác ít nhất là 24 bit và n = n/2309 có thể đặt tên cho loại nhanh hợp lý rộng nhất được hỗ trợ. Các loại nhanh có thể cho phép trình biên dịch trên các hệ thống dựa trên mở rộng tạo mã nhanh nhất có thể chỉ tuân theo ràng buộc rằng giá trị của các biến được đặt tên không được thay đổi do tràn thanh ghi. Các loại chiều rộng chính xác sẽ khiến trình biên dịch trên các hệ thống dựa trên mở rộng đặt chế độ làm tròn độ chính xác thành làm tròn theo độ chính xác đã chỉ định, cho phép phạm vi rộng hơn chịu cùng một ràng buộc. Cuối cùng, n = n/274 có thể đặt tên cho một loại có cả độ chính xác và phạm vi của định dạng kép IEEE 754, cung cấp đánh giá kép nghiêm ngặt. Cùng với các macro tham số môi trường được đặt tên phù hợp, sơ đồ như vậy sẽ sẵn sàng hỗ trợ tất cả năm tùy chọn được mô tả ở trên và cho phép người lập trình chỉ ra ngữ nghĩa dấu phẩy động mà chương trình của họ yêu cầu một cách dễ dàng và rõ ràng. Hỗ trợ ngôn ngữ cho độ chính xác mở rộng có phức tạp như vậy không? . Tuy nhiên, các hệ thống dựa trên mở rộng đặt ra những lựa chọn khó khăn. chúng không hỗ trợ tính toán chính xác kép thuần túy cũng như tính toán chính xác mở rộng thuần túy hiệu quả như hỗn hợp của cả hai và các chương trình khác nhau yêu cầu các hỗn hợp khác nhau. Hơn nữa, không nên để việc lựa chọn thời điểm sử dụng độ chính xác mở rộng cho những người viết trình biên dịch, những người thường bị cám dỗ bởi các điểm chuẩn (và đôi khi được các nhà phân tích số nói thẳng ra) coi số học dấu phẩy động là "không chính xác vốn có" và do đó không xứng đáng cũng như không có khả năng. . Thay vào đó, sự lựa chọn phải được trình bày cho các lập trình viên và họ sẽ yêu cầu các ngôn ngữ có khả năng thể hiện sự lựa chọn của họ. Phần kết luậnCác nhận xét ở trên không nhằm chê bai các hệ thống dựa trên mở rộng mà để phơi bày một số sai lầm, điều đầu tiên là tất cả các hệ thống IEEE 754 phải cung cấp các kết quả giống hệt nhau cho cùng một chương trình. Chúng tôi đã tập trung vào sự khác biệt giữa hệ thống dựa trên mở rộng và hệ thống đơn/kép, nhưng còn có sự khác biệt nữa giữa các hệ thống trong mỗi họ này. Ví dụ: một số hệ thống đơn/đôi cung cấp một lệnh duy nhất để nhân hai số và cộng số thứ ba chỉ với một lần làm tròn cuối cùng. Thao tác này, được gọi là phép cộng-thêm kết hợp, có thể khiến cùng một chương trình tạo ra các kết quả khác nhau trên các hệ thống đơn/kép khác nhau và giống như độ chính xác mở rộng, nó thậm chí có thể khiến cùng một chương trình tạo ra các kết quả khác nhau trên cùng một hệ thống tùy thuộc vào việc . (Một phép cộng nhân hợp nhất cũng có thể làm hỏng quá trình tách của Định lý 6, mặc dù nó có thể được sử dụng theo cách không di động để thực hiện nhiều phép nhân chính xác mà không cần tách. ) Mặc dù tiêu chuẩn IEEE không lường trước được hoạt động như vậy, nhưng nó vẫn tuân thủ. sản phẩm trung gian được chuyển đến một "điểm đến" ngoài tầm kiểm soát của người dùng đủ rộng để giữ chính xác sản phẩm đó và tổng cuối cùng được làm tròn chính xác để khớp với điểm đến chính xác đơn hoặc kép Ý tưởng rằng IEEE 754 quy định chính xác kết quả mà một chương trình nhất định phải cung cấp dù sao cũng rất hấp dẫn. Nhiều lập trình viên muốn tin rằng họ có thể hiểu hành vi của một chương trình và chứng minh rằng nó sẽ hoạt động bình thường mà không cần tham khảo trình biên dịch biên dịch nó hoặc máy tính chạy nó. Theo nhiều cách, hỗ trợ niềm tin này là một mục tiêu đáng giá cho các nhà thiết kế hệ thống máy tính và ngôn ngữ lập trình. Thật không may, khi nói đến số học dấu phẩy động, mục tiêu hầu như không thể đạt được. Các tác giả của các tiêu chuẩn IEEE biết điều đó và họ đã không cố gắng đạt được nó. Kết quả là, mặc dù gần như tuân thủ (hầu hết) tiêu chuẩn IEEE 754 trong toàn ngành công nghiệp máy tính, các lập trình viên của phần mềm di động vẫn phải tiếp tục đối phó với số học dấu chấm động không thể đoán trước. Nếu các lập trình viên khai thác các tính năng của IEEE 754, họ sẽ cần các ngôn ngữ lập trình giúp dự đoán số học dấu phẩy động. Tiêu chuẩn C99 cải thiện khả năng dự đoán ở một mức độ nào đó với chi phí yêu cầu các lập trình viên viết nhiều phiên bản chương trình của họ, mỗi phiên bản cho một n = n/262. Liệu các ngôn ngữ trong tương lai có chọn thay vào đó để cho phép các lập trình viên viết một chương trình duy nhất với cú pháp thể hiện rõ ràng mức độ phụ thuộc vào ngữ nghĩa của IEEE 754 hay không vẫn còn phải xem. Các hệ thống dựa trên mở rộng hiện tại đe dọa triển vọng đó bằng cách cám dỗ chúng ta giả định rằng trình biên dịch và phần cứng có thể biết rõ hơn lập trình viên về cách thực hiện tính toán trên một hệ thống nhất định. Giả định đó là sai lầm thứ hai. độ chính xác được yêu cầu trong kết quả tính toán không phụ thuộc vào máy tạo ra nó mà chỉ phụ thuộc vào kết luận rút ra từ nó, và của người lập trình, trình biên dịch và phần cứng, tốt nhất chỉ có người lập trình mới có thể biết những kết luận đó có thể là gì |