いにしえのFortran　問題集

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

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

[Fortran文法の基礎](http://www.fml.t.u-tokyo.ac.jp/~izumi/sotsuron/FORTRAN_lecture.pdf)

------**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., 足して２で割る）と幾何平均（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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/83ef4754-3a48-41a9-d299-2f4c88a72a0c.png)
例えば3から５までの区間をΔx = 1で　という問題だったら
x = 3の時y = x^2 より y = 9 長方形の面積は 9*1
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) での２次方程式を解く問題で、解が虚根になるときは、そのことを述べて終わるように改良する。

```Fortran.f90

```

####問題 4.2 自然対数の底 e を、精度 10^-5 で求めよ。ここで、写真.１を利用せよ。
写真.1<img width="132" alt="スクリーンショット 2020-04-17 17.57.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517291/8f198011-7e79-ee16-5d25-ea0d0f2dbaf5.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 ! 分母の数字を１増やす
        num = num * count ! 分母の階乗の値を求める
        ans_e = ans_e + (1/num) ! 計算
    end do
    print *, "自然対数eの値は e = " , ans_e , "[精度は10^-5]"
stop
end program hello
```

気分が向いたら更新予定