2020年09月12日
川俣晶の縁側ソフトウェアC# コーディング How Tototal 1411 count

【入門級】マイナス計算が値を変化させないとき

Written By: 川俣 晶連絡先

マイナス計算が値を変化させないとき §

 文字列-1234567890を整数に変換することは可能です。int.TryParseメソッドなどを使います。正しい数値になります。これの符号を反転すると1234567890になります。期待通りです。

 しかし、-2147483648の場合は違います。期待通りの結果にならず値が変化しません。マイナスは付いたママです。

 なぜでしょうか。

実は起きているオーバーフロー §

 C#などで使用されている2の補数表現の負数の有効範囲は、実はマイナス側で一つ多いという特徴があります。つまり、-2147483648は扱えても+2147483648は扱えないのです。

 ですから、実はマイナス計算を行った時点でオーバーフローが起きています。

 オーバーフローが起きると正しい結果になりません。

対策はなんだ? §

 対策は2種類あります。

 一つはint型ではなくlong型を使って桁数を増やす方法。

 もう1つはcheckedコンテキストで実行させ、オーバーフローの存在を検出して実行を止め

る方法です。

 サンプルソースでは後者の方法でオーバーフローを検出する例が最後にあります。

罠の数々 §

  • 一般的にその型の表現できる境界上の値は避けた方が安全である。オーバーフロー、アンダーフローが起こりやすいし、判定を誤る可能性もある
  • そうは言っても符号なしの数値型で0は使いたい。符号なしの数値型では0から1を引いても-1にならないので注意して扱おう
  • checkedコンテキスト/uncheckedコンテキストは知っておく価値がある。意図しない計算結果が出るときは、checkedコンテキストで実行するとどこで間違ったか例外が教えてくれることがある
  • メモリを節約するために、よりビット幅の小さい型を使いたいのはよくあることだが、それをやると意図しないオーバーフローが発生しがちである

参考リンク §

整数数値型 (C# リファレンス)

Int32.TryParse メソッド

Int32.MaxValue フィールド

Int32.MinValue フィールド

checked (C# リファレンス)

unchecked (C# リファレンス)

 int型でこれ以上先に行ったら正常に処理できない限界値はInt32.MaxValue フィールドとInt32.MinValue フィールドに明示されている。かなり大きな値なのでそう簡単にはそこまでいかないと思うかも知れないが、計算中に値が膨れあがって限界を超えることもある。どの値まで有効なのか確認しておこう。また自動チェックさせたいときはchecked文を使う。合わせてチェックしておこう。しかし、わざとオーバーフローさせてオーバーフロー分を無視するテクニックもある。一時的にチェック機能を停止させるにはuncheckedだ。これも確認しておこう。

リポジトリ §

https://github.com/autumn009/cshowto

Negative §

using System;

class Program

{

    private static void parseAndNegative(string s)

    {

        int.TryParse(s, out int v);

        Console.Write(v);

        Console.Write(">>>>");

        v = -v;

        Console.WriteLine(v);

    }

    private static void parseAndNegativeChecked(string s)

    {

        try

        {

            int.TryParse(s, out int v);

            Console.Write(v);

            Console.Write(">>>>");

            checked

            {

                v = -v;

            }

            Console.WriteLine(v);

        }

        catch (OverflowException)

        {

            Console.WriteLine("Overflow");

        }

    }

    static void Main()

    {

        parseAndNegative("-1234567890");

        parseAndNegative("-2147483648");

        parseAndNegativeChecked("-2147483648");

    }

}

実行結果

-1234567890>>>>1234567890

-2147483648>>>>-2147483648

-2147483648>>>>Overflow

Facebook

COOL C# CREW

C#ハウツー連載の解説増量、カラーのソース、新規書き下ろし追加の読みやすい単行本はこちら。

C#ハウツー: 逆引き入門・こんな機能はどう書くの?
キーワード【 川俣晶の縁側ソフトウェアC# コーディング How To
【C# コーディング How To】の次のコンテンツ
2020年
09月
13日
【入門級】簡単なfor文がハングアップするとき
3days 0 count
total 938 count
【C# コーディング How To】の前のコンテンツ
2020年
09月
11日
【入門級】0で割っても例外が起きないことがある?
3days 0 count
total 1444 count

このコンテンツを書いた川俣 晶へメッセージを送る

[メッセージ送信フォームを利用する]

メッセージ送信フォームを利用することで、川俣 晶に対してメッセージを送ることができます。

この機能は、100%確実に川俣 晶へメッセージを伝達するものではなく、また、確実に川俣 晶よりの返事を得られるものではないことにご注意ください。

このコンテンツへトラックバックするためのURL

https://mag.autumn.org/tb.aspx/20200912091909
サイトの表紙【C# コーディング How To】の表紙【C# コーディング How To】のコンテンツ全リスト 【C# コーディング How To】の入手全リスト 【C# コーディング How To】のRSS1.0形式の情報このサイトの全キーワードリスト 印刷用ページ

管理者: 川俣 晶連絡先

Powered by MagSite2 Version 0.36 (Alpha-Test) Copyright (c) 2004-2021 Pie Dey.Co.,Ltd.