高度情報システム科 ブログ
最優秀賞者のプログラム精解!(その2)
2018.12.15
Javaプログラミングコンテスト最優秀賞者のプログラムを見てみよう、第2弾です。
ネットワーク関連の問題の要点部は「文字列 str にIPv4アドレスがサブネットマスクのサフィックス付きで与えられたときに、ネットワークアドレスとブロードキャストアドレスを表示する」のが目標です。
前回の時点で、IPアドレスの上位から8ビットずつをint型のa、b、c、dに代入し、サブネットマスク(サフィックス値)をzに代入しました。
ここから、ネットワークアドレスを求めていきます。
int ip = (a << 24) + (b << 16) + (c << 8) + d;
ipに、IPアドレスを数値として入れました。
"<<"はシフト演算。
c << 8は、cを左に8ビットシフトした値になります。左に1ビットシフトすると2倍になるので、8ビットシフトすると256倍になります。
このあたり、知っていればどうってことはないのですが、一度は覚えていてもいざ使おうとなるとできるかどうか・・・。
ついつい、c * Math.pow(2, 8) とか b * Math.pow(2, 16)とやってしまいそうな気がします。
ipに32ビットの整数値を格納しましたが、int型は32ビットなので大丈夫です。
ここも、余裕を持ってlong型にしようとか考えそうになりますが、値として持てればいい、つまり正負の符号などを考えなくていいのでint型がぴったりですね。
同様にしてサブネットマスクを求めてint型にし、ipと論理積(&)をとればネットワークアドレスが求まります!
といきたいところですが、最優秀者のコードは違いました。
char[] ipc = Integer.toBinaryString(ip).toCharArray();
ipを一旦、2進数文字列に変換し、char型の配列に格納します。
さらに
for (int i = 31; i >= z; i--) ipc[i] = '0';
としました。
考えてみれば、ipを2進表記したときに下位zビットを0にセットするだけでいいですね。
当たり前のことですが、ネットワークアドレスを求めるときにサブネットマスクと論理積をとる、というふうに覚えているとこうした簡単なことに気づきづらいものです。
ついついまともにやってしまいそう・・・。
こうしてあっさり求めたネットワークアドレスを数値に戻します。
a = b = c = d = 0;
for (int i = 0; i < 8; i++) {
a += (ipc[i] - '0') << (7 - i);
b += (ipc[i + 8] - '0') << (7 - i);
c += (ipc[i + 16] - '0') << (7 - i);
d += (ipc[i + 24] - '0') << (7 - i);
}
プログラムは、それを作った人の思考経路が透けて見えるので面白いです。
たとえばaにはipアドレスの上位8ビットを入れたいのですが、各ビットはchar型の配列に'0'か'1'として入っているので、これを一旦数値に変換します。
このとき、char型は内部的に整数値になっているので、ipc[i] - '0'のように引き算ができます。'0'の次が'1'になっているので、これにより'0'は0に、'1'は1になります。
さらに最上位ビットであれば128倍、つまり左に7ビットシフトします。2番目のビットであれば、左に6ビットシフトし、…となるので、for文で繰り返し処理します。
そしてこれらを足し合わせるためにa += (右辺)としています。これはa = a + (右辺)と同じで、aに(右辺)を加えていくという意味になります。
これで数値に変換されますが、この部分は他にもいろいろなやり方がありそうです。
あとは表示するだけ。
System.out.println(a + "." + b + "." + c + "." + d);
見事でした。
もう一つのブロードキャストアドレスも、同じようにできそうですね。
詳しくは次回!