floats smaller than FLT_MIN. why FLT_TRUE_MIN?
Asked Answered
H

3

8

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.

  1. Is there a more effective method of demonstrating the limits of data types?
  2. 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?
Housing answered 6/9, 2014 at 22:20 Comment(3)
en.wikipedia.org/wiki/Denormal_numberEarleneearley
Write that up as an answer, please.Puff
You mentioned your dialect is "gnu99"; I would attract your attention that FLT_TRUE_MIN was introduced with C11, so formally would require using the "gnu11" dialect.Chalkstone
O
12

2 possibilities to get "below minimum":

  1. 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

  2. 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 floats is representable by something other than 0.0. **

** Except +0.0, -0.0. Signed zeros have their own peculiarities.

Oxbridge answered 7/9, 2014 at 0:7 Comment(0)
S
7

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

Sophi answered 6/9, 2014 at 22:46 Comment(0)
S
1

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).

Shore answered 6/9, 2014 at 22:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.