-3

I ran to some problem and it is driven me nuts.

I have a code like this

float a;
unsigned short b;

b += a;

When a is negative, b is going bananas.

I even did a cast

b += (unsigned short) a;

but it doesn't work.

What did I do wrong? How can I add float to a unsigned short?

FYI: When 'a' is -1 and b is 0 then I'll see 'b +=a' will give b = 65535.

CB4
  • 690
  • 3
  • 13
  • 25
  • 2
    works for me. b=42, a=-10 i get 32 (in ideone.com as vanilla c). Show some real code and explain the bananas – pm100 Nov 03 '15 at 22:16
  • 3
    Why are you trying to do this? And even if you cast a negative signed number into a signed version, that probably isn't doing what you think it does. Look into how that works. -32 cast to unsigned is NOT just going to give you positive 32 or something like that. Is this what "bananas" is referring to? No one just knows what "but it doesn't work" means when you give no more context. – Ricky Mutschlechner Nov 03 '15 at 22:20
  • It's worth thinking for a few seconds about what you actually expect to happen. Add a few cases of expected vs actual results in your question. – roeland Nov 03 '15 at 22:32
  • 3
    Neither "going bananas" nor "it doesn't work" is a description. Update your question to tell us the values of `a` and `b` and the output of your program. (Note that to do that, you'll need to update your program so that (a) it's a program rather than a code fragment, and (b) it produces output.) – Keith Thompson Nov 03 '15 at 22:34
  • Just sit down and think for a second or two about the implications of **unsigned** (i.e. **non-negative**) integers. – too honest for this site Nov 03 '15 at 22:51
  • Possible duplicate of [Arithmetic operations on unsigned and signed integers](http://stackoverflow.com/questions/2084949/arithmetic-operations-on-unsigned-and-signed-integers) – Bo Persson Nov 03 '15 at 23:19
  • @Olaf: I don't see enough information in the question to indicate that that's the issue. If `a` (the `float` variable) has a large enough value, the same problem (whatever the heck it is) could occur of `b` were a `signed short`. **We need to see the actual copy-and-pasted bananas.** – Keith Thompson Nov 03 '15 at 23:19
  • `b += (unsigned short) a;` Casting a negative value to `unsigned` will give you even more bananas. Don't do that! – Bo Persson Nov 03 '15 at 23:23
  • I think the problem I am having is when a is negative and it is larger than b. Also, I don't have the abs() method in my project reference. – CB4 Nov 04 '15 at 00:56

4 Answers4

2

Your question would be improved by showing actual values you have trouble with, and explaining what value you expected to get.

But in the meantime, the definition of floating to integer conversion in C11 6.3.1.4/1 is:

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.

This comes into play at the point where the result of b + a, which is a float, is assigned back to b. Recall that b += a is equivalent to b = b + a.

If b + a is a negative number of -1 or greater magnitude, then its integral part is out of range for unsigned short so the code causes undefined behaviour which means anything can happen; including but not limited to going bananas.

A footnote repeats the point that the float is not first converted to a signed integer and then to unsigned short:

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)


As an improvement you could write:

b += (long long)a;

which will at least not cause UB so long as a > LLONG_MIN.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
2

The way to add a float to an unsigned short is simply to add it, exactly as you've done. The operands of the addition will undergo conversions, as I'll describe below.

A simple example, based on your code, is:

#include <stdio.h>
int main(void) {
    float a = 7.5;
    unsigned short b = 42;
    b += a;
    printf("b = %hu\n", b);
    return 0;
}

The output, unsurprisingly, is:

b = 49

The statement

b += a;

is equivalent to:

b = b + a;

(except that b is only evaluated once). When operands of different types are added (or subtracted, or ...), they're converted to a common type based on a set of rules you can find in the C standard section 6.3.1.8. In this case, b is converted from unsigned short to float. The addition is equivalent to 42.0f + 7.5f, which yields 49.5f. The assignment then converts this result from float to unsigned short, and the result,49is stored inb`.

If the mathematical result of the addition is outside the range of float (which is unlikely), or if it's outside the range of unsigned short (which is much more likely), then the program will have undefined behavior. You might see some garbage value stored in b, your program might crash, or in principle quite literally anything else could happen. When you convert a signed or unsigned integer to an unsigned integer type, the result is wrapped around; this does not happen when converting a floating-point value to an unsigned type.

Without more information, it's impossible to tell what problem you're actually having or how to fix it.

But it does seem that adding an unsigned short and a float and storing the result in an unsigned short is an unusual thing to do. There could be situations where it's exactly what you need (if so you need to avoid overflow), but it's possible that you'd be better off storing the result in something other than an unsigned short, perhaps in a float or double. (Incidentally, double is used more often than float for floating-point data; float is useful mostly for saving space when you have a lot of data.)

If you're doing numeric conversions, even implicit ones, it's often (but by no means always) an indication that you should have used a variable of a different type in the first place.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
-1

You are observing the combination of the float being converted to an integer, and unsigned integer wrap-around ( https://stackoverflow.com/a/9052112/1149664 ).

Consider

b += a 

for example with a = -100.67 you add a negative value to a signed data type, and depending on the initial value of b the result aught to be negative. How come you got the idea to use an unsigned short and not just float or double for this task?

Community
  • 1
  • 1
Johan Lundberg
  • 26,184
  • 12
  • 71
  • 97
-1

You want b to be positive (it is unsigned), but a can be negative. It is OK as long as a is not larger than b. This is first point.

Second - when you are casting negative value to unsign.. what actually the result is supposed to be? Number sign is stored in most significant bit and for negative values it is 1. When value is unsigned when if most significant bit is 1 the value is really high and has nothing in common with negative one.

Maybe trying b -= fabs(a) for negative a. Isn't that what you are looking for?

Kamen Stoykov
  • 1,715
  • 3
  • 17
  • 31