戦国IT - 情報処理技術者試験の過去問対策サイト
お知らせお問い合わせ料金プラン

応用情報技術者 2023年 春期 午後03


多倍長整数の演算に関する次の記述を読んで、設問に答えよ。

 コンピュータが一度に処理できる整数の最大桁には、CPUが一度に扱える情報量に依存した限界がある。一度に扱える桁数を超える演算を行う一つの方法として、10を基数とした多倍長整数(以下、多倍長整数という)を用いる方法がある。   〔多倍長整数の加減算〕  多倍長整数の演算では、整数の桁ごとの値を、1の位から順に1次元配列に格納して管理する。例えば整数123は、要素数が3の配列に{3、2、1}を格納して表現する。  多倍長整数の加算は、“桁ごとの加算”の後、“繰り上がり”を処理することで行う。456+789を計算した例を図1に示す。
応用情報技術者試験(令和5年度 午後 問03 図01)
 “桁ごとの加算”を行うと、配列の内容は{15、13、11}となる。1の位は15になるが、15は10×1+5なので、10の位である13に1を繰り上げて{5、14、11}とする。これを最上位まで繰り返す。最上位で繰り上がりが発生する場合は、配列の要素数を増やして対応する。減算も同様に“桁ごとの減算”と“繰り下がり”との処理で計算できる。   〔多倍長整数の乗算〕  多倍長整数の乗算については、計算量を削減するアルゴリズムが考案されており、その中の一つにカラツバ法がある。ここでは、桁数が2のべき乗で、同じ桁数をもつ正の整数同士の乗算について、カラツバ法を適用した計算を行うことを考える。桁数が2のべき乗でない整数や、桁数が異なる整数同士の乗算を扱う場合は、上位の桁を0で埋めて処理する。例えば、123×4は0123×0004として扱う。   〔ツリー構造の構築〕  カラツバ法を適用した乗算のアルゴリズムは、計算のためのツリー構造(以下、ツリーという)を作る処理と、ツリーを用いて演算をする処理から成る。ツリーは、多倍長整数の乗算の式を一つのノードとし、一つのノードは 3 個の子ノードをもつ。  M 桁×M 桁の乗算の式について、乗算記号の左右にある値を、それぞれ M/2 桁ずつに分けて A、B、C、D の四つの多倍長整数を作る。これらの整数を使って、①A×C、②B×D、③(A+B)×(C+D) の 3 個の子ノードを作り、M/2 桁×M/2 桁の乗算を行う層を作る。(A+B)、(C+D) は多倍長整数の加算の結果であるが、ここでは “桁ごとの加算” だけを行い、“繰り上がり” の処理はツリーを用いて行う演算の最後でまとめて行う。生成した子ノードについても同じ手順を繰り返し、1 桁×1 桁の乗算を行う最下層のノードまで展開する。  1234×5678 についてのツリーを図2に示す。図2の層 2 の場合、①は 12×56、②は 34×78、③は 46×134 となる。③の (C+D) は、“桁ごとの加算” だけの処理を行うと、10 の位が 5+7=12、1 の位が 6+8=14 となるので、12×10+14=134 となる。
応用情報技術者試験(令和5年度 午後 問03 図02)
〔ツリーを用いた演算〕  ツリーの最下層のノードは、整数の乗算だけで計算できる。最下層以外の層は、子ノードの計算結果を使って、次の式で計算できることが分かっている。ここで、α、β、γ は、それぞれ子ノード①、②、③の乗算の計算結果を表す。K は対象のノードの桁数を表す。
   ……(1)
 図2のルートノードの場合、k=4、α=672、β=2652、γ=6164 なので、計算結果は次のとおりとなる。
     〔多倍長整数の乗算のプログラム〕  桁数が2のべき乗の多倍長整数 val1, val2 の乗算を行うプログラムを作成した。  プログラム中で利用する多倍長整数と、ツリーのノードは構造体で取り扱う。構造体の型と要素を表1に示す。構造体の各要素には、構造体名.要素名でアクセスできる。また、配列の添字は1から始まる。
応用情報技術者試験(令和5年度 午後 問03 表01)
 多倍長整数の操作を行う関数を表2に、プログラムで使用する主な変数、配列及び関数を表3に、与えられた二つの多倍長整数からツリーを構築するプログラムを図3に、そのツリーを用いて演算を行うプログラムを図4に、それぞれ示す。表2, 表3中の p, q, v1, v2 の型は多倍長整数である。また、図3, 図4中の変数は全て大域変数である。
応用情報技術者試験(令和5年度 午後 問03 表02)
応用情報技術者試験(令和5年度 午後 問03 表03)
応用情報技術者試験(令和5年度 午後 問03 図03)
応用情報技術者試験(令和5年度 午後 問03 図04)

設問1

図2中のに入れる適切な字句を答えよ。

