質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

Q&A

解決済

1回答

2425閲覧

fortranでのクイックソートのプログラムについて

kanso

総合スコア2

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

0グッド

0クリップ

投稿2021/06/03 06:07

前提・実現したいこと

クイックソートサブルーチンをつくり、sample.txtというファイルの中の2列目にしたがってソートしたいです。
エラーが出てしまいエラーの意味がよく分からないので対処法を教えていただきたいです。

発生している問題・エラーメッセージ

エラーメッセージ Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

該当のソースコード

fortran ソースコード module sort implicit none private public qsi contains subroutine gpv (array, n, a, b, pivot_value) real(8), intent(inout) :: array(:), pivot_value integer, intent(in) :: n, a, b pivot_value = array ((int(a) + int(b)) / 2) end subroutine subroutine gpi (array, n, a, b, pivot) real(8), intent(inout) :: array(:) integer, intent(in) :: n, a, b integer, intent(out) :: pivot real(8) :: buffer, pivot_value integer :: l, r if (a == b) then pivot = 0 return end if call gpv(array, n, a, b, pivot_value) l = a r = b do while (.true.) do while (array(l) < pivot_value) if (l >= b) exit l = l + 1 end do do while (pivot_value < array(r)) if (r <= a) exit r = r - 1 end do if (r <= 1) exit buffer = array(l) array(l) = array(r) array(r) = buffer l = l + 1 r = r + 1 end do pivot = r end subroutine recursive subroutine qss(array, n, a, b) real(8), intent(inout) :: array(:) integer, intent(in) :: n, a, b integer :: pivot call gpi(array, n, a, b, pivot) if (pivot /= 0) then call qss(array, n, a, pivot) call qss(array, n, pivot + 1, b) end if end subroutine subroutine qsi(array, n) real(8) :: array(:) integer :: n call qss(array, n, 1, n) end subroutine end module program quicksort use sort implicit none real(8) :: a(75), b(75) integer :: i, fi = 10 open (fi, file = 'sample.txt', action = 'read') do i = 1, 75 read (fi,*) a(i), b(i) end do call qsi(b,75) do i = 1, 75 write (*,*) a(i) end do close(fi) stop end program quicksort

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

sample.txtの中身はこんな感じです
3 1.05365E-15
3.5 3.00415E-15
4 5.4112E-15
4.5 8.22389E-15
5 1.13945E-14
5.5 1.48783E-14
6 1.86337E-14
6.5 2.26218E-14
7 2.68063E-14
7.5 3.11537E-14
8 3.56329E-14
8.5 4.0215E-14
9 4.48738E-14
9.5 4.95846E-14
10 5.43254E-14
10.5 5.90756E-14
11 6.38169E-14
11.5 6.85324E-14
12 7.3207E-14
12.5 7.78272E-14
13 8.23809E-14
13.5 8.68574E-14
14 9.12473E-14
14.5 9.55424E-14
15 9.97358E-14
15.5 1.03821E-13
16 1.07794E-13
16.5 1.1165E-13
17 1.15387E-13
17.5 1.19E-13
18 1.2249E-13
18.5 1.25854E-13
19 1.29093E-13
19.5 1.32207E-13
20 1.35195E-13
20.5 1.3806E-13
21 1.40801E-13
21.5 1.43422E-13
22 1.45925E-13
22.5 1.4831E-13
23 1.50582E-13
23.5 1.52742E-13
24 1.54793E-13
24.5 1.56738E-13
25 1.58581E-13
25.5 1.60324E-13
26 1.6197E-13
26.5 1.63522E-13
27 1.64983E-13
27.5 1.66356E-13
28 1.67645E-13
28.5 1.68851E-13
29 1.69979E-13
29.5 1.71029E-13
30 1.72006E-13
30.5 1.72911E-13
31 1.73747E-13
31.5 1.74516E-13
32 1.75221E-13
32.5 1.75863E-13
33 1.76446E-13
33.5 1.7697E-13
34 1.77438E-13
34.5 1.77852E-13
35 1.78213E-13
35.5 1.78525E-13
36 1.78788E-13
36.5 1.79006E-13
37 1.79179E-13
37.5 1.79311E-13
38 1.79405E-13
38.5 1.79462E-13
39 1.79486E-13
39.5 1.79479E-13
40 1.79447E-13

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

エラーメッセージの意味は、配列をはみ出した時に起こるメモリーアクセス違反の警告です。

多分 gfortran をお使いだと思いますが、コンパイル時のオプションで -g を付けるなり、実行時エラーを出力させるようにすると、エラーの起きた行番号などが示されるので、それをみて原因を追究できるはずです。

しかしながら、入力ファイル二列目をソートしてそれに従って一列目を並べ替えるとすると、今のルーチンのままでは配列を一つしか渡しておらず二列目しか操作していないので、エラーを取り除いても目的は達せられないと思います。

データ数や実行回数にもよりますが、より簡便なソートアルゴリズムを用いる方法もあります。K&R の C の本に載っている shell sort を流用した例を示します。shell sort は gap の取り方で性能を上げられるのですが、ここでは素朴な性能イマイチな方法を取っています。(なお再帰を使わないので FORTRAN77 でも使えるという利点がありますw)

昇順に並べます。sample.txt は、既にソート済みだったのでイマイチチェックになりませんでした。

fortran

1module shell_sort 2 implicit none 3contains 4 subroutine shell(x, y) ! shell sort 5 real(8), intent(in out) :: x(:), y(:) 6 real(8) :: tmp 7 integer :: i, j, igap 8 igap = size(x) 9 do while(igap > 0) 10 do i = igap, size(x) 11 do j = i - igap, 1, -igap 12 if ( x(j) > x(j + igap) ) then 13 tmp = x(j) 14 x(j) = x(j + igap) 15 x(j + igap) = tmp 16 tmp = y(j) 17 y(j) = y(j + igap) 18 y(j + igap) = tmp 19 end if 20 end do 21 end do 22 igap = igap / 2 23 end do 24 end subroutine shell 25end module shell_sort 26 27program test 28 use shell_sort 29 implicit none 30 real(8), allocatable :: x(:), y(:) 31 integer :: i 32 33 allocate(x(75), y(75)) 34 open(10, file = 'sample.txt') 35 36 do i = 1, 75 37 read(10, *) y(i), x(i) 38 end do 39 40 call shell(x, y) 41 42 do i = 1, 75 43 print *, x(i), y(i) 44 end do 45 46 ! sort check 47 !call random_number(x) 48 !y = [(i, i = 1, size(y))] 49 !call shell(x, y) 50 51 print *, all(x(:size(x)-1)<x(2:)) 52 53end program test

投稿2021/06/03 15:54

curehoney

総合スコア249

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kanso

2021/06/04 05:27

回答ありがとうございます。 自分もよく分からないで使っていたのですが real(8), intent(in out) :: x(:), y(:)などの配列の次元のところに:を入れるのは どういった意味があるのでしょうか?教えていただきたいです。
curehoney

2021/06/04 06:17

(:)の意味は、x や y が一次元配列の引き数であることを宣言しています。x(:,:) ならば二次元配列であることを示します。 サイズを明示的に渡さなくてもいい利点があります。
kanso

2021/06/07 06:14

サイズを示さなくていいんですね。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問