前回の記事で、AWK を使ってどのように分数の約分ができるのか、ということをやりました。
今回は、引き続き足し算と引き算をさせてみようと思います。
前回のまとめ
以下のようにして約分を行いました。詳しい方針は過去記事をご覧ください
$ echo 6/8 | tr '/' '\n' | factor |\ awk 'NR == 1{for(i=2; i<=NF; i++){a[$i] += 1}} NR == 2{for(i=2; i<=NF; i++){a[$i] -= 1}}; END{nume = 1; deno = 1; for(b in a){if (a[b] > 0){nume *= b**a[b]} else if (a[b] < 0){deno *= b**(-1*a[b])}} {print nume"/"deno}}' 3/4
AWK で分数計算を行なってみる
AWK で分数の足し算引き算を実装します
目標
Input: 1/2 ± 1/3 (など)
Output: 答え
一例
適時計算結果を表示させることで解説としたいと思います。
# awk で区切り文字" " として扱うために前処理 $ echo '1/3 + 1/6' | tr '/' ' ' 1 3 + 1 6 # ここでは半角スペースで区切られていることが大事なので、 ## 1/3+1/6 のような入力にも対応したければ、以下を挟む $ echo '1/3+1/6' | sed -E 's@([0-9])([^ /0-9])([0-9 ])@\1 \2 \3@' 1/3 + 1/6 # 計算を行う。真ん中の符号が + か - かで場合分け $ echo '1/3 + 1/6' | tr '/' ' ' |\ awk '$3 == "+"{print ($1*$5 + $2*$4)"/"($2 * $5)}; $3 == "-"{print ($1*$5 - $2*$4)"/"($2 * $5)}' 9/18 # 前回の訳文の結果を使えるように渡してあげる $ echo '1/3 + 1/6' | tr '/' ' ' |\ awk '$3 == "+"{print ($1*$5 + $2*$4)"/"($2 * $5)}$3 == "-"{print ($1*$5 - $2*$4)"/"($2 * $5)}' |\ tr '/' '\n' | factor |\ awk 'NR == 1{for(i=2; i<=NF; i++){a[$i] += 1}} NR == 2{for(i=2; i<=NF; i++){a[$i] -= 1}}; END{nume = 1; deno = 1; for(b in a){if (a[b] > 0){nume *= b**a[b]} else if (a[b] < 0){deno *= b**(-1*a[b])}} {print nume"/"deno}}' # マイナスも試してみます $ echo '1/3 - 1/6' | tr '/' ' ' | awk '$3 == "+"{print ($1*$5 + $2*$4)"/"($2 * $5)}$3 == "-"{print ($1*$5 - $2*$4)"/"($2 * $5)}' | tr '/' '\n' | factor | awk 'NR == 1{for(i=2; i<=NF; i++){a[$i] += 1}} NR == 2{for(i=2; i<=NF; i++){a[$i] -= 1}}; END{nume = 1; deno = 1; for(b in a){if (a[b] > 0){nume *= b**a[b]} else if (a[b] < 0){deno *= b**(-1*a[b])}} {print nume"/"deno}}' 1/6
おまけ
これまた Ruby なら一瞬です
$ echo '1/3 + 1/6' |\ sed -E 's@^([0-9]+/[0-9]+)[ ]?\+[ ]?([0-9]+/[0-9]+)@puts \1r+\2r@g' |\ ruby 1/2
おわりに
だいぶ AWK を使ったけいさんにも慣れてきたかと思います。
AWK に頼らないで生活できるよう目指していきたいです。