36

What happens if a negative floating point value is converted into a value of unsigned integral type? Standard quotes would be appreciated. The problem I'm facing is conversion into values of unsigned integral types from a variant class, that contains an object of floating-point type.

EXAMPLE:

unsigned i = -.1;
2501
  • 25,460
  • 4
  • 47
  • 87
user1095108
  • 14,119
  • 9
  • 58
  • 116

3 Answers3

41

In case the negative value is -1.0 or lower, it invokes undefined behavior since the integral part then cannot be represented by an unsigned number. Otherwise, (as in the case of -0.1), if it can be represented by an integer type, it is well-defined behavior. See the C11 standard, ISO 9899:2011:

6.3.1.4

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined. 61)

And then there is a non-normative foot note explaining the above text:

61) The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).

ISO/IEC 9899:1999 (C99) contains exactly the same text.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    Is that the C standard? Actually I've noticed the question is multi-tagged. Have an upvote. – Bathsheba Apr 06 '16 at 06:57
  • 1
    @Bathsheba the question is labeled both C and C++ so either standard would be relevant. But it's a good question. – Mark Ransom Apr 06 '16 at 06:57
  • 7
    @Lundin but the question explicitly does -.1, which, truncated would be representable. – Antti Haapala -- Слава Україні Apr 06 '16 at 07:51
  • 9
    As Antti points out `(unsigned)-.1` is within the range (−1, Utype_MAX+1), so this particular case is not undefined behaviour. We could re-write the answer pedantically, ***With the execption of negative values above -1.0**, it invokes undefined behaviour*. – Toby Speight Apr 06 '16 at 10:24
  • 3
    @TobySpeight Perhaps you mean "With the execption of negative values **below/less than** -1.0" – nalzok Apr 06 '16 at 16:37
  • 1
    @sunqingyao The range (-1, Utype_MAX+1) is exclusive at both ends (inclusive would have been notated with square brackets [,]), so the inequality is in fact `<= 1.0`. – Iwillnotexist Idonotexist Apr 06 '16 at 16:49
  • 1
    @sun, of course not - values of -1.0 and less produce undefined behaviour. Values strictly between -1.0 and UINT_MAX+1 have specified behaviour. [atturri's answer](/a/36443699/4850040) phrases it better... – Toby Speight Apr 06 '16 at 16:59
  • @TobySpeight I mean -0.5 is above -1.0, because it's **greater** than the later. – nalzok Apr 06 '16 at 17:30
  • @sun - Yes, -0.5 is a value above -1.0, so *it's an exception* to the statement, "it invokes undefined behaviour". As I said, atturri's wording is better than mine ("it is undefined ... if the [number] is less than or equal to -1.0") – Toby Speight Apr 06 '16 at 17:36
  • 1
    A later answer sites the same standard paragraphs and points out that it is well defined. Your opening sentence contradicts the evidence you give! – JDługosz Apr 07 '16 at 03:08
  • I changed the wording of this answer. – Lundin Apr 07 '16 at 06:38
28

It is undefined behaviour in C99 if the floating point number is less than or equal to -1.0. If it's in the range (-1.0, 0.0), the resulting value will be 0.

From C99, §6.3.1.4, paragraph 1

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined

Footnote 50 clarifies the behaviour for the (-1.0, 0.0) range.

atturri
  • 1,133
  • 7
  • 13
5

Your example, unsigned i = -.1; is well-defined by both C11 and C99, and the result is i == 0.

Quoted from N1570, 6.3.1.4 Real floating and integer:

  1. When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.61)

61) The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (-1, Utype_MAX+1).

Quoted from N869, 6.3.1.4 Real floating and integer:

#1

When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.43)

43)The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (-1, Utype_MAX+1).

However, as you can see from the quotations, trying to convert floating-point constants outside the range (-1, Utype_MAX+1) invokes undefined behaviour.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
nalzok
  • 14,965
  • 21
  • 72
  • 139