Đã có app VietJack trên điện thoại, giải bài tập SGK, SBT Soạn văn, Văn mẫu, Thi online, Bài giảng. miễn phí. Tải ngay ứng dụng trên Android và iOS
Các bạn có thể mua thêm khóa học JAVA CORE ONLINE và ỨNG DỤNG cực hay, giúp các bạn vượt qua các dự án trên trường và đi thực thi Java. Khóa học có giá chỉ 300K, được ưu đãi, tạo điều kiện cho sinh viên mua khóa học
Nội dung từ khóa học gồm 16 chương và 100 video cực hay, học trực tiếp tại https. //www. demy. com/tu-tin-di-lam-voi-kien-thuc-ve-java-core-toan-tap/ Bạn nào có nhu cầu mua, inbox trực tiếp a Tuyền, cựu SV Bách Khoa K53, fb. https. //www. Facebook. com/tuyen. vietjack
Theo dõi facebook cá nhân Nguyễn Thanh Tuyền https. //www. Facebook. com/tuyen. vietjack to continue theo dõi hàng loạt bài viết mới nhất về Java,C,C++,Javascript,HTML,Python,Database,Mobile. mới nhất của chúng tôi
Các bài học JavaScript khác tại VietJack
- Javascript - Cú pháp
- Javascript - Kích hoạt
- Javascript - Vị trí trong tệp HTML
- Javascript - Biến
- Javascript - Toán tử
- Javascript - Lệnh Nếu. Khác
Trang trước
Trang sau
doi_tuong_math_trong_javascript. jsp
Bài viết liên quan
160 bài học ngữ pháp tiếng Anh hay nhất
155 bài học Java tiếng Việt hay nhất
100 bài học Android tiếng Việt hay nhất
247 bài học CSS tiếng Việt hay nhất
197 thẻ HTML cơ bản
297 bài học PHP
101 bài học C++ hay nhất
97 bài tập C++ có giải hay nhất
208 bài học Javascript có giải pháp hay nhất
Học cùng VietJack
Trang web chia sẻ nội dung miễn phí dành cho người Việt
Lớp 1-2-3 Lớp 4 Lớp 5 Lớp 6 Lớp 7 Lớp 8 Lớp 9 Lớp 10 Lớp 11 Lớp 12 Lập trình Tiếng Anh
Chính sách
Chính sách bảo mật
Hình thức thanh toán
Chính sách đổi trả khóa học
Chính sách hủy khóa học
Tuyển dụng
Liên hệ với chúng tôi
Tầng 2, số nhà 541 Vũ Tông Phan, Phường Khương Đình, Quận Thanh Xuân, Thành phố Hà Nội, Việt Nam
Phone. 084 283 45 85
Email. vietjackteam@gmail. com
CÔNG TY TNHH ĐẦU TƯ VÀ DỊCH VỤ GIÁO DỤC VIETJACK
Người đại diện. Nguyễn Thanh Tuyền
Số giấy chứng nhận đăng ký kinh doanh. 0108307822, ngày cấp. 04/06/2018, nơi cấp. Sở Kế hoạch và Đầu tư thành phố Hà Nội
Floating-point arithmetic is considered an esoteric subject by many people. This is rather surprising because floating-point is ubiquitous in computer systems. Almost every language has a floating-point datatype; computers from PCs to supercomputers have floating-point accelerators; most compilers will be called upon to compile floating-point algorithms from time to time; and virtually every operating system must respond to floating-point exceptions such as overflow. 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. It begins with background on floating-point representation and rounding error, continues with a discussion of the IEEE floating-point standard, and concludes with numerous examples of how computer builders can better support floating-point
Categories and Subject Descriptors. [Primary] C. 0 [Computer Systems Organization]. General -- instruction set design; D. 3. 4 [Programming Languages]. Processors -- compilers, optimization; G. 1. 0 [Numerical Analysis]. General -- computer arithmetic, error analysis, numerical algorithms [Secondary]
D. 2. 1 [Software Engineering]. Requirements/Specifications -- languages; D. 3. 4 Programming Languages]. Formal Definitions and Theory -- semantics; D. 4. 1 Operating Systems]. Process Management -- synchronization
General Terms. Algorithms, Design, Languages
Additional Key Words and Phrases. Denormalized number, exception, floating-point, floating-point standard, gradual underflow, guard digit, NaN, overflow, relative error, rounding error, rounding mode, ulp, underflow
Introduction
Builders of computer systems often need information about floating-point arithmetic. There are, however, remarkably few sources of detailed information about it. One of the few books on the subject, Floating-Point Computation by Pat Sterbenz, is long out of print. This paper is a tutorial on those aspects of floating-point arithmetic [floating-point hereafter] that have a direct connection to systems building. It consists of three loosely connected parts. The first section, , discusses the implications of using different rounding strategies for the basic operations of addition, subtraction, multiplication and division. It also contains background information on the two methods of measuring rounding error, ulps and
n = n/22
n = n/23. The second part discusses the IEEE floating-point standard, which is becoming rapidly accepted by commercial hardware manufacturers. Included in the IEEE standard is the rounding method for basic operations. The discussion of the standard draws on the material in the section . The third part discusses the connections between floating-point and the design of various aspects of computer systems. Topics include instruction set design, optimizing compilers and exception handling
I have tried to avoid making statements about floating-point without also giving reasons why the statements are true, especially since the justifications involve nothing more complicated than elementary calculus. Those explanations that are not central to the main argument have been grouped into a section called "The Details," so that they can be skipped if desired. In particular, the proofs of many of the theorems appear in this section. The end of each proof is marked with the z symbol. When a proof is not included, the z appears immediately following the statement of the theorem
Rounding Error
Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation. The section describes how it is measured
Since most floating-point calculations have rounding error anyway, does it matter if the basic arithmetic operations introduce a little bit more rounding error than necessary? That question is a main theme throughout this section. The section discusses guard digits, a means of reducing the error when subtracting two nearby numbers. Guard digits were considered sufficiently important by IBM that in 1968 it added a guard digit to the double precision format in the System/360 architecture [single precision already had a guard digit], and retrofitted all existing machines in the field. Two examples are given to illustrate the utility of guard digits
The IEEE standard goes further than just requiring the use of a guard digit. It gives an algorithm for addition, subtraction, multiplication, division and square root, and requires that implementations produce the same result as that algorithm. Thus, when a program is moved from one machine to another, the results of the basic operations will be the same in every bit if both machines support the IEEE standard. This greatly simplifies the porting of programs. Other uses of this precise specification are given in
Floating-point Formats
Several different representations of real numbers have been proposed, but by far the most widely used is the floating-point representation. Floating-point representations have a base
In general, a floating-point number will be represented as ± d. dd. 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. Two other parameters associated with floating-point representations are the largest and smallest allowable exponents, emax and emin. Since there are
bits, where the final +1 is for the sign bit. The precise encoding is not important for now
There are two reasons why a real number might not be exactly representable as a floating-point number. The most common situation is illustrated by the decimal number 0. 1. Although it has a finite decimal representation, in binary it has an infinite repeating representation. Thus when
Floating-point representations are not necessarily unique. For example, both 0. 01 × 101 và 1. 00 × 10-1 represent 0. 1. If the leading digit is nonzero [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à Ulps
Vì 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 sai số làm tròn, ulps và
chữ 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ý 1
Sử dụng định dạng dấu phẩy động có tham sốBằng chứng
Mộ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ý 2
Nế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 bị 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
[and similarly for r2] to obtain
[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
In order to avoid confusion between exact and computed values, the following notation is used. 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ý 3
Sai 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à 11Back to. If z =1 = -1 + i0, then
1/z = 1/[-1 + i0] = [[-1- i0]]/[[-1 + i0][-1 - i0]] = [-1 -- i0]/[[-1]2 - 02] = -1 + i[-0],and so, while. Thus IEEE arithmetic preserves this identity for all z. Some more sophisticated examples are given by Kahan [1987]. Although distinguishing between +0 and -0 has advantages, it can occasionally be confusing. For example, signed zero destroys the relation x = y
Denormalized Numbers
Consider normalized floating-point numbers with
It's very easy to imagine writing the code fragment,
while [n is even] {02
while [n is even] {03
while [n is even] {09
while [n is even] {10
while [n is even] {11
while [n is even] {04
while [n is even] {13, and much later having a program fail due to a spurious division by zero. Tracking down bugs like this is frustrating and time consuming. On a more philosophical level, computer science textbooks often point out that even though it is currently impractical to prove large programs correct, designing programs with the idea of proving them often results in better code. For example, introducing invariants is quite useful, even if they aren't going to be used as part of a proof. Floating-point code is just like any other code. it helps to have provable facts on which to depend. For example, when analyzing formula , it was very helpful to know that x/2
The IEEE standard uses denormalized numbers, which guarantee , as well as other useful relations. They are the most controversial part of the standard and probably accounted for the long delay in getting 754 approved. Most high performance hardware that claims to be IEEE compatible does not support denormalized numbers directly, but rather traps when consuming or producing denormals, and leaves it to software to simulate the IEEE standard. The idea behind denormalized numbers goes back to Goldberg [1967] and is very simple. When the exponent is emin, the significand does not have to be normalized, so that when
There is a small snag when
Recall the example of
FIGURE D-2 Flush To Zero Compared With Gradual Underflow
illustrates denormalized numbers. The top number line in the figure shows normalized floating-point numbers. Notice the gap between 0 and the smallest normalized number. If the result of a floating-point calculation falls into this gulf, it is flushed to zero. The bottom number line shows what happens when denormals are added to the set of floating-point numbers. The "gulf" is filled in, and when the result of a calculation is less than, it is represented by the nearest denormal. When denormalized numbers are added to the number line, the spacing between adjacent floating-point numbers varies in a regular way. adjacent spacings are either the same length or differ by a factor of
spacing abruptly changes fromto, which is a factor of, rather than the orderly change by a factor of
Without gradual underflow, the simple expression x - y can have a very large relative error for normalized inputs, as was seen above for x = 6. 87 × 10-97 and y = 6. 81 × 10-97. Large relative errors can happen even without cancellation, as the following example shows [Demmel 1984]. Consider dividing two complex numbers, a + ib and c + id. The obvious formula
suffers from the problem that if either component of the denominator c + id is larger than, the formula will overflow, even though the final result may be well within range. A better method of computing the quotients is to use Smith's formula
[11]Applying Smith's formula to [2 · 10-98 + i10-98]/[4 · 10-98 + i[2 · 10-98]] gives the correct answer of 0. 5 with gradual underflow. It yields 0. 4 with flush to zero, an error of 100 ulps. It is typical for denormalized numbers to guarantee error bounds for arguments all the way down to 1. 0 x.
Exceptions, Flags and Trap Handlers
When an exceptional condition like division by zero or overflow occurs in IEEE arithmetic, the default is to deliver a result and continue. Typical of the default results are NaN for 0/0 and, and
Sometimes continuing execution in the face of exception conditions is not appropriate. The section gave the example of x/[x2 + 1]. When x >, the denominator is infinite, resulting in a final answer of 0, which is totally wrong. Although for this formula the problem can be solved by rewriting it as 1/[x + x-1], rewriting may not always solve the problem. The IEEE standard strongly recommends that implementations allow trap handlers to be installed. Then when an exception occurs, the trap handler is called instead of setting the flag. The value returned by the trap handler will be used as the result of the operation. It is the responsibility of the trap handler to either clear or set the status flag; otherwise, the value of the flag is allowed to be undefined
The IEEE standard divides exceptions into 5 classes. overflow, underflow, division by zero, invalid operation and inexact. There is a separate status flag for each class of exception. The meaning of the first three exceptions is self-evident. Invalid operation covers the situations listed in , and any comparison that involves a NaN. The default result of an operation that causes an invalid exception is to return a NaN, but the converse is not true. When one of the operands to an operation is a NaN, the result is a NaN but no invalid exception is raised unless the operation also satisfies one of the conditions in
TABLE D-4 Exceptions in IEEE 754*ExceptionResult when traps disabledArgument to trap handleroverflow±*x is the exact result of the operation,
The inexact exception is raised when the result of a floating-point operation is not exact. In the
There is an implementation issue connected with the fact that the inexact exception is raised so often. If floating-point hardware does not have flags of its own, but instead interrupts the operating system to signal a floating-point exception, the cost of inexact exceptions could be prohibitive. This cost can be avoided by having the status flags maintained by software. The first time an exception is raised, set the software flag for the appropriate class, and tell the floating-point hardware to mask off that class of exceptions. Then all further exceptions will run without interrupting the operating system. When a user resets that status flag, the hardware mask is re-enabled
Trap Handlers
One obvious use for trap handlers is for backward compatibility. Old codes that expect to be aborted when exceptions occur can install a trap handler that aborts the process. This is especially useful for codes with a loop like while [n is even] {
14 while [n is even] {
15 while [n is even] {
16 while [n is even] {
03 while [n is even] {
18 while [n is even] {
19. Since comparing a NaN to a number with , , or = [but not ] always returns false, this code will go into an infinite loop if while [n is even] {
06 ever becomes a NaN.
while [n is even] {06 ever becomes a NaN.
There is a more interesting use for trap handlers that comes up when computing products such asthat could potentially overflow. One solution is to use logarithms, and compute expinstead. The problem with this approach is that it is less accurate, and that it costs more than the simple expression, even if there is no overflow. There is another solution using trap handlers called over/underflow counting that avoids both of these problems [Sterbenz 1974]
The idea is as follows. There is a global counter initialized to zero. Whenever the partial productoverflows for some k, the trap handler increments the counter by one and returns the overflowed quantity with the exponent wrapped around. In IEEE 754 single precision, emax = 127, so if pk = 1. 45 × 2130, it will overflow and cause the trap handler to be called, which will wrap the exponent back into range, changing pk to 1. 45 × 2-62 [see below]. Similarly, if pk underflows, the counter would be decremented, and negative exponent would get wrapped around into a positive one. When all the multiplications are done, if the counter is zero then the final product is pn. If the counter is positive, the product overflowed, if the counter is negative, it underflowed. If none of the partial products are out of range, the trap handler is never called and the computation incurs no extra cost. Even if there are over/underflows, the calculation is more accurate than if it had been computed with logarithms, because each pk was computed from pk - 1 using a full precision multiply. Barnett [1987] discusses a formula where the full accuracy of over/underflow counting turned up an error in earlier tables of that formula
IEEE 754 specifies that when an overflow or underflow trap handler is called, it is passed the wrapped-around result as an argument. The definition of wrapped-around for overflow is that the result is computed as if to infinite precision, then divided by 2
Rounding Modes
In the IEEE standard, rounding occurs whenever an operation has a result that is not exact, since [with the exception of binary decimal conversion] each operation is computed exactly and then rounded. By default, rounding means round toward nearest. The standard requires that three other rounding modes be provided, namely round toward 0, round toward +
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 ]. When using interval arithmetic, the sum of two numbers x and y is an interval, whereis 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. This is not very helpful if the interval turns out to be large [as it often does], since the correct answer could be anywhere in that interval. Interval arithmetic makes more sense when used in conjunction with a multiple precision floating-point package. The calculation is first performed with some precision p. If interval arithmetic suggests that the final answer may be inaccurate, the computation is redone with higher and higher precisions until the final interval is a reasonable size
Flags
The IEEE standard has a number of flags and modes. As discussed above, there is one status flag for each of the five exceptions. underflow, overflow, division by zero, invalid operation and inexact. There are four rounding modes. round toward nearest, round toward +
Consider writing a subroutine to compute xn, where n is an integer. When n > 0, a simple routine like
PositivePower[x,n] {
while [n is even] {
x = x*x
n = n/2
}
u = x
while [true] {
n = n/2
if [n==0] return u
x = x*x
while [n is even] {0
}
If n < 0, then a more accurate way to compute xn is not to call
while [n is even] {21
while [n is even] {22 but rather
while [n is even] {23
while [n is even] {22, because the first expression multiplies n quantities each of which have a rounding error from the division [i. e. , 1/x]. In the second expression these are exact [i. e. , x], and the final division commits just one additional rounding error. Unfortunately, these is a slight snag in this strategy. If
while [n is even] {25
while [n is even] {22 underflows, then either the underflow trap handler will be called, or else the underflow status flag will be set. This is incorrect, because if x-n underflows, then xn will either overflow or be in range. But since the IEEE standard gives the user access to all the flags, the subroutine can easily correct for this. It simply turns off the overflow and underflow trap enable bits and saves the overflow and underflow status bits. It then computes
while [n is even] {23
while [n is even] {22. If neither the overflow nor underflow status bit is set, it restores them together with the trap enable bits. If one of the status bits is set, it restores the flags and redoes the calculation using
while [n is even] {21
while [n is even] {22, which causes the correct exceptions to occur
Another example of the use of flags occurs when computing arccos via the formula
arccos x = 2 arctanIf arctan[
Systems Aspects
The design of almost every aspect of a computer system requires knowledge about floating-point. Computer architectures usually have floating-point instructions, compilers must generate those floating-point instructions, and the operating system must decide what to do when exception conditions are raised for those floating-point instructions. Computer system designers rarely get guidance from numerical analysis texts, which are typically aimed at users and writers of software, not at computer designers. As an example of how plausible design decisions can lead to unexpected behavior, consider the following BASIC program
while [n is even] {2
while [n is even] {3
while [n is even] {4
When compiled and run using Borland's Turbo Basic on an IBM PC, the program prints
while [n is even] {31
while [n is even] {32. This example will be analyzed in the next section
Incidentally, some people think that the solution to such anomalies is never to compare floating-point numbers for equality, but instead to consider them equal if they are within some error bound E. This is hardly a cure-all because it raises as many questions as it answers. What should the value of E be? If x < 0 and y > 0 are within E, should they really be considered to be equal, even though they have different signs? Furthermore, the relation defined by this rule, a ~ b
Instruction Sets
It is quite common for an algorithm to require a short burst of higher precision in order to produce accurate results. One example occurs in the quadratic formula []/2a. As discussed in the section , when b2
The computation of b2 - 4ac in double precision when each of the quantities a, b, and c are in single precision is easy if there is a multiplication instruction that takes two single precision numbers and produces a double precision result. In order to produce the exactly rounded product of two p-digit numbers, a multiplier needs to generate the entire 2p bits of product, although it may throw bits away as it proceeds. Thus, hardware to compute a double precision product from single precision operands will normally be only a little more expensive than a single precision multiplier, and much cheaper than a double precision multiplier. Despite this, modern instruction sets tend to provide only instructions that produce a result of the same precision as the operands
If an instruction that combines two single precision operands to produce a double precision product was only useful for the quadratic formula, it wouldn't be worth adding to an instruction set. However, this instruction has many other uses. Consider the problem of solving a system of linear equations,
a11x1 + a12x2 + · · · + a1nxn= b1a21x1 + a22x2 + · · · + a2nxn= b2
· · ·
an1x1 + an2x2 + · · ·+ annxn= bn
which can be written in matrix form as Ax = b, where
Suppose that a solution x[1] is computed by some method, perhaps Gaussian elimination. There is a simple way to improve the accuracy of the result called iterative improvement. First compute
[12]and then solve the system
[13] Ay =Note that if x[1] is an exact solution, then
The three steps , , and can be repeated, replacing x[1] with x[2], and x[2] with x[3]. This argument that x[i + 1] is more accurate than x[i] is only informal. For more information, see [Golub and Van Loan 1989]
When performing iterative improvement,
To summarize, instructions that multiply two floating-point numbers and return a product with twice the precision of the operands make a useful addition to a floating-point instruction set. Some of the implications of this for compilers are discussed in the next section
Ngôn ngữ và Trình biên dịch
The interaction of compilers and floating-point is discussed in Farnum [1988], and much of the discussion in this section is taken from that paper
Ambiguity
Ideally, a language definition should define the semantics of the language precisely enough to prove statements about programs. While this is usually true for the integer part of a language, language definitions often have a large grey area when it comes to floating-point. Perhaps this is due to the fact that many language designers believe that nothing can be proven about floating-point, since it entails rounding error. If so, the previous sections have demonstrated the fallacy in this reasoning. This section discusses some common grey areas in language definitions, including suggestions about how to deal with them
Remarkably enough, some languages don't clearly specify that if
while [n is even] {06 is a floating-point variable [with say a value of
while [n is even] {34], then every occurrence of [say]
while [n is even] {35 must have the same value. For example Ada, which is based on Brown's model, seems to imply that floating-point arithmetic only has to satisfy Brown's axioms, and thus expressions can have one of many possible values. Thinking about floating-point in this fuzzy way stands in sharp contrast to the IEEE model, where the result of each floating-point operation is precisely defined. In the IEEE model, we can prove that
while [n is even] {36 evaluates to
while [n is even] {37 [Theorem 7]. In Brown's model, we cannot
Another ambiguity in most language definitions concerns what happens on overflow, underflow and other exceptions. The IEEE standard precisely specifies the behavior of exceptions, and so languages that use the standard as a model can avoid any ambiguity on this point
Another grey area concerns the interpretation of parentheses. Due to roundoff errors, the associative laws of algebra do not necessarily hold for floating-point numbers. For example, the expression
while [n is even] {38 has a totally different answer than
while [n is even] {39 when x = 1030, y = -1030 and z = 1 [it is 1 in the former case, 0 in the latter]. The importance of preserving parentheses cannot be overemphasized. The algorithms presented in theorems 3, 4 and 6 all depend on it. For example, in Theorem 6, the formula xh = mx - [mx - x] would reduce to xh = x if it weren't for parentheses, thereby destroying the entire algorithm. A language definition that does not require parentheses to be honored is useless for floating-point calculations
Subexpression evaluation is imprecisely defined in many languages. Suppose that
while [n is even] {40 is double precision, but
while [n is even] {06 and
while [n is even] {42 are single precision. Then in the expression
while [n is even] {40
while [n is even] {44
while [n is even] {45 is the product performed in single or double precision? Another example. in
while [n is even] {06
while [n is even] {44
while [n is even] {48 where
while [n is even] {49 and
while [n is even] {50 are integers, is the division an integer operation or a floating-point one? There are two ways to deal with this problem, neither of which is completely satisfactory. The first is to require that all variables in an expression have the same type. This is the simplest solution, but has some drawbacks. First of all, languages like Pascal that have subrange types allow mixing subrange variables with integer variables, so it is somewhat bizarre to prohibit mixing single and double precision variables. Another problem concerns constants. In the expression
while [n is even] {51, most languages interpret 0. 1 to be a single precision constant. Now suppose the programmer decides to change the declaration of all the floating-point variables from single to double precision. If 0. 1 is still treated as a single precision constant, then there will be a compile time error. The programmer will have to hunt down and change every floating-point constant
The second approach is to allow mixed expressions, in which case rules for subexpression evaluation must be provided. There are a number of guiding examples. The original definition of C required that every floating-point expression be computed in double precision [Kernighan and Ritchie 1978]. This leads to anomalies like the example at the beginning of this section. The expression
while [n is even] {52 is computed in double precision, but if
while [n is even] {53 is a single-precision variable, the quotient is rounded to single precision for storage. Since 3/7 is a repeating binary fraction, its computed value in double precision is different from its stored value in single precision. Thus the comparison q = 3/7 fails. Đ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
Another guiding example is inner products. If the inner product has thousands of terms, the rounding error in the sum can become substantial. One way to reduce this rounding error is to accumulate the sums in double precision [this will be discussed in more detail in the section ]. If
while [n is even] {54 is a double precision variable, and
while [n is even] {55 and
while [n is even] {56 are single precision arrays, then the inner product loop will look like
while [n is even] {54
while [n is even] {04
while [n is even] {54
while [n is even] {44
while [n is even] {61. If the multiplication is done in single precision, than much of the advantage of double precision accumulation is lost, because the product is truncated to single precision just before being added to a double precision variable
A rule that covers both of the previous two examples is to compute an expression in the highest precision of any variable that occurs in that expression. Then
while [n is even] {53
while [n is even] {04
while [n is even] {52 will be computed entirely in single precision and will have the boolean value true, whereas
while [n is even] {54
while [n is even] {04
while [n is even] {54
while [n is even] {44
while [n is even] {61 will be computed in double precision, gaining the full advantage of double precision accumulation. However, this rule is too simplistic to cover all cases cleanly. If
while [n is even] {70 and
while [n is even] {71 are double precision variables, the expression
while [n is even] {42
while [n is even] {04
while [n is even] {06
while [n is even] {44
while [n is even] {76 contains a double precision variable, but performing the sum in double precision would be pointless, because both operands are single precision, as is the result
A more sophisticated subexpression evaluation rule is as follows. First assign each operation a tentative precision, which is the maximum of the precisions of its operands. This assignment has to be carried out from the leaves to the root of the expression tree. Then perform a second pass from the root to the leaves. In this pass, assign to each operation the maximum of the tentative precision and the precision expected by the parent. In the case of
while [n is even] {53
while [n is even] {04
while [n is even] {52, every leaf is single precision, so all the operations are done in single precision. In the case of
while [n is even] {54
while [n is even] {04
while [n is even] {54
while [n is even] {44
while [n is even] {61, the tentative precision of the multiply operation is single precision, but in the second pass it gets promoted to double precision, because its parent operation expects a double precision operand. And in
while [n is even] {42
while [n is even] {04
while [n is even] {06
while [n is even] {44
while [n is even] {76, the addition is done in single precision. Farnum [1988] presents evidence that this algorithm in not difficult to implement
The disadvantage of this rule is that the evaluation of a subexpression depends on the expression in which it is embedded. This can have some annoying consequences. For example, suppose you are debugging a program and want to know the value of a subexpression. You cannot simply type the subexpression to the debugger and ask it to be evaluated, because the value of the subexpression in the program depends on the expression it is embedded in. A final comment on subexpressions. since converting decimal constants to binary is an operation, the evaluation rule also affects the interpretation of decimal constants. Điều này đặc biệt quan trọng đối với các hằng số như
while [n is even] {90 không thể biểu diễn chính xác ở dạng nhị phân
Another potential grey area occurs when a language includes exponentiation as one of its built-in operations. Unlike the basic arithmetic operations, the value of exponentiation is not always obvious [Kahan and Coonen 1982]. If
while [n is even] {91 is the exponentiation operator, then
while [n is even] {92 certainly has the value -27. However,
while [n is even] {93 is problematical. If the
while [n is even] {91 operator checks for integer powers, it would compute
while [n is even] {93 as -3. 03 = -27. On the other hand, if the formula xy = eylogx is used to define
while [n is even] {91 for real arguments, then depending on the log function, the result could be a NaN [using the natural definition of log[x] =
while [n is even] {97 when x < 0]. If the FORTRAN
while [n is even] {98 function is used however, then the answer will be -27, because the ANSI FORTRAN standard defines
while [n is even] {99 to be i
In fact, the FORTRAN standard says that
Any arithmetic operation whose result is not mathematically defined is prohibitedUnfortunately, with the introduction of ±
while [n is even] {93 to be -27.
The IEEE Standard
The section ," discussed many of the features of the IEEE standard. However, the IEEE standard says nothing about how these features are to be accessed from a programming language. Thus, there is usually a mismatch between floating-point hardware that supports the standard and programming languages like C, Pascal or FORTRAN. Some of the IEEE capabilities can be accessed through a library of subroutine calls. For example the IEEE standard requires that square root be exactly rounded, and the square root function is often implemented directly in hardware. This functionality is easily accessed via a library square root routine. However, other aspects of the standard are not so easily implemented as subroutines. For example, most computer languages specify at most two floating-point types, while the IEEE standard has four different precisions [although the recommended configurations are single plus single-extended or single, double, and double-extended]. Infinity provides another example. Constants to represent ±
A more subtle situation is manipulating the state associated with a computation, where the state consists of the rounding modes, trap enable bits, trap handlers and exception flags. One approach is to provide subroutines for reading and writing the state. In addition, a single call that can atomically set a new value and return the old value is often useful. As the examples in the section show, a very common pattern of modifying IEEE state is to change it only within the scope of a block or subroutine. Thus the burden is on the programmer to find each exit from the block, and make sure the state is restored. Language support for setting the state precisely in the scope of a block would be very useful here. Modula-3 is one language that implements this idea for trap handlers [Nelson 1991]
There are a number of minor points that need to be considered when implementing the IEEE standard in a language. Since x - x = +0 for all x, [+0] - [+0] = +0. However, -[+0] = -0, thus -x should not be defined as 0 - x. The introduction of NaNs can be confusing, because a NaN is never equal to any other number [including another NaN], so x = x is no longer always true. In fact, the expression x
x = x*x01 is not provided. Furthermore, NaNs are unordered with respect to all other numbers, so x
x = x*x02 function that returns one of
Although the IEEE standard defines the basic floating-point operations to return a NaN if any operand is a NaN, this might not always be the best definition for compound operations. For example when computing the appropriate scale factor to use in plotting a graph, the maximum of a set of values must be computed. In this case it makes sense for the max operation to simply ignore NaNs
Finally, rounding can be a problem. The IEEE standard defines rounding very precisely, and it depends on the current value of the rounding modes. This sometimes conflicts with the definition of implicit rounding in type conversions or the explicit
x = x*x03 function in languages. This means that programs which wish to use IEEE rounding can't use the natural language primitives, and conversely the language primitives will be inefficient to implement on the ever increasing number of IEEE machines
Optimizers
Compiler texts tend to ignore the subject of floating-point. For example Aho et al. [1986] mentions replacing
x = x*x04 with
x = x*x05, leading the reader to assume that
x = x*x06 should be replaced by
while [n is even] {51. However, these two expressions do not have the same semantics on a binary machine, because 0. 1 cannot be represented exactly in binary. This textbook also suggests replacing
x = x*x08 by
x = x*x09, even though we have seen that these two expressions can have quite different values when y
while [n is even] {38 can have a totally different answer than
while [n is even] {39, as discussed above. There is a problem closely related to preserving parentheses that is illustrated by the following code
while [n is even] {5
while [n is even] {6
:
This is designed to give an estimate for machine epsilon. If an optimizing compiler notices that eps + 1 > 1
Many problems, such as numerical integration and the numerical solution of differential equations involve computing sums with many terms. Because each addition can potentially introduce an error as large as . 5 ulp, a sum involving thousands of terms can have quite a bit of rounding error. A simple way to correct for this is to store the partial summand in a double precision variable and to perform each addition using double precision. If the calculation is being done in single precision, performing the sum in double precision is easy on most computer systems. However, if the calculation is already being done in double precision, doubling the precision is not so simple. One method that is sometimes advocated is to sort the numbers and add them from smallest to largest. However, there is a much more efficient method which dramatically improves the accuracy of sums, namely
Theorem 8 [Kahan Summation Formula]
Suppose thatis computed using the following algorithmwhile [n is even] {7
while [n is even] {8
while [n is even] {9
x = x*x0
x = x*x1
x = x*x2
x = x*x3
x = x*x4
Then the computed sum S is equal towhere
Using the naive formula, the computed sum is equal towhere .
An optimizer that believed floating-point arithmetic obeyed the laws of algebra would conclude that C = [T-S] - Y = [[S+Y]-S] - Y = 0, rendering the algorithm completely useless. These examples can be summarized by saying that optimizers should be extremely cautious when applying algebraic identities that hold for the mathematical real numbers to expressions involving floating-point variables
Another way that optimizers can change the semantics of floating-point code involves constants. In the expression
x = x*x12, there is an implicit decimal to binary conversion operation that converts the decimal number to a binary constant. Because this constant cannot be represented exactly in binary, the inexact exception should be raised. In addition, the underflow flag should to be set if the expression is evaluated in single precision. Since the constant is inexact, its exact conversion to binary depends on the current value of the IEEE rounding modes. Thus an optimizer that converts
x = x*x13 to binary at compile time would be changing the semantics of the program. However, constants like 27. 5 which are exactly representable in the smallest available precision can be safely converted at compile time, since they are always exact, cannot raise any exception, and are unaffected by the rounding modes. Constants that are intended to be converted at compile time should be done with a constant declaration, such as
x = x*x14
x = x*x15
while [n is even] {04
x = x*x17
Common subexpression elimination is another example of an optimization that can change floating-point semantics, as illustrated by the following code
x = x*x5
x = x*x6
x = x*x7
Although
x = x*x18 can appear to be a common subexpression, it is not because the rounding mode is different at the two evaluation sites. Three final examples. x = x cannot be replaced by the boolean constant
x = x*x19, because it fails when x is a NaN; -x = 0 - x fails for x = +0; and x < y is not the opposite of x
Despite these examples, there are useful optimizations that can be done on floating-point code. First of all, there are algebraic identities that are valid for floating-point numbers. 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. However, even these simple identities can fail on a few machines such as CDC and Cray supercomputers. Instruction scheduling and in-line procedure substitution are two other potentially useful optimizations
Như một ví dụ cuối cùng, hãy xem xét biểu thức
while [n is even] {70
while [n is even] {04
while [n is even] {45, trong đó
while [n is even] {06 và
while [n is even] {42 là các biến chính xác đơn và
while [n is even] {70 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,
while [n is even] {70 _______30_______04
while [n is even] {45 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
Some compiler writers view restrictions which prohibit converting [x + y] + z to x + [y + z] as irrelevant, of interest only to programmers who use unportable tricks. 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
Another problem is illustrated by the following program fragment
x = x*x8
x = x*x9
n = n/20
n = n/21
Suppose the second multiply raises an exception, and the trap handler wants to use the value of
if [n==0] return u3. On hardware that can do an add and multiply in parallel, an optimizer would probably move the addition operation ahead of the second multiply, so that the add can proceed in parallel with the first multiply. Thus when the second multiply traps,
if [n==0] return u3
while [n is even] {04
x = x*x32
while [n is even] {44
x = x*x34 has already been executed, potentially changing the result of
if [n==0] return u3. It would not be reasonable for a compiler to avoid this kind of optimization, because every floating-point operation can potentially trap, and thus virtually all instruction scheduling optimizations would be eliminated. This problem can be avoided by prohibiting trap handlers from accessing any variables of the program directly. Instead, the handler can be given the operands or result as an argument
But there are still problems. In the fragment
the two instructions might well be executed in parallel. If the multiply traps, its argument
while [n is even] {11 could already have been overwritten by the addition, especially since addition is usually faster than multiply. Computer systems that support the IEEE standard must provide some way to save the value of
while [n is even] {11, either in hardware or by having the compiler avoid such a situation in the first place
W. Kahan has proposed using presubstitution instead of trap handlers to avoid these problems. In this method, the user specifies an exception and the value he wants to be used as the result when the exception occurs. As an example, suppose that in code for computing [sin x]/x, the user decides that x = 0 is so rare that it would improve performance to avoid a test for x = 0, and instead handle this case when a 0/0 trap occurs. Using IEEE trap handlers, the user would write a handler that returns a value of 1 and install it before computing sin x/x. Using presubstitution, the user would specify that when an invalid operation occurs, the value 1 should be used. Kahan calls this presubstitution, because the value to be used must be specified before the exception occurs. When using trap handlers, the value to be returned can be computed when the trap occurs
The advantage of presubstitution is that it has a straightforward hardware implementation. As soon as the type of exception has been determined, it can be used to index a table which contains the desired result of the operation. Although presubstitution has some attractive attributes, the widespread acceptance of the IEEE standard makes it unlikely to be widely implemented by hardware manufacturers
The Details
A number of claims have been made in this paper concerning properties of floating-point arithmetic. We now proceed to show that floating-point is not black magic, but rather is a straightforward subject whose claims can be verified mathematically. This section is divided into three parts. The first part presents an introduction to error analysis, and provides the details for the section . The second part explores binary to decimal conversion, filling in some gaps from the section . The third part discusses the Kahan summation formula, which was used as an example in the section
Rounding Error
In the discussion of rounding error, it was stated that a single guard digit is enough to guarantee that addition and subtraction will always be accurate [Theorem 2]. We now proceed to verify this fact. Theorem 2 has two parts, one for subtraction and one for addition. The part for subtraction is
Theorem 9
If x and y are positive floating-point numbers in a format with parameters
Bằng chứng
Interchange x and y if necessary so that x > y. It is also harmless to scale x and y so that x is represented by x0. x1 . xp - 1 ×From the definition of guard digit, the computed value of x - y is x -rounded to be a floating-point number, that is, [x -] +
The exact difference is x - y, so the error is [x - y] - [x -+
Secondly, if x -< 1, then
in this case the relative error is bounded by[18]
The final case is when x - y < 1 but x -
When
Theorem 10
If x
Bằng chứng
The algorithm for addition with k guard digits is similar to that for subtraction. If xThe sum is at least
It is obvious that combining these two theorems gives Theorem 2. Theorem 2 gives the relative error for performing one operation. Comparing the rounding error of x2 - y2 and [x + y] [x - y] requires knowing the relative error of multiple operations. The relative error of xy is
Similarly
[20] xAssuming that multiplication is performed by computing the exact product and then rounding, the relative error is at most . 5 ulp, so
[21] ufor any floating-point numbers u and v. Putting these three equations together [letting u = xy and v = x
So the relative error incurred when computing [x - y] [x + y] is
[23]This relative error is equal to
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. In order to estimate the maximum error that can occur when computing with , the following fact will be needed
Theorem 11
If subtraction is performed with a guard digit, and y/2Bằng chứng
Note that if x and y have the same exponent, then certainly xy is exact. Otherwise, from the condition of the theorem, the exponents can differ by at most 1. Scale and interchange x and y if necessary so that 0When
Theorem 12
If subtraction uses a guard digit, and if a,b and c are the sides of a triangle [aBằng chứng
Let's examine the factors one by one. From Theorem 10, band thus[a + b + c] [1 - 2
This means that there is an
The next term involves the potentially catastrophic subtraction of c and a
x = x*x32, because ab may have rounding error. Because a, b and c are the sides of a triangle, a
The third term is the sum of two exact positive quantities, so[26] [c
Finally, the last term is[27] [a
using both Theorem 9 and Theorem 10. If multiplication is assumed to be exactly rounded, so that x
whereE = [1 +
An upper bound for E is [1 + 2
Theorem 12 certainly shows that there is no catastrophic cancellation in formula . So although it is not necessary to show formula is numerically stable, it is satisfying to have a bound for the entire formula, which is what Theorem 3 of gives
Chứng minh Định lý 3
Letq = [a + [b + c]] [c - [a - b]] [c + [a - b]] [a + [b - c]]andQ = [a
Then, Theorem 12 shows that Q = q[1 +
provided
với.
To make the heuristic explanation immediately following the statement of Theorem 4 precise, the next theorem describes just how closely µ[x] approximates a constant
Theorem 13
If µ[x] = ln[1 + x]/x, then for 0Bằng chứng
Note that µ[x] = 1 - x/2 + x2/3 - . is an alternating series with decreasing terms, so for xProof of Theorem 4
Since the Taylor series for lnis an alternating series, 0 < x - ln[1 + x] < x2/2, the relative error incurred when approximating ln[1 + x] by x is bounded by x/2. If 1
where .
for some
Là
It is easy to check that if