3 ms·
ARM handles signed and unsigned numbers equally. Addition and subtraction are the same operation whether signed or unsigned. Multiplication of 32-bit numbers
by mansr 16y ago
ARM handles signed and unsigned numbers equally. Addition and subtraction are the same operation whether signed or unsigned. Multiplication of 32-bit numbers with 64-bit result has both signed and unsigned versions. Condition codes can test for both signed and unsigned relations.
As for the real problem, you are right on the mark. Mixing signed and unsigned can result in a negative number being interpreted as a large positive number with unpleasant consequences. However, casts will rarely remedy this in a safe manner since unsigned to signed conversion where the value is outside the range of the target type is unspecified by the C standard.
- pietrofmaggi 16y ago"ARM handles signed and unsigned numbers equally." Yep, you are right. I wrote this in a hurry and forget that what I was thinking about was arguments passing in functions. C compilers has to "trim values" if the parameter are not signed int.
- mansr 16y agoWrong again. Function parameters are passed as if the values were assigned to variables of the corresponding types using the usual implicit conversion rules. If the function parameter has type of different width than the value being passed, a truncation or sign/zero extension happens. A signed value assigned to an equal-width unsigned parameter retains the same bit pattern (in 2's complement). Unsigned to signed conversion is potentially unspecified (out of range values). All known ARM compilers convert from unsigned to signed by keeping the bits unchanged. In no case does the signedness of parameters affect the speed of the compiled code (on ARM).
- pietrofmaggi 16y agoYep^2 Thanks for remembering this. Time to take a break for today.
- pietrofmaggi 16y agoNow with a bit more of time, just for sake of completeness (from the ARM's System Developers Guide). "If your code uses addition, subtraction, and multiplication then there's no performance difference between signed and unsigned operation. However, there is a difference when it comes to division." Consider the following short example that averages two integers: int average_v1(int a, int b) { return (a+b)/2; } This compiles to: average_v1 ADD r0, r0, r1 ; r0 = a+ b ADD r0, r0, r0, LSR #31 ; if (r0<0) r0++ MOV r0, r0, ASR #1 ; r0 = r0 >> 1 MOV ro, r14 ; return ro Notice that the compiler adds one to the sum before shifting by right if the sum is negative. In other words it replaces x/2 by the statement: (x<0)?((x+1)>>1):(x>>1) It must do this because x is signed. In C on an ARM target, a divide by two is not a right shift if x is negative. For example, -3 >> 1 = -2 but -3/2 = -1. Division rounds towards zero, but arithmetic right shift rounds towards -inf. It is more efficient to use unsigned types for division. The compiler converts unsigned power of two divisions directly to right shifts. For this and other fancy ARM insight take a look at the ARM System Developer's Guide, really a nice book: http://www.elsevier.com/wps/find/bookdescription.cws_home/702211/description#description http://www.elsevier.com/wps/find/bookdescription.cws_home/70...
- mansr 16y agoThis is not specific to ARM. There is to my knowledge no CPU architecture where an arithmetic right shift works differently. Unsigned types allow the compiler to perform this optimisation. However, unsigned types can easily introduce unexpected behaviours elsewhere. One of the more common is a comparison in which an unsigned wraparound where a negative result was expected causes the wrong branch to be taken. If a value is known to be positive, one can always safely use a right shift directly rather than the division operator.