メインコンテンツ

非正規浮動小数点

結果が非正規になる浮動小数点演算

説明

このチェックでは、浮動小数点演算の結果が非正規になるかどうかを判別します。

非正規数とは、仮数部の上位桁に 0 を付けずに表現できる最小の浮動小数点数よりも小さな値のことです。非正規数の存在は有効桁数が失われることを示します。この損失はそれ以降の演算に累積し、最終的には予期しない値につながります。非正規数は、ハードウェアのサポートがないターゲットでの実行速度を低下させる可能性もあります。

既定では、このチェックの結果は検証結果に表示されません。チェックの結果を表示するには、オプション非正規検出モード (-check-subnormal)の既定値を変更します。チェックの結果は、指定した検証モードに応じて変化します。[allow] 以外のすべてのモードで非正規結果を特定するには、[非正規浮動小数点] チェックがレッドまたはオレンジになる演算を検索します。

モードチェックの色チェック後の動作

forbid:

このモードでは、非正規値の出現が検出されます。このモードでは、結果が非正規になる実行パスが停止され、非正規値がそれ以上伝播しなくなります。したがって、実際には、最初に出現した非正規数のみが表示されます。

チェックの色は、演算の結果のみに依存します。チェックでは、このような結果が非正規オペランドからのみ発生する場合でも、結果が非正規になる演算にフラグが付けられます。

たとえば、x が不明の場合、x は非正規になる可能性があるため、x * 2 も非正規になる可能性があります。このチェックの結果はオレンジになります。

チェックはブロックされます。

チェックがレッドの場合、検証が停止されます。チェックがオレンジの場合、検証では非正規結果を含む実行パスが考慮対象から除外されます。たとえば、結果のツールヒントには非正規値が示されません。

warn-all:

このモードでは、非正規値の出現箇所がすべて強調表示されます。結果が非正規となった原因がそれ以前の非正規値にある場合でも、その結果が強調表示されます。

チェックの色は、演算の結果のみに依存します。チェックでは、このような結果が非正規オペランドからのみ発生する場合でも、結果が非正規になる演算にフラグが付けられます。

たとえば、x が不明の場合、x は非正規になる可能性があるため、x * 2 も非正規になる可能性があります。このチェックの結果はオレンジになります。

チェックはブロックされません。

チェックがレッドになっても、検証が続行されます。チェックがオレンジの場合、検証では非正規結果を含む実行パスは考慮対象から除外されません。

warn-first:

このモードでは、最初に出現した非正規値が強調表示されます。非正規値がそれ以降の演算結果に非正規値を伝播させている場合、このような後続の結果は強調表示されません。

チェックの色は、演算結果とオペランド値に依存します。チェックでは、結果が非正規オペランドからのみ発生する場合には、結果が非正規になる演算にフラグが付けられません。

このモードのチェックは次のようになります。

  • レッド、ソフトウェアで考慮されるすべての実行パスで演算結果が非正規になる場合で、オペランドが非正規ではない場合。

  • オレンジ、オペランドが非正規でないときに一部の実行パスの演算結果が非正規になる場合。

    たとえば、x が不明の場合、x が非正規でない場合でも、x * 0.5 が非正規になる可能性があります。

  • グリーン、オペランドが非正規である場合を除いて、演算結果が非正規にならない場合。

    たとえば、x が不明の場合でも、x が非正規である場合を除いて、x * 2 が非正規になる可能性はありません。

チェックはブロックされません。

チェックがレッドになっても、検証が続行されます。チェックがオレンジの場合、検証では非正規結果を含む実行パスは考慮対象から除外されません。

非正規のチェックを選択する場合、変数の範囲から非正規値が除外されるかどうかをツールヒントから特定することもできます。たとえば、ツールヒントによって [-1.0 .. -1.1754E-38] or [-0.0..0.0] or [1.1754E-38..1.0] と表示される場合、変数は非正規値にはならないと解釈できます。

