2010-07-26 19 views
5

Trong khi làm việc trên một bài tập lập trình đơn giản, tôi tạo ra một vòng lặp while (vòng lặp DO trong Fortran) có nghĩa là để thoát ra khi một biến thực đã đạt đến một giá trị chính xác.Fortran có những giới hạn cố hữu về tính chính xác về số so với các ngôn ngữ khác không?

Tôi nhận thấy rằng do độ chính xác được sử dụng, sự bình đẳng chưa bao giờ được đáp ứng và vòng lặp trở thành vô hạn. Đây là, tất nhiên, không phải không nghe và một là thông báo rằng, thay vì so sánh hai con số cho bình đẳng, tốt nhất là xem nếu sự khác biệt tuyệt đối giữa hai con số nhỏ hơn một ngưỡng thiết lập.

Điều tôi thấy thất vọng là mức độ thấp đến mức tôi phải đặt ngưỡng này, ngay cả với các biến ở độ chính xác gấp đôi, cho vòng lặp của tôi để thoát đúng cách. Hơn nữa, khi tôi viết lại một phiên bản "chưng cất" của vòng lặp này trong Perl, tôi không gặp vấn đề gì về độ chính xác về số và vòng lặp thoát ra tốt.

Kể từ khi mã để tạo ra vấn đề là quá nhỏ, trong cả hai Perl và Fortran, tôi muốn tái tạo nó ở đây trong trường hợp tôi đang glossing qua một chi tiết quan trọng:

Fortran Mã

PROGRAM precision_test 
IMPLICIT NONE 

! Data Dictionary 
INTEGER :: count = 0 ! Number of times the loop has iterated 
REAL(KIND=8) :: velocity 
REAL(KIND=8), PARAMETER :: MACH_2_METERS_PER_SEC = 340.0 

velocity = 0.5 * MACH_2_METERS_PER_SEC ! Initial Velocity 
DO 
     WRITE (*, 300) velocity 
     300 FORMAT (F20.8) 
     IF (count == 50) EXIT 
     IF (velocity == 5.0 * MACH_2_METERS_PER_SEC) EXIT 
!  IF (abs(velocity - (5.0 * MACH_2_METERS_PER_SEC)) < 1E-4) EXIT 
     velocity = velocity + 0.1 * MACH_2_METERS_PER_SEC 
     count = count + 1 
END DO 

END PROGRAM precision_test 

Perl Mã dòng

#! /usr/bin/perl -w 
use strict; 

my $mach_2_meters_per_sec = 340.0; 

my $velocity = 0.5 * $mach_2_meters_per_sec; 

while (1) { 
     printf "%20.8f\n", $velocity; 
     exit if ($velocity == 5.0 * $mach_2_meters_per_sec); 
     $velocity = $velocity + 0.1 * $mach_2_meters_per_sec; 
} 

Các nhận xét ra trong Ví tran là những gì tôi sẽ cần phải sử dụng cho các vòng lặp để thoát khỏi bình thường. Lưu ý rằng ngưỡng được đặt thành 1E-4, điều tôi cảm thấy khá thảm hại.

Tên của các biến đến từ bài tập lập trình tự học dựa trên tôi đã thực hiện và không có bất kỳ sự liên quan nào.

Mục đích là vòng lặp dừng lại khi biến vận tốc đạt đến 1700.

Sau đây là các kết quả đầu ra cắt ngắn:

Perl Output

170.00000000 
    204.00000000 
    238.00000000 
    272.00000000 
    306.00000000 
    340.00000000 

...

1564.00000000 
    1598.00000000 
    1632.00000000 
    1666.00000000 
    1700.00000000 

Fortran Output

170.00000000 
    204.00000051 
    238.00000101 
    272.00000152 
    306.00000203 
    340.00000253 

...

1564.00002077 
    1598.00002128 
    1632.00002179 
    1666.00002229 
    1700.00002280 

gì tốt là tốc độ và dễ song song nếu độ chính xác của nó stinks Fortran không? Nhắc tôi về ba cách để làm những việc:

  1. The Right Way

  2. The Way sai

  3. Các Max Power Way

"Đó không phải là chỉ sai đường?"

" Vâng! Nhưng nhanh hơn!"

Tất cả đùa sang một bên, tôi phải làm gì đó sai.

Liệu Fortran có những hạn chế cố hữu về tính chính xác số so với các ngôn ngữ khác, hay tôi (rất có thể) người có lỗi?

