プログラムの穴埋め問題になります。解き方を見ていきましょう。
問題
次のプログラム中の に入れる正しい答えを,解答群の中から選べ。二
つの には,同じ答えが入る。ここで,配列の要素番号は 1 から始まる。
Unicode の符号位置を,UTF-8 の符号に変換するプログラムである。本問で数値の
後ろに“(16)”と記載した場合は,その数値が 16 進数であることを表す。
Unicode の各文字には,符号位置と呼ばれる整数値が与えられている。UTF-8 は,
Unicode の文字を符号化する方式の一つであり,符号位置が 800(16) 以上 FFFF(16)
以下の文字は,次のように 3 バイトの値に符号化する。
3 バイトの長さのビットパターンを 1110xxxx 10xxxxxx 10xxxxxx とする。ビット
パターンの下線の付いた“x”の箇所に,符号位置を 2 進数で表した値を右詰めで格
納し,余った“x”の箇所に,0 を格納する。この 3 バイトの値が UTF-8 の符号であ
る。
例えば,ひらがなの“あ”の符号位置である 3042(16) を 2 進数で表すと
11000001000010 である。これを,上に示したビットパターンの“x”の箇所に右詰め
で格納すると,1110xx11 10000001 10000010 となる。余った二つの“x”の箇所に 0
を格納すると,“あ”の UTF-8 の符号 11100011 10000001 10000010 が得られる。
関数 encode は,引数で渡された Unicode の符号位置を UTF-8 の符号に変換し,先
頭から順に 1 バイトずつ要素に格納した整数型の配列を返す。encode には,引数と
して,800(16) 以上 FFFF(16) 以下の整数値だけが渡されるものとする。
![](https://www.xn--4grr4jzer0z13b8ydc6hw8c14slx0cfdtdwftp3d.website/wp-content/uploads/2024/02/スクリーンショット-2024-02-10-20.44.21.png)
解答群
ア ((4 - i) × 2)
イ (2 の (4 - i)乗)
ウ (2 の i 乗)
エ (i × 2)
オ 2
カ 6
キ 16
ク 64
ケ 256
解き方
まずは問題文にも書いてるこの関数encodeのやりたいことを整理してみます。
関数encodeで何をしたいのか?
「あ」という文字の文字コードをUnicodeからUTFに変更したいということですね。これは2進数でも表現できるということが問題にも書かれていますのでそれを抜き出してみます。
Unicode:11000001000010
UTF-8 :11100011 10000001 10000010
関数encodeにUnicodeの値を入れたらUTF-8の値になるプログラムということですね。
ではどのようにしたら変更できるのか?これも問題文に解説があります。以下のビットパターンのx部分にUnicodeのビット列を右詰で当てはめるということです。
1110xxxx 10xxxxxx 10xxxxxx
確かにUnicodeを当てはめてみると変換できることが確認できると思います。
プログラムをトレース
それではプログラムをトレースしていきます。
codePoint=11000001000010(Unicode)
utf8bytes={224,128,128}
↑を計算しやすいように2進数に変換すると
utf8bytes={11100000, 10000000, 10000000}
となります。
cp=11000001000010
for文でiは3から1に1ずつ変化します。
utf8Bytes[i] ← utf8Bytes[i] + (cp ÷ 〇〇の余り)
↑今回の問題のここが鍵です。これが何をやっているかをみてみましょう。
utf8Bytes[i] ← utf8Bytes[i] + (cp ÷ の余り)
これは前述のビットパターンに当てはめるという操作をしています。具体的に書くと10xxxxxxに000010(Unicodeの下6桁)を当てはめたいのです。そして〇〇に何が入るかを考えれば良いわけですね。
cpの下6桁を取り出すには?
ここでシフト演算が使えます。論理右シフトをすると1ビット右にずらすごとに2のマイナスべき乗ずつ割り算ができましたね。
→1/2 →1/4 →1/8 →1/16 →1/32 →1/64
つまり11000001000010を64で割ると11000001.000010になります。この時000010は余りですね。
これで下6桁が取り出せました。
つまり答えはクの64になります。
シフト演算を10進数でやってみる
前述のシフト演算の部分は慣れないと腹落ちして理解するのが難しいと思いますので10進数で考えてみましょう。
まず10進数でもシフト演算はできるんです。
10を左に一つずらすと100で10倍
10000を右に1つずらすと1000で1/10です。
10000を右に2つずらすと100で1/100になりますよね。
こうしてみるとシフト演算が2新数でもできることが繋がるのではないでしょうか。
そして余りの部分も確認してみましょう。
2102141を右に3つずらしてみます。これは10進数での右論理シフトで3つずれた形になりますね。また10進数で3つずらすということは1000で割るとも言えますよね。
2102141÷1000=2102余り141
余りが取り出せました。このような形でシフト演算を使って余りを取り出すことができます。utf8Bytes[i] ← utf8Bytes[i] + (cp ÷ 〇〇の余り)この式はまさにこのシフト演算で余りを取り出すということを行なっていたわけです。
総括
今回の問題はまだ続きがありますがメインの考え方と答えはここまででわかったと思います。cp←cp÷〇〇の商という部分もシフト演算した残りの桁をまた使いまわすための動きですね。
科目bではこういった複数の知識を組み合わせて解決するという問題が多いです。トレースもよく使いますので繰り返し練習しておくのがおすすめです。
コメントを残す