🧩今日の学び
・奇数件の中央値では、件数を2で割った商をそのまま位置にすると1つ手前にずれるため、余りがある場合はLOW-POSに1を加える必要がある。
・5 ÷ 2のような簡単な例を手で計算し、商・余り・LOW-POS・HIGH-POSを表にすると、コードだけでは見えにくい規則やミスを発見しやすい。
・「動きそう」「考え方は合っている」で終わらせず、偶数・奇数など条件を変えて実行し、結果を目で確認するところまでがプログラム設計と検証の一部になる。
なるお)んー、とりあえず…
係長)わかったか?
な)パンケーキ食ってきていいす?
係)なんで「行ってこい!」っていうと思ってるんだよ!!
な)えー、ねっとりシロップを食べることで、甘いという欲求と食べたいという欲求を同時に満たせるんですよ!
係)だからなんで「食べに行って良し」になるんだよ!
いいから、さっさと考えろよ!
な)むー
奇数のときだけ中央値が1つずれている
な)偶数は正解で、奇数が間違ってたんだから…そこら辺かな?
だから、そこら辺ってどこなのよ…と
COUNT=05 LOW-POS=02 HIGH-POS=02 MEDIAN IS 00900.0
COUNT = 5だからそれはOKで、両POSが02じゃなくて03になるはずだから、ここになるのかしら
DIVIDE COUNT-LOOPING BY 2 GIVING LOW-POS
REMAINDER REMAIND.
IF REMAIND = 0
COMPUTE HIGH-POS = LOW-POS + 1
ELSE
COMPUTE HIGH-POS = LOW-POS
END-IF.
COUNTが偶数のときはこうだから
IF REMAIND = 0
COMPUTE HIGH-POS = LOW-POS + 1
偶数は+1するのはいいでしょー
奇数のときはこうだっつーんだから
ELSE
COMPUTE HIGH-POS = LOW-POS
同じで良いわけでしょう??
なんで、一つ少なくなったわけなのかしら…
係)お前偶数と奇数の違いは理解したから、その考えになってるんだよな?
な)あ、あい…
割り切れない計算は頭の中だけで考えない
係)考え方は理解した、それを頭の中だけで計算してるのか?
切り捨てが絡む割り算は暗算に向かないぞ。
な)ほ?
係)偶数はど真ん中の前後の平均、奇数はど真ん中そのものだが、割り切れないだろ?
だったら、どうなるんだ?
な)え…と…
係)だから、頭の中で考えるな、手を使って計算してみろ。
な)あい…
5÷2の商は2だから奇数では1を戻す
な)んー、カウントが5だとして、半分のところになるわけだから、3だよね…
1 2 [3] 4 5
これを出すには5を2で割るんでしょ??
あれ?
んーと、割り切れないんってことだからして?
うーん…そっか!
5 / 2は2.5だから、商が2で1足りないわけだから、LOW-POSに1足すと割り切れて、それがそのまま中央値のカウント数字になるからして、これでどうだっての、これで!
DIVIDE COUNT-LOOPING BY 2 GIVING LOW-POS
REMAINDER REMAIND.
IF REMAIND = 0
COMPUTE HIGH-POS = LOW-POS + 1
ELSE
ADD 1 TO LOW-POS ← 追加
COMPUTE HIGH-POS = LOW-POS
END-IF.
つまり、割り切れないから、商としては1つ少なくなっちゃうと。
だから、それを戻してあげないといけないってわけっすね!
係)そうだ。
良いか、1 + 1といった足し算ぐらいなら暗算でも間違えることは少ないが、割り算とくに、余りが出るといったときの処理は生活で使うわけでもないからな、あまり使ってこない。
表にすれば偶数・奇数の規則が見えてくる
係)お前ならめんどくさいとか思うだろうが、こういうときは、頭の中で暗算するんじゃなく、表に起こしてしまえ。
今回であればこういう形だな。
| 件数 | 商 | 余 | LOW | HIGH |
|---|---|---|---|---|
| 1 | 0 | 1 | 1 | 1 |
| 2 | 1 | 0 | 1 | 2 |
| 3 | 1 | 1 | 2 | 2 |
| 4 | 2 | 0 | 2 | 3 |
| 5 | 2 | 1 | 3 | 3 |
| 6 | 3 | 0 | 3 | 4 |
間違いだと気づかずに進めてしまうと、何が間違いだったのかは気が付きづらい。
そうなると、どこにその部分があるかが探しづらい。
単純なミスほど早い段階で目で確認する
だから最初の段階で単純なミスを絶対に犯さないように、めんどくさがらずに、きちんと目で確認しろ。
くだらないミスで泣きをみるのはお前自身だからな。俺は知らんからな。
な)あい…
係)よし、それじゃ、そこ直して実行してみろ。
な)あい…
IDENTIFICATION DIVISION.
PROGRAM-ID. NARUO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT INPUT-FILE
ASSIGN TO "naruo2.txt"
ORGANIZATION IS LINE SEQUENTIAL.
SELECT SORT-FILE
ASSIGN TO "sortwork.tmp".
SELECT OUTPUT-FILE
ASSIGN TO "naruo2_sorted.txt"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD INPUT-FILE.
01 INPUT-RECORD.
05 INPUT-SALE-DATE PIC X(10).
05 INPUT-ITEM-NAME PIC X(20).
05 INPUT-AMOUNT PIC 9(5).
SD SORT-FILE.
01 SORT-RECORD.
05 SORT-SALE-DATE PIC X(10).
05 SORT-ITEM-NAME PIC X(20).
05 SORT-AMOUNT PIC 9(5).
FD OUTPUT-FILE.
01 OUTPUT-RECORD.
05 OUTPUT-SALE-DATE PIC X(10).
05 OUTPUT-ITEM-NAME PIC X(20).
05 OUTPUT-AMOUNT PIC 9(5).
WORKING-STORAGE SECTION.
01 EOF-FLAG PIC X VALUE "N".
01 COUNT-LOOPING PIC 9(2) VALUE 0.
01 READ-COUNT PIC 9(2) VALUE 0.
01 REMAIND PIC 9 VALUE 0.
01 LOW-POS PIC 9(2) VALUE 0.
01 HIGH-POS PIC 9(2) VALUE 0.
01 LOW-VAL PIC 9(5) VALUE 0.
01 HIGH-VAL PIC 9(5) VALUE 0.
01 MEDIAN-VAL PIC 9(5)V9 VALUE 0.
PROCEDURE DIVISION.
SORT SORT-FILE
ON ASCENDING KEY SORT-AMOUNT
USING INPUT-FILE
GIVING OUTPUT-FILE.
OPEN INPUT OUTPUT-FILE.
PERFORM UNTIL EOF-FLAG = "Y"
READ OUTPUT-FILE
AT END
MOVE "Y" TO EOF-FLAG
NOT AT END
IF OUTPUT-AMOUNT IS NUMERIC
AND OUTPUT-AMOUNT > 0
ADD 1 TO COUNT-LOOPING
END-IF
END-READ
END-PERFORM.
CLOSE OUTPUT-FILE.
DIVIDE COUNT-LOOPING BY 2 GIVING LOW-POS
REMAINDER REMAIND.
IF REMAIND = 0
COMPUTE HIGH-POS = LOW-POS + 1
ELSE
ADD 1 TO LOW-POS
COMPUTE HIGH-POS = LOW-POS
END-IF.
OPEN INPUT OUTPUT-FILE.
MOVE "N" TO EOF-FLAG.
PERFORM UNTIL EOF-FLAG = "Y"
READ OUTPUT-FILE
AT END MOVE "Y" TO EOF-FLAG
NOT AT END
IF OUTPUT-AMOUNT IS NUMERIC
AND OUTPUT-AMOUNT > 0
ADD 1 TO READ-COUNT
IF READ-COUNT = LOW-POS
MOVE OUTPUT-AMOUNT TO LOW-VAL
END-IF
IF READ-COUNT = HIGH-POS
MOVE OUTPUT-AMOUNT TO HIGH-VAL
END-IF
END-IF
END-READ
END-PERFORM.
CLOSE OUTPUT-FILE.
COMPUTE MEDIAN-VAL = (LOW-VAL + HIGH-VAL) / 2.
DISPLAY "COUNT=" COUNT-LOOPING
" LOW-POS=" LOW-POS " HIGH-POS=" HIGH-POS.
DISPLAY "MEDIAN IS " MEDIAN-VAL.
STOP RUN.
奇数でも正しい中央値!ついに完成
どうよ!プリーズ!
COUNT=05 LOW-POS=03 HIGH-POS=03 MEDIAN IS 01500.0
どうよ!サンキュー!
係)お前の情緒がわからん…
な)できたんじゃないんすか!これ!
おむすび
係)ま、これでいいだろ。ようやく完成だな…ほんと長かった…。
な)こっちのセリフですよ!
係)なんでだよ!
な)でも、あざんした(ペコ
係)な、なんだよ、殊勝だな…気持ち悪い…
な)ひど!いっつもそうっすよ!ふざけてるとかうるさいとか気持ち悪いとか!
そんなのわかってますから、わかってやってますから!残念でしたー!
係)どんなキレかたしてんだよ!
な)今度クーニャンいきますからね!絶対ですよ!
係)わかったよ…。
ま、よくやったよ。
な)え!?褒められた!?え、だれ!?え、なに気持ち悪い!?
係)ふ、ふ、ふざけんな!
(書きシリーズ 第一部完)
係長のワンポイント
計算ロジックは「頭の中で正しそう」では完成じゃない。
本当は、簡単な数字を手で並べて、結果の規則が合っているか確認するところまでが設計だ。
よくある誤解は、割り算の商をそのまま位置として使えると思うことだが、奇数では余りが出るぶん1つずれる。
だから5 ÷ 2のような小さな例を実際に書き、商・余り・LOW・HIGHの関係を表で確認する。
その結果、単純なミスを早い段階で見つけ、後の大きな手戻りを防げる。
COBOLは頭の中だけで組む言語ではなく、手を使って確かめながら正しさを積み上げる言語だ。

コメント