trình biên dịch của tôi là gfortran (gcc phiên bản 4.1.2), Perl v5.12.1, trên một dual Core AMD Opteron @ 1 GHZ.

+0

Không nên là số 3 "Cách điện tối đa"? – detly

+0

Rất tiếc. Bạn đúng. Cảm ơn! – EMiller

+1

Fortran đang sử dụng một đôi ở đây và tôi nghi ngờ Perl để làm như vậy. Nhưng việc kiểm tra một số điểm bằng với số dấu phẩy động là vấn đề (trừ khi bạn có số "an toàn" như '0,0144'). Vì vậy, tôi sẽ nói rằng nó có lẽ là phương pháp thử nghiệm của bạn đó là sai. – Wolph

Trả lời

15

phân công của bạn là vô tình chuyển đổi các giá trị cho độ chính xác đơn và sau đó trở lại tăng gấp đôi.

Tr y tạo 0.1 *0.1D0 * và bạn sẽ thấy sự cố của mình được khắc phục.

+0

Trên thực tế, ông đã sử dụng một REAL (loại = 8), đó là DOUBLE PRECISION. – Gilead

+1

@Gilead: Vâng, tôi đã bỏ lỡ bước đầu đó; trải nghiệm Fortran của tôi không phải với GNU Fortran. Đã xóa câu trả lời không đúng và đưa vào câu trả lời đúng. – ysth

+0

Ah! Đó là câu trả lời. Rất tinh tế! 1 cho điều này. – Gilead

7

Như đã trả lời, hằng số dấu chấm động "đồng bằng" trong Fortran sẽ mặc định là loại thực mặc định, có thể sẽ có độ chính xác đơn. Đây là một sai lầm gần như cổ điển.

Ngoài ra, việc sử dụng "loại = 8" không phải là di động - nó sẽ cung cấp cho bạn độ chính xác gấp đôi với gfortran, nhưng không phải với một số trình biên dịch khác. Cách an toàn, di động để xác định các precisions cho cả hai biến và hằng số trong Fortran> = 90 là sử dụng các hàm nội tại, và yêu cầu độ chính xác mà bạn cần. Sau đó, chỉ định "các loại" trên các hằng số trong đó độ chính xác là quan trọng. Một phương pháp thuận tiện là xác định các biểu tượng của riêng bạn. Ví dụ:

integer, parameter :: DR_K = selected_real_kind (14) 

REAL(DR_K), PARAMETER :: MACH_2_METERS_PER_SEC = 340.0_DR_K 

real (DR_K) :: mass, velocity, energy 

energy = 0.5_DR_K * mass * velocity**2 

Điều này cũng có thể quan trọng đối với số nguyên, ví dụ: nếu cần giá trị lớn. Đối với các câu hỏi liên quan đến số nguyên, hãy xem Fortran: integer*4 vs integer(4) vs integer(kind=4)Long ints in Fortran

+0

'thực (loại = 8)' là hoàn toàn tiêu chuẩn Fortran 90. Tất cả các trình biên dịch tuân thủ Fortran 90 nên, và làm, hỗ trợ nó. Điều đó nói rằng, cách thích hợp để yêu cầu một độ chính xác cụ thể trong Fortran 90 là một cái gì đó như sau: 'số nguyên, tham số :: dp = selected_real_kind (15, 307) thực (loại = dp) :: a' Xem [ Fortran Wiki] (http://fortranwiki.org/fortran/show/Real+precision) –

+3

@fB: @MSB là đúng để khẳng định rằng loại = 8 không phải là di động, và bạn có quyền nói rằng nó là tiêu chuẩn Fortran 90 Không có tính di động của câu lệnh phát sinh vì trong khi type = 8 là một bộ chọn kiểu hợp lệ thì sự phụ thuộc của phần tử 8 phụ thuộc vào việc thực thi. Chắc chắn hầu hết các trình biên dịch hiện tại sẽ (tôi tin) giải thích điều này là một số nguyên 8 byte, nhưng điều này không được đảm bảo theo tiêu chuẩn. Nó chắc chắn không phải luôn luôn là sự thật rằng tất cả các trình biên dịch Fortran sẽ giải thích điều này theo cùng một cách, và một trong những mối quan tâm của các lập trình viên Fortran trung bình là tính di động theo thời gian. –

+0

@MSB Đúng vậy, tôi thực sự đã nhận xét câu trả lời sai. –

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