模範解答

ア:3×7 イ:4×12

解説

解答の論理構成

  1. 図2の層2のノード「34×78(B×D)」を分割
    【問題文】では、子ノード生成の手順を
    「①A×C、②B×D、③(A+B)×(C+D) の 3 個の子ノードを作り…」
    と示しています。また分割は “M/2 桁” 単位で行い、桁ごとの加算では繰り上がりをしません。
    • 34 の values 配列は {4, 3}、左 1 桁が 3、右 1 桁が 4。
      → A=3、B=4
    • 78 の values 配列は {8, 7}、左 1 桁が 7、右 1 桁が 8。
      → C=7、D=8
      よって子ノード①は 3×7、②は 4×8、③は (3+4)×(7+8) となります。
      図中で②・③は既に表示されているので、空欄 には①の 3×7 が入ります。
  2. 図2の層2のノード「46×134(((A+B)×(C+D)))」を分割
    • 46 の values 配列は {6, 4}、左 1 桁が 4、右 1 桁が 6。
      → A=4、B=6
    • 134 は “繰り上がり前” の結果なので values 配列は {14, 12}
      (1 の位が 14, 10 の位が 12 で桁数は 2 のまま)。
      → C=12、D=14
      子ノード①は 4×12、②は 6×14、③は (4+6)×(12+14)=10×26 です。
      図中で②・③は表示済みのため、空欄 には①の 4×12 が入ります。
  3. 以上より
    ア:3×7
    イ:4×12

誤りやすいポイント

  • “桁ごとの加算”後に繰り上がりをしないため、134 のように 2 桁のまま値が 10 以上になるケースを見落としやすいです。
  • values 配列は下位桁が添字 1 である点を忘れ、left(p, 1) と right(p, 1) を取り違えると A・B、C・D の割り当てが逆になります。
  • Karatsuba 法の子ノード①②③の順序(A×C、B×D、(A+B)×(C+D))を覚え違えると、図の空欄に別の式を書いてしまいます。

FAQ

Q: “134” が 3 桁に見えるのに桁数 2 のまま扱われるのはなぜですか?
A: 【問題文】にあるとおり、(C+D) は “桁ごとの加算” だけを行い “繰り上がり” を後回しにするため、10 の位に 12, 1 の位に 14 を保持したまま 2 桁で管理します。
Q: 子ノード③の (A+B)×(C+D) の計算結果はいつ繰り上がり処理をしますか?
A: ツリー全体の計算が終わったあと、図4の最後で carry() を呼び出すタイミングで一括して繰り上げ・繰り下げを行います。
Q: 左右で桁数が異なるときはどう考えますか?
A: 【問題文】に「上位の桁を0で埋めて処理する」とあるとおり、短い方を 0 埋めして同じ桁数(2 のべき乗)にそろえてから分割します。

関連キーワード: 多倍長整数, カラツバ法, 桁ごとの加算, 繰り上がり処理, ツリー構造

設問2

図2中の層2にある46×134のノードについて、本文中の式(1)の数式は具体的にどのような計算式になるか。次の式の①~④に入れる適切な整数を答えよ。   ( ① ) × 100 + (( ② ) - ( ③ ) - 84) × 10 + ( ④ )

模範解答

①:48 ②:260 ③:48 ④:84

解説

解答の論理構成

  1. カラツバ法の子ノード作成
    【問題文】には
    「乗算記号の左右にある値を、それぞれ M/2 桁ずつに分けて A、B、C、D の四つの多倍長整数を作る」
    とある。
    ノード「46×134」は M=2(values 配列の要素数が 2)なので M/2=1。
    • 46(values={6,4})
      • A=left(46,1)=4
      • B=right(46,1)=6
    • 134(values={14,12})
      • 134 は 56+78 の“桁ごとの加算”結果であり、繰り上がり未処理なので
        下位桁が 14、上位桁が 12 で 2 桁扱いになる点に注意。
      • C=left(134,1)=12
      • D=right(134,1)=14
  2. 各子ノードの計算
    同一ノード内での子ノードは
    「① A×C、② B×D、③ (A+B)×(C+D)」
    と定義されている(【問題文】より)。
    • …… これが α
    • …… これが β
      • (繰り上がりはまだ行わない)
      • よって …… これが γ
  3. ルート式への代入
    ツリー計算では【問題文】の式
    α×10^k + (γ-α-β)×10^{k/2} + β ……(1)
    を各ノードに適用する。
    今回は k=2(2 桁)なので

    したがって


    α=48, γ=260, α=48, β=84 を代入すると

    となり、設問の空欄は
    ①48, ②260, ③48, ④84 で確定する。

