Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can an unsigned long become negative when multiplied by a float?

The title is probably ill-chosen, but I could not find a good one-line summary for this question. My problem is that I cannot make sense of what my compiler is doing, and I wonder whether I found a bug in the compiler... or in my understanding of the C language.

My understanding is that:

  • - 1UL == ULONG_MAX, and this is safe since the overflow behavior of unsigned numbers is well defined
  • the product (- 1UL) * 1.0f involves the conversion of the left operand to float, and this conversion preserves the value (namely ULONG_MAX) except for rounding errors

So far my compiler agrees, unless 1UL comes from a variable. Here is my test program, with its output as comments:

#include <stdio.h>

int main(void)
{
    unsigned long one = 1;
    unsigned long minus_one = - one;
    printf("%lu\n", - one);            // 18446744073709551615
    printf("%g\n", minus_one * 1.0f);  // 1.84467e+19
    printf("%g\n", (- one) * 1.0);     // 1.84467e+19
    printf("%g\n", (- 1UL) * 1.0f);    // 1.84467e+19
    printf("%g\n", (- one) * 1.0f);    // -1
    return 0;
}

I cannot make sense of the last output. I tried various optimization levels, and various language standards (C90, C99 and C11) with identical results. Anyone a clue?

Environment: gcc 4.8.1 / Ubuntu Linux 14.04 / x86-64 (I32LP64)

Edit: I just noticed that my question may be a duplicate of combination of unary minus and float conversion.

like image 254
Edgar Bonet Avatar asked Feb 12 '15 10:02

Edgar Bonet


People also ask

Can unsigned long be zero?

The minimum value that can be stored in unsigned long long int is zero.

Can a long be negative C++?

long long int data type in C++ is used to store 64-bit integers. It is one of the largest data types to store integer values, unlike unsigned long long int both positive and negative. Some properties of the long long int data type are: Being a signed data type, it can store positive values as well as negative values.


1 Answers

This seems to be a bug in gcc 4.8. I have the same behavior as you with 4.8, but gcc 4.9 and clang show the corrected behavior.

like image 177
Jens Gustedt Avatar answered Oct 20 '22 00:10

Jens Gustedt