すべて展開する

次の例の DBL_MIN は、double 型で表すことのできる最小の正規値です。

forbid モードでの結果:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
この例では、DBL_MIN/4.0 の結果が非正規になるため、最初の [非正規浮動小数点] チェックはレッドになります。レッド チェックにより、検証は停止されます。次の演算 val * 2.0 のランタイム エラーは検証されません。

warn-all モードでの結果:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
この例では、両方の演算結果が非正規になるため、どちらの [非正規浮動小数点] チェックもレッドになります。

warn-first モードでの結果:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
この例では、DBL_MIN は非正規ではありませんが、DBL_MIN/4.0 の結果は非正規になります。最初の [非正規浮動小数点] チェックはレッドになります。2 番目の [非正規浮動小数点] チェックはグリーンになります。これは、val が非正規になることによってのみ val * 2.0 が非正規になるためです。レッド/オレンジ チェックでは、非正規値になる最初の出現箇所のみが表示されます。これらの非正規値がそれ以降の演算に伝播してもレッド/オレンジ チェックは表示されません。

次の例の arg1arg2 は不明です。検証では、これらが double 型で許容されるすべての値を取り得ると仮定されます。

forbid モードでの結果:

void func (double arg1, double arg2) {
	  double difference1 = arg1 - arg2;
	  double difference2 = arg1 - arg2;
	  double val1 = difference1 * 2;
	  double val2 = difference2 * 2;
}
この例では、arg1arg2 がきわめて近い値の場合、difference1 は非正規になる可能性があります。最初の [非正規浮動小数点] チェックはオレンジになります。このチェックの後の検証では、以下が検討対象から除外されます。

  • arg1arg2 が近い値で、それが原因で difference1 の結果が非正規値になる場合。

    それ以降の演算 arg1 - arg2[非正規浮動小数点] チェックはグリーンになり、difference2 は非正規にはなりません。difference2 * 2 のチェック結果は、同じ理由でグリーンになります。

  • difference1 が非正規値の場合。

    それ以降の演算 difference1 * 2[非正規浮動小数点] チェックはグリーンになります。

warn-all モードでの結果:

void func (double arg1, double arg2) {
	  double difference1 = arg1 - arg2;
	  double difference2 = arg1 - arg2;
	  double val1 = difference1 * 2;
	  double val2 = difference2 * 2;
}

この例では、4 つの演算結果が非正規になる可能性があります。この 4 つの [非正規浮動小数点] チェックはオレンジになります。

warn-first モードでの結果:

void func (double arg1, double arg2) {
	  double difference1 = arg1 - arg2;
	  double difference2 = arg1 - arg2;
	  double val1 = difference1 * 2;
	  double val2 = difference2 * 2;
}
この例では、arg1arg2 がきわめて近い値の場合、difference1difference2 は非正規になる可能性があります。最初の 2 つの [非正規浮動小数点] チェックはオレンジになります。difference1difference2 が非正規になる場合を除いて、val1val2 が非正規になる可能性はありません。最後の 2 つの [非正規浮動小数点] チェックはグリーンになります。レッド/オレンジ チェックでは、非正規値になる最初の出現箇所のみが表示されます。これらの非正規値がそれ以降の演算に伝播してもレッド/オレンジ チェックは表示されません。

void main() {
    float d = 1e-38;	
    float e = 1e-38 - 1e-39; 
}

この例では、warn-first および warn-all モードの両方で 2 つのレッド チェックが表示されます (forbid モードは最初のレッド チェック以降の解析を妨げます)。

1e-38 などのリテラル定数は、データ型 double を持ちます。リテラル定数を範囲のより狭い float 型の変数に代入する場合、定数をその型で表現できない可能性があります。この問題は、レッド チェックで示されます。チェックでは、代入中の double から float への変換にフラグを設定します。

結果情報

グループ: 数値
言語: C | C++
頭字語: SUBNORMAL

バージョン履歴

R2016b で導入