誤りやすいポイント

  • 「桁ごとの加算」をした直後の多倍長整数では 要素が 9 を超えてもそのまま にするルールを忘れ、134 を「1・3・4」と思い込んで分割を誤る。
  • M/2 桁で分けるときに 配列添字の大きい方が“左” になることを取り違え、A・B と C・D を逆に設定してしまう。
  • (γ-α-β) の計算順序を勘違いし、(α+β-γ) にしてしまう。

FAQ

Q: なぜ 134 の下位桁が 14 になるのですか?
A: 134 は 56 と 78 を “桁ごとの加算” だけで足した結果です。1 の位は 6+8=14、10 の位は 5+7=12 となり、繰り上がりは最後まで行わないため values 配列は {14,12} になります。
Q: 子ノードの数が 3 個なのはなぜですか?
A: カラツバ法では 2 つの乗算を 3 つに分割して計算量を削減するため、各ノードは必ず①A×C、②B×D、③(A+B)×(C+D) の 3 子ノードを生成します。
Q: k と k/2 の 10 乗を掛ける理由は?
A: ①と②で求めた部分積は元の桁位置に戻す必要があります。高位の部分積 α は 10^k 倍、中央の調整項 (γ-α-β) は 10^{k/2} 倍、低位の部分積 β はそのまま加えることで元の桁揃えを実現します。

関連キーワード: カラツバ法, 桁ごとの加算, 多倍長整数, 繰り上がり処理

設問3

図3中のに入れる適切な字句を答えよ(オとカは順不同)。

模範解答

ウ:pow(3,i-1) エ:3*(i-1) オ:pe.val1 カ:pe.val2

解説

解答の論理構成

  1. 【問題文】の図3では、層ごとの先頭インデックス layer_top[] を決めるために
    layer_top[i + 1] ← layer_top[i] +
    とあります。ルート層の要素数は 1、その次の層は子ノードが 3 個ずつなので 3^1、
    さらにその次は 3^2 … と増えていきます。
    したがって には “現在の層の要素数”=pow(3, i − 1) が入ります。
  2. 子ノード①の格納位置 tidx を求める行は
    tidx ← layer_top[dp + 1] +  // 子ノード①へのインデックス
    親ノード i が 1 なら子①は次層の先頭、2 ならその 3 つ後ろ… という規則なので
    オフセットは 3*(i − 1) です。ゆえに は 3*(i-1) となります。
  3. 子ノード生成3行では、親ノード pe の左右半分を渡します。
    elements[tidx ] ← new_elem(cn, left(, cn), left(, cn)) elements[tidx + 1] ← new_elem(cn, right(, cn), right(, cn)) elements[tidx + 2] ← new_elem(cn, lradd(, cn), lradd(, cn))
    val1 と val2 を左右に分割するので には
    親ノードが保持する多倍長整数
    pe.val1 pe.val2
    がそのまま入ればよいことが分かります(順序は左辺・右辺で使い分けるため順不同可)。
  4. 以上より
    • ウ:pow(3,i-1)
    • エ:3*(i-1)
    • オ:pe.val1
    • カ:pe.val2
      が解答となります。

誤りやすいポイント

  • 層の要素数を 3*dp と誤認する
    (実際には累乗:pow(3, dp − 1))。
  • 子ノードの格納位置を i3 で計算し、1 ずれに気付かない
    (インデックスは 1 から始まるので 3
    (i − 1) が正)。
  • に left(pe.val1, cn) のような部分結果を直接書いてしまう
    (分割は new_elem 内で行われる)。
  • pow() と shift() を混同し、10 の冪乗と 3 の冪乗を取り違える。

FAQ

Q: layer_top[] 計算でなぜ累乗を使うのですか?
A: 各ノードが必ず 3 つの子を持つため、層 i のノード数は で表せます。これを足し込むことで次層の先頭インデックスを効率的に求めています。
Q: left() と right() の引数に pe.val1 ではなく結果を入れても動作しそうですが?
A: 動作はしますが冗長です。new_elem() の内部で再度分割する必要がなくなり、設計意図に沿う最短の書き方が pe.val1 と pe.val2 です。
Q: の式を pow(3,1)(i-1) と書いても良いですか?
A: 数値的には同じですが、冗長です。問題意図は “3 の固定倍” を明示する 3
(i-1) です。

関連キーワード: カラツバ法, 多倍長整数, 再帰分割, インデックス計算, 三分木

設問4

図4中のに入れる適切な字句を答えよ。

模範解答

キ:mod(mul, 10) ク:elements[cidx + 2] ケ:elements[cidx]

解説

