Dealing with overflow and underflow in integer and floating-point multiplication
16-Bit Integer
The range for int16_t is [−32,768, +32,767], since it is a 16-bit two’s complement type (and these limits are specified in C 2018 7.20.2.1 1). When a floating-point value is converted to an integer type, it is truncated (6.3.1.4 1), so all values inside the open interval (−32,769, +32,768) have defined results (do not overflow), and values outside that overflow (the C standard does not define the behavior).
The C standard’s requirements for float are such that all integers from −32,769 to +32,768 can be represented. Per 5.2.4.2.2 14, the spacing between representable numbers in a neighborhood of 1 is at most 10− 5, so the spacing in the neighborhood of 32,769 is at most 32,769•10−5 = .32769. Further, 5.2.4.2.2 13 tells us this is within the range of the float format (at least 1037). So integers up to 32,769 in magnitude are representable. The float values are a subset of the double values per 6.2.5 10.
Therefore, we can perform the desired scaling, test, and conversion with:
float t = *sample * factor;
if (t <= -INT16_MIN - 1.f)
{
fprintf(stderr, "Warning, underflow in sample #%lu.\n", i);
*sample = INT16_MIN;
}
else if (INT16_MAX + 1.f <= t)
{
fprintf(stderr, "Warning, overflow in sample #%lu.\n", i);
*sample = INT16_MAX;
}
else
*sample = t;
The above uses float since it suffices for range, but double may be used if more precision is desired in the representation of factor or the product.
Wider Integer Types
The IEEE-754 binary64 format commonly used for double is sufficient, as its 53-bit significand ensures integers up to 253 can be represented.
However, the C standard alone does not guarantee this. It only guarantees spacing of 10−9 in the neighborhood of 1 and a 32-bit int may have values up to 2,147,483,647, this is insufficient to guarantee the test may be performed in the same way as above. For general portable conversion of floating-point values to integer types, this answer provides safe code.
Read more here: Source link
