I don’t understand how dealing with numbers correctly is not a solved problem in computer engineering by now.
Unsigned sizes: A five year mistake
61–70 of 153 posts
Re: Unsigned sizes: A five year mistake
#62I don't get it. Is this a parody of poor design decisions? Sure, it's possible to write bugs in C. And if you really want to, you can disable the compiler warnings which flag tautologous comparisons and mixed-sign comparisons (a common reason for doing this is to avoid spurious warnings in generic-type code). But, uhh, "people can deliberately write bugs" has got to be the weakest justification I've ever seen for cha…
The C language does not have any data type that has the property "can't be negative". Signed integers can be negative. The so-called "unsigned" integers of C are integer residues modulo 2^N, which are neither positive nor negative, i.e. these concepts are not applicable to "unsigned" integers. An alternative view is that any C "unsigned" is both positive and negative. For example the unsigned short "1" is the same nu…
#include
int main() {
unsigned short a = 1;
long b = a;
printf("%ld\n", b);
}
If not, why?Re: Unsigned sizes: A five year mistake
#63Earlier quoted context omitted.
> But I would say if you know a value will logically always be >= 0, better to have a type that reflects that. Except that's not quite what unsigned types do. They are not (just) numbers that will always be >= 0, but numbers where the value of `1 - 2` is > 1 and depends on the type. This is not an accident but how these types are intended to behave because what they express is that you want modular arithmetic, not no…
This is true, which means that a language has to be designed from the ground up to deal with these problems or there will always be inscrutable bugs due to misuse of arithmetic results. A simple example in a c-like language would be that the following function would not compile: unsigned foo(unsigned a, unsigned b) { return a - b; } but this would: unsigned foo(unsigned a, unsigned b) { auto c = a - b; return c >= 0…
Second, it's not as simple as you present. What is the type of c? Obviously it needs to be signed so that you could compare it to zero, but how many bits does it have? What if a and b are 64 bit? What if they're 128 bit?
You could do it without storing the value and by carrying a proof that a >= b, but that is not so simple, either (I mean, the compiler can add runtime checks, but languages like C don't like invisible operations).
Re: Unsigned sizes: A five year mistake
#64I hate using languages that only have signed integers. Using integers that can’t be negative fits many problems nicely and avoids the edge case of having to check for negative.
You are perfectly right, but neither C nor C++ nor many more recent languages derived from them have non-negative integers. The so-called "unsigned" integers of C are integer residues, where each value can be interpreted either as both positive and negative or as neither positive nor negative. In any case no "unsigned" value can be said to be non-negative. You have to go back to languages not contaminated by C, like…
Re: Unsigned sizes: A five year mistake
#65Earlier quoted context omitted.
> Wrapping around is what happens when you decrement the minimum value of any integer type, including signed types. No, signed wraparound is undefined behavior in C, whereas unsigneds are defined to wraparound. If you use -ftrapv, signed wraparound is an immediate abort().
That is right. While C like in many other places fails to define the correct behavior to avoid shaming the processor or compiler makers that fail to provide it, there are only 2 correct behaviors on overflows and underflows, like when incrementing the biggest number or decrementing the smallest number. Both for signed integers and for non-negative integers, the 2 alternatives of correct behavior on overflows and unde…
Re: Unsigned sizes: A five year mistake
#66Systems programmers love to hate on unsigned integers. Generations have been infected with the Java world model that integers have to be pretend number lines centered on zero. Guess what, you still have boundary conditions to deal with. There are times when you really really need to use the full word range without negative values. This happens more often with low level programming and machines with small word sizes,…
Having them available is not the issue, using them for sizes and indices is what causes a lot of tricky bugs.
It's pretty rare to have values that can be negative but are always integers. At least in the work I do. The most common case I encounter are approximations of something related to log probability. Such as various scores in dynamic programming and graph algorithms.
Most of the time, when you deal with integers, you need special handling to avoid negative values. Once you get used to thinking about unsigned integers, you quickly develop robust ways of avoiding situations where the values would be negative.
Re: Unsigned sizes: A five year mistake
#67Systems programmers love to hate on unsigned integers. Generations have been infected with the Java world model that integers have to be pretend number lines centered on zero. Guess what, you still have boundary conditions to deal with. There are times when you really really need to use the full word range without negative values. This happens more often with low level programming and machines with small word sizes,…
Java doesn't have unsigned as primitive types, because James Gosling did a series of interviews at Sun among "expert" C devs, and all got the C language rules for unsigned arithmetic wrong. Yes I miss them in Java as primitives, however there are utility methods for unsigned arithmetic, that get it right.
Re: Unsigned sizes: A five year mistake
#68> But what about the range? While it’s true that you get twice the range, surprisingly often the code in the range above signed-int max is quite bug-ridden. Any code doing something like (2U * index) / 2U in this range will have quite the surprise coming. Alas, (2S * signed_index) / 2S will similarly result in surprises the moment the signed_index hits half the signed-int max. There's no free lunch when trying to che…
The difference is that in the unsigned case you get a seemingly plausible value, and in the signed case you get a negative value which you can be sure is wrong. This is the problem.
Re: Unsigned sizes: A five year mistake
#69Earlier quoted context omitted.
Having them available is not the issue, using them for sizes and indices is what causes a lot of tricky bugs.
Why does an unsigned type for sizes or indices fare worse than a signed type? When do I want the -247th element in an array? When do I have a block that is -10 bytes in size?
The source of confusion is that unsigned is a terrible name. Unsigned does not mean non-negative. Its 100% complete valid to assign a negative value to an unsigned, it just fails silently.
If you want non-negative integers, then you should make a wrapper class that enforces non-negativity at compile and runtime.
Re: Unsigned sizes: A five year mistake
#70Earlier quoted context omitted.
It's not "can't be negative", it's just that the semantics for negativity is wrapping around. And - yes, there are very important use cases for unsigned/modulo-2n/wraparound values. But sizes of data structures are generally _not_ one of those use cases. The fact that the size is non-negative does not mean that the type should be unsigned. You should still be able to, say, subtract sizes and get a signed value which…
That’s definitely not true. Unsigned ints have no “negativity” semantic. Wrapping around is what happens when you decrement the minimum value of any integer type, including signed types. Regardless of the type you use to represent an integer value that cannot legally be negative, you will have to take care not to allow your program to return values lower than zero for things like indices or sizes.
They do. The code:
unsigned x;
unsigned y = -x;
is well-defined in C and C++. See this discussion on StackOverflow for spec text and reference: