user3737289
user3737289

Reputation: 141

Are there any (valid) C implementations where float cannot represent the value 0?

If all floats are represented as x = (-1)^s * 2^e * 1.m , there is no way to store zero without support for special cases.

Upvotes: 5

Views: 199

Answers (3)

tmyklebu
tmyklebu

Reputation: 14215

I believe the following floating-point system is an example of a conforming floating-point arithmetic without a representation for zero:

A float is a 48-bit number with one sign bit, 15 exponent bits, and 32 significand bits. Every choice of sign bit, exponent bits, and significant bits corresponds to a normal floating-point number with an implied leading 1 bit.

Going through the constraints in section 5.2.4.2.2 of the draft C standard Keith Thompson linked:

  • This floating-point system plainly conforms to paragraphs 1 and 2 of 5.2.4.2.2 in the draft standard.
  • We only represent normalised numbers; paragraph 3 merely permits us to go farther.
  • Paragraph 4 is tricky; it says that zero and "values that are not floating-point numbers" may be signed or unsigned. But paragraph 3 didn't force us to have any values that aren't floating-point numbers, so I can't imagine interpreting paragraph 4 as requiring there to be a zero.
  • The range of representable values in paragraph 5 is apparently -0x1.ffffffffp+16383 to 0x1.ffffffffp+16383.
  • Paragraph 6 states that +, -, *, / and the math library have implementation-defined accuracy. Still OK.
  • Paragraph 7 doesn't really constrain this implementation as long as we can find appropriate values for all the constants.
  • We can set FLT_ROUNDS to 0; this way, I don't even have to specify what happens when addition or subtraction overflows.
  • FLT_EVAL_METHOD shall be 0.
  • We don't have subnormals, so FLT_HAS_SUBNORM shall be zero.
  • FLT_RADIX shall be 2, FLT_MANT_DIG shall be 32, FLT_DECIMAL_DIG shall be 10, FLT_DIG shall be 9, FLT_MIN_EXP shall be -16383, FLT_MIN_10_EXP shall be -4933, FLT_MAX_EXP shall be 16384, and FLT_MAX_10_EXP shall be 4933.
  • You can work out FLT_MAX, FLT_EPSILON, FLT_MIN, and FLT_TRUE_MIN.

Upvotes: 1

Keith Thompson
Keith Thompson

Reputation: 263357

No, all conforming C implementations must support a floating-point value of 0.0.

The floating-point model is described in section 5.2.4.2.2 of the C standard (the link is to a recent draft). That model does not make the leading 1 in the significand (sometimes called the mantissa) implicit, so it has no problem representing 0.0.

Most implementations of binary floating-point don't store the leading 1, and in fact the formula you cited in the question:

x = (-1)^s * 2^e * 1.m

is typically correct (though the way e is stored can vary).

In such implementations, including IEEE, a special-case bit pattern, typically all-bits-zero, is used to represent 0.0.

Following up on the discussion in the comments, tmyklebu argues that not all numbers defined by the floating-point model in 5.2.4.2.2 are required to be representable. I disagree; if not all such numbers are required to be representable, then the model is nearly useless. But even leaving that argument aside, there is an explicit requirement that 0.0 must be representable. N1570 6.7.9 paragraph 10:

If an object that has static or thread storage duration is not initialized explicitly, then:

  • ...
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • ...

This is a very long-standing requirement. A C reference from 1975 (3 years before the publication of K&R1) says:

The initial value of any externally-defined object not explicitly initialized is guaranteed to be 0.

which implies that there must be a representable 0 value. K&R1 (published in 1978) says, on page 198:

Static and external variables which are not initialized are guaranteed to start off as 0; automatic and register variables which are not initialized are guaranteed to start off as garbage.

Interestingly, the 1990 ISO C standard (equivalent to the 1989 ANSI C standard) is slightly less explicit than its predecessors and successors. In 6.5.7, it says:

If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.

If a floating-point type were not required to have an exact representation for 0.0, then the "assigned 0" phrase would imply a conversion from the int value 0 to the floating-point type, yielding a small value close to 0.0. Still, C90 has the same floating-point model as C99 and C11 (but with no mention of subnormal or unnormalized values), and my argument above about model numbers still applies. Furthermore, the C90 standard was officially superseded by C99, which in turn was superseded by C11.

Upvotes: 8

user3737289
user3737289

Reputation: 141

After o search a while a found this.

ISO/IEC 9899:201x section 6.2.5, Paragraph 13

Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number.

section 6.3.1.7, Paragraph 1

When a value of real type is converted to a complex type, the real part of the complex result value is determined by the rules of conversion to the corresponding real type and the imaginary part of the complex result value is a positive zero or an unsigned zero.

So, if i understand this right, any implementations where supports C99 (first C standard with _Complex types), must support a floating-point value of 0.0.

EDIT Keith Thompson pointed out that complex types are optional in C99, so this argument is pointless.

Upvotes: 2

Related Questions