0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

いにしえのFortran 問題集

Last updated at Posted at 2020-09-27

大学でFortran95を使うことがあったので、教材で配布されている問題を解いてみた。

環境はMacのVSCodeでModern Fortranを使って行った。

Fortran文法の基礎

------memo------は初心者の方に役立つかもしれない情報を載せた

まだ授業が終わってなく提出コードが酷似するのを防ぐため
きちんと動くが不細工なコードになるように変更した

変数名abcは各自で変更しろという箇所

問題 (2.2.1) 2 つの実数を読み込み、加減乗除を出力する。

Fortran.f90
program abc
    implicit none
    real abc1,abc2,abc
    print *, "abc1を入力してください"
    read(*,*) abc1
    print *, "abc2を入力してください"
    read(*,*) abc2
    abc = abc1 + abc2
    print *, "abc1 + abc2 = ", abc
stop
end program abc

------memo------
printとwriteはほとんど同じ しかし、writeはファイルの書き込みが可能なのでwriteで統一するべきかも
readは入力された値を変数に代入する
realは実数 integerは整数
numとはnumberの略、数値を代入する際よく使われる

問題 (2.2.2) 実数 a と b を読み込んで、a と b の算術平均(i.e., 足して2で割る)と幾何平均(i.e., 積のルート)を計算するプログラムを作成せよ。

大学の教授たちは何故わかりにくい言葉を使いたがるのか謎だが、
この問題をわかりやすくすると、
step1. 実数a,bを読み込む
step2. a,bの平均を求めよ
step3. a,bの積のルートを求めよ

Fortran.f90
program abc
    implicit none
    real abc1,abc2,abc3,abc4
    print *, "abc1を入力してください"
    read(*,*) abc1
    print *, "abc2を入力してください"
    read(*,*) abc2
    abc3 = (abc1 + abc2) / 2
    abc4 = (abc1 * abc2) ** 0.5
    print *, "平均値", abc3
    print *, "積のルート", abc4
stop
end program abc

------memo------
sum()などあると思ったが、なさそう(自分で関数を作るのか?)なので普通に作った。
追記 配列に入れsumする方法があった

問題 (2.2.3) x を入力し、1/(2+2x+x^2) を出力する。

Fortran.f90
program hello
    real abc,abc2,abc3,abc4
    print *, "abcを入力してください"
    read(*,*) abc
    abc2 = 2 * abc
    abc3 = abc ** 2
    abc4 = 1/(2+abc2+abc3)
    print *, "1/(2+2abc+abc^2) = ", abc4 
stop
end program hello

------memo------
割り算がある為、実数のrealを使用
わかりやすいようにtwoTimeとsquareに分けた

問題 (2.2.4) x 時 y 分 z 秒から k 時 m 分 n 秒まで何秒あるかを計算する。

発展問題

Fortran.f90
program hello
    implicit none
    integer hour1,hour2,min1,min2,sec1,sec2
    print *, "時、分、秒を順番に入力してください"
    read(*,*) hour1,min1,sec1
    print *, "差分を求めたい 時、分、秒を順番に入力してください"
    read(*,*) hour2,min2,sec2

    sec1 = (hour1 * 3600) + (min1 * 60) + sec1 !時間,分を全て秒に変換
    sec2 = (hour2 * 3600) + (min2 * 60) + sec2

    sec1 = abs(sec1 - sec2) !絶対値

    hour1 = int(sec1 / 3600) !秒から時間へ
    sec1 = modulo(sec1,3600) !時間を引いた秒

    min1 = int(sec1 / 60)
    sec1 = modulo(sec1,60)

    print *, "差分は",hour1,"時間",min1,"分",sec1,"秒"
stop
end program hello

------memo------
時間、分を秒数に変換するという発想がミソ
入力形式を hh : mm : ss にしたかったが、めんどくさそうだったのでやめた

問題 (2.3.1) 2 次方程式 ax^2 + bx + c = 0 の係数 a,b,c を読み込んで、その根を表示する。

