2021-05-21に投稿

負の数の剰余(^~^)

20210124shogi2a2b1.png
「 👇 AtCode の有志が書いた練習問題解いてたら、次のような細かな話しが載ってたぜ」

📖 D - 1.03.四則演算と優先順位

E15-XEjUUAEu2WK.jpg

kifuwarabe-futsu.png
「 いや、それより早く問題を解けだぜ、お父ん」

ohkina-hiyoko-futsu.png
「 剰余の結果の正負は、割られる数の正負の符号に揃うだけなんじゃないの?」

 5 %  3 =  2    // ?
-5 %  3 = -2    // ?
 5 % -3 =  2    // ?
-5 % -3 = -2    // ?

ramen-tabero-futsu2.png
「 👆 つまり こう?」

20210521math64.png

kifuwarabe-futsu.png
「 👆 コードテストでは そうなってるな」

📖 -5%3

20210521math65.png

 5 %   3  =  2    // ?
-5 %   3  =  1    // ?
 5 % (-3) = -1    // ?
-5 % (-3) = -2    // ?

ramen-tabero-futsu2.png
「 👆 Wolfram Alpha とは一部異なるぜ」

ohkina-hiyoko-futsu.png
「 現場に合わせればいいのよ」

ramen-tabero-futsu2.png
「 C++ で負の剰余をそう定義したことと、 Wolfram Alpha が負の剰余をそう定義したことで、
どのような都合の良さを取って、どのような都合の悪さを取らなかったのか 気になるぜ」

kifuwarabe-futsu.png
「 お父んが練習問題サボってるのが 気になるぜ」

20210521math66a1.png

ramen-tabero-futsu2.png
「 👆 剰余とは カマボコ のようなものだぜ」

kifuwarabe-futsu.png
「 お父んの空間には 食べ物がよく置いてある」

20210521math66a3.png

ramen-tabero-futsu2.png
「 👆 5 を 3人ずつに分けたら 2 余るぜ」

ohkina-hiyoko-futsu.png
「 1 を 3人で分けなさいよ。作戦負けよ」

kifuwarabe-futsu.png
「 では、 ー5 を 3人で分けてくれだぜ」

20210521math66a4.png

ramen-tabero-futsu2.png
「 👆 これが、 ー5 を 3人ずつに分けたら ー2 余るという C++の主張だぜ」

ohkina-hiyoko-futsu.png
「 存在しないカマボコを取り合ってる3人 わらう」

kifuwarabe-futsu.png
「 自然な解釈のように見えるが……」

20210521math66a7.png

ramen-tabero-futsu2.png
「 👆 これが、 ー5 を 3人ずつに分けたら 1 余るという Wolfram Alpha の主張だぜ」

ohkina-hiyoko-futsu.png
「 存在しないカマボコが なぜ突然 現れたの?」

20210521math66a8.png

ramen-tabero-futsu2.png
「 👆 もし 6枚のカマボコがあるとして ー5 すれば 1 余るだろ、という理屈だぜ」

kifuwarabe-futsu.png
「 6枚のカマボコがある、ということにするのは 無理攻めな気がするぜ」

20210521math66a9.png

ramen-tabero-futsu2.png
「 👆 C++ の主張では、
 8枚のカマボコを3人で分けたら  2余る。
 5枚のカマボコを3人で分けたら  2余る。
ー5枚のカマボコを3人で分けたら ー2余るぜ」

kifuwarabe-futsu.png
「 そうだぜ」

20210521math67a1.png

ramen-tabero-futsu2.png
「 👆 Wolfram Alpha の主張を理解するために、らせん状に重ねたカマボコを考えてみようぜ?」

kifuwarabe-futsu.png
「 好きにやってくれだぜ」

20210521math68.png

ramen-tabero-futsu2.png
「 👆 5 を 3 で割ったら 2 余るぜ」

20210521math68a1.png

ramen-tabero-futsu2.png
「 👆 -5 を 3 で割ったら 1 余るぜ」

kifuwarabe-futsu.png
「 フーム 別に 分かりやすくはならなかったぜ」

ohkina-hiyoko-futsu.png
「 2個余ってるか、1個足りないか の違いなのよね」

kifuwarabe-futsu.png
「 じゃ、 5 を -3人で分けてくれだぜ」

20210521math66a10.png

ramen-tabero-futsu2.png
「 👆 C++の主張としては、3で割ろうが、ー3で割ろうが、余りは変わらん ということだぜ」

kifuwarabe-futsu.png
「 直観に従うぜ」

20210521math68a2.png

ramen-tabero-futsu2.png
「 👆 Wolfram Alpha の方は 3で割るか、-3で割るかで 結果が違ってくるぜ」

kifuwarabe-futsu.png
「 Wolfram Alpha の方は何をやってるか分からん」

📖 D - 1.03.四則演算と優先順位

