...
Denormalized numbers can severely impair the precision of floating-point numbers and should not be used.
Noncompliant Code Example
This code attempts to reduce a floating-point number to a denormalized value and then restore the value. This operation is very imprecise.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> float x = 1/3.0; printf("Original : %e\n", x); x = x * 7e-45; printf("Denormalized? : %e\n", x); x = x / 7e-45; printf("Restored : %e\n", x); |
This code produces the following output on implementations that use IEEE 754 floats:
Code Block |
---|
Original : 3.333333e-01 Denormalized? : 2.802597e-45 Restored : 4.003710e-01 |
Compliant Solution
Do not produce code that could use not allow code to produce denormalized numbers. If floats are producing denormalized numbers, use doubles instead.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> double x = 1/3.0; printf("Original : %e\n", x); x = x * 7e-45; printf("Denormalized? : %e\n", x); x = x / 7e-45; printf("Restored : %e\n", x); |
Code Block |
---|
Original : 3.333333e-01 Denormalized? : 2.333333e-45 Restored : 3.333333e-01 |
If using doubles also produces denormalized numbers, using long doubles may or may not help. (On some implementations, long double has the same exponent range as double.) If using long doubles produces denormalized numbers, some other solution must be found.
Printing Denormalized Numbers
Denormalized numbers can also be troublesome because some functions have implementation-defined behavior when used with denormalized values. For example, using the %a
or $%A
conversion specifier in a format string can produce implementation-defined results when applied to denormalized numbers.
...
Code Block |
---|
#include<stdio.h> float x = 0x1p-125; double y = 0x1p-1020; printf("normalized float with %%e : %e\n", x); printf("normalized float with %%a : %a\n", x); x = 0x1p-140; printf("denormalized float with %%e : %e\n", x); printf("denormalized float with %%a : %a\n", x); printf("normalized double with %%e : %e\n", y); printf("normalized double with %%a : %a\n", y); y = 0x1p-1050; printf("denormalized double with %%e : %e\n", y); printf("denormalized double with %%a : %a\n", y); |
Implementation Details
On a 32-bit Linux machine using GCC 4.3.2, this code produces the following output:
Code Block |
---|
normalized float with %e : 2.350989e-38 normalized float with %a : 0x1p-125 denormalized float with %e : 7.174648e-43 denormalized float with %a : 0x1p-140 normalized double with %e : 8.900295e-308 normalized double with %a : 0x1p-1020 denormalized double with %e : 8.289046e-317 denormalized double with %a : 0x0.0000001p-1022 |
Risk Assessment
Floating-point numbers are an approximation; using subnormal floating-point number are a worse approximation.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FLP05-C | Low | Probable | High | P2 | L3 |
Automated Detection
TODO
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[Bryant 2003] | Section 2.4, "Floating Point" |
[IEEE 754] | |
[ISO/IEC 9899:2011] | Subclause 7.21.6.1, "The fprintf Function" |
...