Fortran.f90
program hello
    implicit none
    real a,b,c,ansPlus,ansMinus,d
    print *, "a,b,cの値を順番に入力してください"
    read(*,*) a,b,c
    if (a == 0) then
        ansPlus = c / b
        print *, "x = ",ansPlus
    else
        d = b**2 - 4*a*c
        if (d >= 0) then
            ansPlus = (-b + sqrt(d)) / 2*a
            ansMinus = (-b - sqrt(d)) / 2*a
            print *, "x = ",ansPlus,",",ansMinus
        else 
            print *, "虚数解です"
        end if
    end if
stop
end program hello

------memo------
解の公式を使用する
a = 0 の時の条件文を追加

問題 (3.1) 整数 n から整数 m までの和を計算する。

Fortran.f90
program hello
    implicit none
    integer total,n,m,i
    print *, "整数n,整数mを順番に入力してください"
    read (*,*) n,m
    if (n > m) then 
        total = m
        m = n
        m = total
    end if
    total = 0
    do i = n, m
        total = total + i
    end do
     print *, "和は",total
stop
end program hello

------memo------
for文で n > mの時の対応
ループ文で nからmまでm-n+1回ループする

問題 (3.2) 関数 y = x^2の x = x1 から x = x2 までの範囲で、積分を計算する。xy 平面の y = x^2のグラフの下の部分の面積を、x について微小区間(幅がΔx)の矩形の和として求めよ。x1x2 、およびΔx は標準入力から読み込む。

難しい言葉が出てきて頭痛い
整理すると
step.1 x1,x2,Δx を読み込む
step.2 x1からx2までの範囲でy = x^2 を積分するが,
step.3 積分する際の長方形の面積幅を使用する形で積分せよ
ということなのか??

積分とは長方形の面積の和である
積分.png
例えば3から5までの区間をΔx = 1で という問題だったら
x = 3の時y = x^2 より y = 9 長方形の面積は 91
x = 4の時y = x^2 より y = 16 長方形の面積は 16
1
よって面積の和は25

長方形よりも台形にした方が誤差は小さくなるのでは?と思うが。。。

矩形(クケイ)-> 連続する自然数の積 長方形数、長方数 とも呼ばれる

Fortran.f90
program hello
    implicit none
    real x1,x2,delX,ans
    print *, "x1,x2,Δxを順番に入力してください"
    read (*,*) x1,x2,delX
    ans = 0
    if (x1 < x2) then                     !x2がx1より大きくないか確認
        if (x2 - x1 > delX ) then         !Δxが大きすぎないか確認
            do while (x1 /= x2)           !x1 == x2になるまでループ
                if (x1 > x2) then         
                    delX = x2 - (x1 - delX) !x1がx2より大きくなった場合残りの面積を求める
                end if
                ans = ans + ((x1 ** 2) * delX) !長方形の面積を足していく
                x1 = x1 + delX            !長方形の座標を変える
            end do
        else
            print *, "ERROR [内容:Δxの値が大きすぎます]"
        end if
    else 
        print *, "ERROR [内容:x2よりx1が大きいです]"
    end if
    print *, "面積は",ans
    
stop
end program hello

------memo------
とりあえず解けたが問題文の解釈間違いで間違っている気がする。。。
アルゴリズムの考え方というより数学的な考え方

問題 (4.1) 問題 (2.3.1) での2次方程式を解く問題で、解が虚根になるときは、そのことを述べて終わるように改良する。

Fortran.f90

問題 4.2 自然対数の底 e を、精度 10^-5 で求めよ。ここで、写真.1を利用せよ。

写真.1スクリーンショット 2020-04-17 17.57.19.png

Fortran.f90
program hello
    implicit none
    real num,count,accuracy,ans_e
    num = 1 ! 階乗の計算
    count = 0 !分母の数字
    accuracy = 10 ** 5 !精度
    ans_e = 1 !eの計算 
    do while (num <= accuracy ) ! 分母だけ考える
        count = count + 1 ! 分母の数字を1増やす
        num = num * count ! 分母の階乗の値を求める
        ans_e = ans_e + (1/num) ! 計算
    end do
    print *, "自然対数eの値は e = " , ans_e , "[精度は10^-5]"
stop
end program hello

気分が向いたら更新予定

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?