より正確に言うと、C++の剰余演算子は(A / B) * B + (A % B)とAが等しくなるように定義されており、結果的にAの正負と一致します。

ohkina-hiyoko-futsu.png
「 👆 これは何のことを言ってるの?」

ramen-tabero-futsu2.png
「 みんなで食べたカマボコと、余り を足せば、元のカマボコに戻るだろ、という式だぜ。
具体的な数を入れて 計算してみようぜ?」

20210521math69.png

ramen-tabero-futsu2.png
「 👆 図で描けば こうだな。
割り算が小数点切捨てになってるのが コンピューターの独特な所だぜ」

A = 5
B = 3

  ( A / B ) * B + ( A % B )
= ( 5 / 3 ) * 3 + ( 5 % 3 )
= (   1   ) * 3 + (   2   )
=           4   + (   2   )
=               5

ramen-tabero-futsu2.png
「 👆 合ってるな」

kifuwarabe-futsu.png
「 他のパターンもやれだぜ」

A = -5
B =  3

  (  A / B ) * B + (  A % B )
= ( -5 / 3 ) * 3 + ( -5 % 3 )
= (   -1   ) * 3 + (   -2   )    # -5 % 3 は定義から -2
=           -3   + (   -2   )
=               -5

ramen-tabero-futsu2.png
「 👆 合ってるな」

kifuwarabe-futsu.png
「 まだ2パターン残ってるぜ」

A =  5
B = -3

  ( A /  B ) *  B + ( A %  B )
= ( 5 / -3 ) * -3 + ( 5 % -3 )
= (  -1    ) * -3 + (   2    )    # -5 % 3 は定義から 2
=            3    + (   2    )
=                 5

ramen-tabero-futsu2.png
「 👆 合ってるな」

kifuwarabe-futsu.png
「 らすいち」

A = -5
B = -3

  (  A /  B ) *  B + (  A %  B )
= ( -5 / -3 ) * -3 + ( -5 % -3 )
= (    1    ) * -3 + (   -2    )    # -5 % -3 は定義から -2
=            -3    + (   -2    )
=                 -5

ramen-tabero-futsu2.png
「 👆 合ってるな」

ohkina-hiyoko-futsu.png
「 Wolfram Alpha の方も 見ておきましょう!」

A = -5
B =  3

  (  A / B ) * B + (  A % B )
= ( -5 / 3 ) * 3 + ( -5 % 3 )
= (   -1   ) * 3 + (    1   )    # -5 % 3 は定義から 1
=           -3   + (    1   )
=               -2

ramen-tabero-futsu2.png
「 👆 合わないぜ」

kifuwarabe-futsu.png
「 Wolfram Alpha がなぜ?」

ramen-tabero-futsu2.png
「 むむむむ……」

📖 Modulo operation

ramen-tabero-futsu2.png
「 👆 なんてこった。 負の剰余には、2種類ぐらい 良い方法があるらしいぜ。
ユークリッド除法 と、 ドナルド・クヌースの切り下げ除算

📖 Modulo of Negative Numbers

mod(a, n) = a - n * floor(a / n)

ramen-tabero-futsu2.png
「 👆 ドナルド・クヌースのやり方を真似てみるか」

A = -5
B =  3

   A - B * floor(  A / B )
= -5 - 3 * floor( -5 / 3 )
= -5 - 3 *          -2        # 負の無限大の方へ切り下げる
= -5 +   6
=    1

ramen-tabero-futsu2.png
「 👆 あひゃあ! 1 だ!」

kifuwarabe-futsu.png
「 1 だぜ!」

ohkina-hiyoko-futsu.png
「 他のパターンも見てみましょう!」

A =  5
B = -3

  A -  B * floor( A /  B )
= 5 - -3 * floor( 5 / -3 )
= 5 - -3 *         -2         # 負の無限大の方へ切り下げる
= 5 -    6
=  -1

ramen-tabero-futsu2.png
「 👆 なんと ー1 だぜ!」

kifuwarabe-futsu.png
「 Wolfram Alpha は ドナルド・クヌースの切り下げ除算を使っているのかだぜ?
らすいち も見てみようぜ!」

A = -5
B = -3

   A -  B * floor(  A /  B )
= -5 - -3 * floor( -5 / -3 )
= -5 - -3 *           1         # 負の無限大の方へ切り下げる
= -5 -   -3
=   -2

ramen-tabero-futsu2.png
「 👆 ー2 だな」

ohkina-hiyoko-futsu.png
「 何がいいのか 分かんないわね!」

ramen-tabero-futsu2.png
「 あー、 C++ の方法だと 計算の途中で 自己言及 があるが、
ドナルド・クヌースの方は 自己言及 がないんで、 好きな人は好きな定義だな」

kifuwarabe-futsu.png
「 しかし お父んの らせんのカマボコ では 何も納得できない……」

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント