Main Content

Subnormal float

Floating-point operation has subnormal results

Description

This check determines if a floating-point operation produces a subnormal result.

Subnormal numbers have magnitudes less than the smallest floating-point number that can be represented without leading zeros in the significand. The presence of subnormal numbers indicates loss of significant digits. This loss can accumulate over subsequent operations and eventually result in unexpected values. Subnormal numbers can also slow down the execution on targets without hardware support.

By default, the results of the check do not appear in your verification results. To see the results of the check, change the default value of the option Subnormal detection mode (-check-subnormal). The results of the check vary based on the detection mode that you specify. In all modes other than allow, to identify the subnormal results, look for red or orange Subnormal float checks on operations.

ModeCheck ColorsBehavior Following Check

forbid:

This mode detects the occurrence of a subnormal value. This mode stops the execution path with the subnormal result and prevents subnormal values from propagating further. Therefore, in practice, you see only the first occurrence of the subnormal value.

The color of the check depends only on the result of the operation. The check flags an operation that has subnormal results even if those results come only from subnormal operands.

For instance, if x is unknown, x * 2 can be subnormal because x can be subnormal. The result of the check is orange.

Blocking check.

If the check is red, the verification stops. If the check is orange, the verification removes the execution paths containing the subnormal result from consideration. For instance, the tooltip on the result does not show the subnormal values.

warn-all:

This mode highlights all occurrences of subnormal values. Even if a subnormal result comes from previous subnormal values, the result is highlighted.

The color of the check depends only on the result of the operation. The check flags an operation that has subnormal results even if those results come only from subnormal operands.

For instance, if x is unknown, x * 2 can be subnormal because x can be subnormal. The result of the check is orange.

Non-blocking check.

The verification continues even if the check is red. If the check is orange, the verification does not remove the execution paths containing the subnormal result from consideration.

warn-first:

This mode highlights the first occurrence of a subnormal value. If a subnormal value propagates to further subnormal results, those subsequent results are not highlighted.

The check color depends on the result of the operation and the operand values. The check does not flag a subnormal result if it comes only from subnormal operands.

In this mode, the check is:

  • Red, if the operation produces subnormal results on all execution paths that the software considers, and the operands are not subnormal.

  • Orange, if the operation produces subnormal results on some of the execution paths when the operands are not subnormal.

    For instance, if x is unknown, x * 0.5 can be subnormal even if x is not subnormal.

  • Green, if the operation does not produce subnormal results unless the operands are subnormal.

    For instance, even if x is unknown, x * 2 cannot be subnormal unless x is subnormal.

Non-blocking check.

The verification continues even if the check is red. If the check is orange, the verification does not remove the execution paths containing the subnormal result from consideration.

If you choose to check for subnormals, you can also identify from the tooltips whether a variable range excludes subnormal values. For instance, if the tooltips show [-1.0 .. -1.1754E-38] or [-0.0..0.0] or [1.1754E-38..1.0], you can interpret that the variable does not have subnormal values.

Examples

expand all

In the following examples, DBL_MIN is the minimum normal value that can be represented using the type double.

Results in forbid mode:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
In this example, the first Subnormal float check is red because the result of DBL_MIN/4.0 is subnormal. The red check stops the verification. The following operation, val * 2.0, is not verified for run-time errors.

Results in warn-all mode:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
In this example, both Subnormal float checks are red because both operations have subnormal results.

Results in warn-first mode:

#include <float.h>

void func(){
    double val = DBL_MIN/4.0;
    double val2 = val * 2.0;
}
In this example, DBL_MIN is not subnormal but the result of DBL_MIN/4.0 is subnormal. The first Subnormal float check is red. The second Subnormal float check is green. The reason is that val * 2.0 is subnormal only because val is subnormal. Through red/orange checks, you see only the first instance where a subnormal value appears. You do not see red/orange checks from those subnormal values propagating to subsequent operations.

In the following examples, arg1 and arg2 are unknown. The verification assumes that they can take all values allowed for the type double.

Results in forbid mode:

void func (double arg1, double arg2) {
	  double difference1 = arg1 - arg2;
	  double difference2 = arg1 - arg2;
	  double val1 = difference1 * 2;
	  double val2 = difference2 * 2;
}
In this example, difference1 can be subnormal if arg1 and arg2 are sufficiently close. The first Subnormal float check is orange. Following this check, the verification excludes from consideration the following:

  • The close values of arg1 and arg2 that led to the subnormal value of difference1.

    In the subsequent operation arg1 - arg2, the Subnormal float check is green and difference2 is not subnormal. The result of the check on difference2 * 2 is green for the same reason.

  • The subnormal value of difference1.

    In the subsequent operation difference1 * 2, the Subnormal float check is green.

Results in warn-all mode:

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

In this example, the four operations can have subnormal results. The four Subnormal float checks are orange.

Results in warn-first mode:

void func (double arg1, double arg2) {
	  double difference1 = arg1 - arg2;
	  double difference2 = arg1 - arg2;
	  double val1 = difference1 * 2;
	  double val2 = difference2 * 2;
}
In this example, if arg1 and arg2 are sufficiently close, difference1 and difference2 can be subnormal. The first two Subnormal float checks are orange. val1 and val2 cannot be subnormal unless difference1 and difference2 are also subnormal. The last two Subnormal float checks are green. Through red/orange checks, you see only the first instance where a subnormal value appears. You do not see red/orange checks from those subnormal values propagating to subsequent operations.

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

In this example, the two red checks appear in both warn-first and warn-all mode (the forbid mode prevents analysis after the first red check).

Literal constants such as 1e-38 have the data type double. If you assign a literal constant to a variable with narrower type float, the constant might not be representable in this type. This issue is indicated with the red checks. The checks flag the conversion from double to float during assignment.

Result Information

Group: Numerical
Language: C | C++
Acronym: SUBNORMAL

Version History

Introduced in R2016b