问题描述:

In an attempt to see what would happen in the case of a float underflow I found that I could make float numbers much smaller than FLT_MIN. I'm using xcode 5.1 on OS 10.9. The language dialect is gnu99.

`#include <stdio.h>`

#include <stdlib.h>

#include <float.h>

int main(int argc, const char * argv[])

{

float underflow = FLT_MIN * 0.0000004;

printf("Float min is %f or %e.\nUnderflow is %f or %e\nMin float exp is %d.\n", FLT_MIN, FLT_MIN, underflow, underflow, FLT_MIN_10_EXP);

return 0;

}

Prints:

Float min is 0.000000 or 1.175494e-38.

Underflow is 0.000000 or 4.203895e-45

Min float exp is -37.

- Is there a more effective method of demonstrating the limits of data types?
- Why is FLT_MIN not actually the smallest float value? Are there other constants that I'm supposed to be using? After typing the previous question I found FLT_TRUE_MIN. What is this number?

2 possibilities to get "below minimum":

`float`

range:Typical

`float`

numbers have 2 ranges: full precision (normal range) from`FLT_MAX`

down to`FLT_MIN`

and a 2nd range with reducing precision from`FLT_MIN`

down to`FLT_TRUE_MIN`

. This 2nd range, called "subnormal" typically provides about 10^-7 more range.`FLT_TRUE_MIN`

is the "minimum positive floating-point number"`FLT_MIN`

is the "minimum normalized positive floating-point number"`FLT_MIN_10_EXP`

is the "minimum negative integer such that 10 raised to that power is in the range of normalized floating-point numbers"C11dr §5.2.4.2.2

In general

`0 < FLT_TRUE_MIN <= FLT_MIN <= 10^FLT_MIN_10_EXP <= 10^-37`

Math performed as

`double`

.`printf()`

coverts each`float`

passed to it to a`double`

. C allows code to optimize such that the value passed to`printf()`

may be the`double`

product of`FLT_MIN * 0.0000004`

.`float underflow = FLT_MIN * 0.0000004; printf("%e\n", underflow);`

Had the output been

`4.701976e-45`

rather than`4.203895e-45`

, this would have been the case.

Note on "subnormal". A compelling reason *for* subnormal (or denormal) numbers lies in the following problem.

```
float a,b;
... // somehow a and b are set.
// Are the 2 below equivalent?
if (a == b) foo();
if ((a - b) == 0) foo();
```

Without subnormal numbers, 2 nearly the same value numbers near `FLT_MIN`

would have a non-zero mathematical difference much below `FLT_MIN`

and the result would round to `0.0`

.

With subnormal numbers, the difference of every pair of different `float`

s is representable by something other than `0.0`

. **

** Except `+0.0, -0.0`

. Signed zeros have their own peculiarities.

In really simple, not exact terms, floating points are stored as 0.xxxxx x 2^yyyyyy. "Normal" numbers are required to NOT have leading zeros in the xxxxx part. So the smallest number you can make is something like 0.10000 x 2^-111111. However if you "cheat" and denormalize the number you can make one like 0.000001 x 2^-111111, which is smaller but has fewer significant digits.

See http://en.wikipedia.org/wiki/Denormal_number

Representing a floating number as `y = (+/-) significand x base ^ (exponent - precision)`

, every `y != 0`

has a unique representation if you make sure that `significand >= base ^ (precision - 1)`

. A nonzero `y`

that satisfies this is called **normalized**. Now `FLT_MIN`

is the minimum normalized positive `float`

, while `FLT_TRUE_MIN`

is the true minimum you get without the normalized-restriction.

In other words, `FLT_MIN = base ^ (FLT_MIN_EXP - 1)`

and `FLT_TRUE_MIN = base ^ (FLT_MIN_EXP - precision)`

.