解答の論理構成

  1. 【問題文】の「最下層のノードは、整数の乗算だけで計算できる。」に従い、mul は 1 桁×1 桁の積です。
    1 の位を取り出すには剰余演算が必要で、表 3 の関数
    「mod(m, k) … m を k で割った剰余を整数で返す。」
    が用意されています。したがって
    el.result.values[1] ← mod(mul, 10)
    が [キ] となります。
  2. カラツバ法の再帰計算式 (1) で α, β, γ を「子ノード①, ②, ③の乗算の計算結果」と定義しています。
    ・cidx は「子ノード①へのインデックス」を指しているので
    elements[cidx] が α
    elements[cidx + 1] が β
    elements[cidx + 2] が γ です。
  3. s1 ← sub( [ク].result, [ケ].result ) は γ−α を作る処理、
    続く s2 ← sub(s1, elements[cidx + 1].result) で −β を加えて
    γ−α−β が完成します。よって
    ・[ク] には γ を表す elements[cidx + 2]
    ・[ケ] には α を表す elements[cidx]
    を当てはめれば所望の差分が得られます。
以上より
  • キ:mod(mul, 10)
  • ク:elements[cidx + 2]
  • ケ:elements[cidx]
が正答となります。

誤りやすいポイント

  • shift と sub の順序を取り違え、α×10^k と (γ−α−β)×10^{k/2} を逆に配置してしまう。
  • 表 3 のインデックスは 1 始まり。cidx + 2 を 2 と誤読し 0 起算で実装すると γ と β が入れ替わる。
  • mod(mul, 10) を使わず mul − (mul / 10)*10 などと書いてしまい、字句指定に反して減点される。
  • sub(p, q) は “桁ごとの減算” を行うだけで繰り下げが未処理。carry() を呼ばないと中間値が負の桁を持つことに気付かずバグを出す。

FAQ

Q: どうして elements[cidx + 2] が γ だと分かるのですか?
A: 図 3 のツリー生成で「elements[tidx + 2] ← new_elem(cn, lradd(...))」とあり、lradd は (A+B) と (C+D) の乗算、すなわち式 (1) の γ に対応すると明記されています。
Q: 1 桁×1 桁の積が 2 桁になる根拠は?
A: 9×9=81 が最大ですから、必ず 2 桁以内で収まります。【問題文】にも「el.result.N ← 2 // 計算結果は2桁」と固定で確保しています。
Q: carry() を最後に一度だけ呼ぶ理由は?
A: カラツバ法の途中計算では“桁ごとの加算・減算”だけを実施し、繰り上がり・繰り下がりは全体をまとめて処理した方が回数を削減できるためです。【問題文】「“繰り上がり” の処理はツリーを用いて行う演算の最後でまとめて行う。」とあります。

関連キーワード: 多倍長整数, カラツバ法, 剰余演算, 繰り上がり処理, ツリー構造

設問5

N桁同士の乗算をする場合、多倍長整数の構造体において、配列valuesに必要な最大の要素数は幾つか。Nを用いて答えよ。

模範解答

2 × N

解説

解答の論理構成

  1. 【問題文】では「多倍長整数の演算では、整数の桁ごとの値を、1の位から順に1次元配列に格納して管理する」とあります。
    ➜ 1つの桁につき values 配列に1要素を割り当てる設計です。
  2. N 桁の最大値は です。同様にもう一方も だとすると、積の最大値は

    となり、 未満です。
  3. ちょうど 2N 桁まで しか取りません。したがって、N 桁同士を掛けた結果が 2N+1 桁へ繰り上がることはありません。
  4. values 配列には結果の全桁を格納できる必要があるので、最大要素数は
これが模範解答「2 × N」と一致します。

誤りやすいポイント

  • 繰り上がりを 1 桁余分に見積もって「2N+1」と考えてしまう。
    しかし でも を超えないので誤りです。
  • 基数 10 の話を見落とし、ビット数換算で要素数を計算してしまう。
  • 「ツリー構造の途中で一時的に桁が増えるのでは?」と心配するケース。
    子計算の結果も最大 2N 桁以内に収まるため追加要素は不要です。

FAQ

Q: 最上位での carry 処理でさらに 1 桁増えることはありませんか?
A: N 桁×N 桁の最大積は なので、carry を行っても 2N 桁以内に収まります。
Q: 片方が N 桁、もう片方が N−1 桁の場合はどうなりますか?
A: 本問題では「桁数が2のべき乗で、同じ桁数をもつ正の整数同士の乗算」を前提にしています。桁数が異なるときは上位を 0 で埋め、結局 N 桁同士の乗算と同じ扱いになります。
Q: 配列を動的確保する実装なら要素数を気にしなくて良いのでは?
A: 試験の設問は「必要な最大の要素数」を理論上求めるものです。実装が動的か静的かに関わらず、上限を把握しておくことが重要です。

関連キーワード: 多倍長演算, 桁あふれ, 10進基数, 乗算アルゴリズム
戦国ITクイズ機能

\ せっかくなら /

応用情報技術者
クイズ形式で学習しませんか?

クイズ画面へ遷移する

すぐに利用可能!

©︎2026 情報処理技術者試験対策アプリ

このサイトについてプライバシーポリシー利用規約特商法表記開発者について