Fast arithmetic method for ints

I am writing a program c. I have an unsigned integer (16 bits) whose value can be any at any time, and I have a signed char (8 bits) whose value can be any at any time, within the obvious limits of data types. I need to add a signed char to an unsigned int, the result will be unsigned int, and if the value overflows either past 0xFFFF or below 0x00, I need the result to equal the limit (either 0x00 or 0xFFFF). I want to know what would be the fastest way to do this? My approach is shown below, but it uses a long data type and therefore long binary arithmetic, so I assume there is a faster way ...

long i; unsigned int result; i = someUINT + someCHAR; if(i <= 0) { result = 0; } else if(i >= 0xFFFF) { result = 0xFFFF; } else { result = (unsigned int)i; } 

EDIT: I am using a 16-bit MCU (PIC24HJ series) and the Microchip C30 compiler.

+4
source share
7 answers

Almost certainly the correct answer

 if(i <= 0) { result = 0; } else if(i >= 0xFFFF) { result = 0xFFFF; } else { result = (unsigned int)i; } 

Profile the application, and if it turns out to be a bottleneck (which I very much doubt), rewrite it.


Modern compilers are very good at writing conditional conventions for code like this, so just write it so that it makes the most sense and allows the compiler to do its job. Do not confuse the compiler, and any poor person should read this code in the future, using some kind of confusing cracked bit.

+3
source

You can avoid a lengthy check before adding:

 if(0xFFFF - someUINT < someCHAR) { return 0xFFFF; } else { return someUINT + someCHAR; } 

Of course, if you really need it to be FAST, turn it into a built-in function or macro and go into the assembly.

0
source

This algorithm only works in 2 add-ons.

When checking a signed add-on for overflow, the result must have the same sign as at least one of the operands. This case is a little different; if the result discards the “sign” bit, then it is OK, if both operands have the same “sign” bit. And of course, calculating unsigned limits is easier!

 uint16_t UIntPlusChar(uint16_t u, char ch) { int16_t i = (int16_t)u; int16_t p = i + ch; if ((ch ^ i) < 0 && (p ^ i) < 0) p = i >> 15; return (uint16_t)p; } 
0
source

Wow, I love such things. Here is my punch suggesting that most of the time it will be between the borders, try this

  long i; i= char + int; if((i & 0xFFFF) == i){ return (int)i; } else if(i < 0) { return 0; } else { return 0xFFFF; } 
0
source

The fastest way will almost always be to use processor-specific features that you cannot describe in portable C code. Write clearly the correct portable code that works, and let the compiler do what it will do. If you have specific benchmarks that show that it should be faster specifically, use an optional custom version specific to the processor.

Many processors (including, I believe, PIC24) have saturation commands that perform this particular operation. The fastest, as a rule, is to write an assembly that uses this instruction specifically, but there is no reason for this unless you have evidence that the function should be faster.

0
source
 result = someUINT + someCHAR; if (someCHAR > 0) { if (result < someCHAR) { result = 0xFFFF; } } else if (result > someUINT) { result = 0; } 
0
source

I would suggest that something like:

  UInt16 uival;
   Int8 sbval;
   UInt16 result;

   result = uival + sbval;
   if (uival & 0x8000) / * Only worry about max-val overflow * /
   {
     if (result = 65280) / * Underflow * /
       result = 0;
   }

A little simplified, because any overflow can occur only in a small part of the numerical range. If the addition was 16 bits, it would be necessary to check the difference between the original uint16 and the result to see if there was an overflow; since adding only 8 bits is not necessary. I have not used parts of PIC24xx, so I don’t know if testing at 256 or 65280 works faster than other values, but on 8-bit parts this certainly should be.

0
source

Source: https://habr.com/ru/post/1342184/


All Articles