Variable length integer subtraction

On a controlled buffer of unsigned char it is possible to do subtraction faster than if you followed standard mathematical rules, here is an example:
1
2
3
4
5
6
typedef unsigned char uchr;
uchr num1 = 5; //00000101
uchr num2 = 3; //00000011
num2 = ~num2;  // 11111100
++num2; // 11111101
uchr num3 = num1 + num2; // 00000010(2) - computer truncates result to fit char 

Since you will be working with a buffer you don't even need to worry about truncating the final bit because the add function will not be able to reach it - unless it is given the ability to grow the buffer in which case you just set the bit to 0 yourself
Last edited on
> it is possible to do subtraction faster
...
1
2
3
4
5
6
7
8
9
10
11
12
//C = A-B
movf	B,w
subwf	A,w
movwf	C
//taking 3 cycles

//C = ~A+1 + B
comf	A,f
incf	A,w
addwf	B,w
movwf	C
//taking 4 cycles 
Have you tried it on a buffer? The example above was only given to allow developers to try the method quickly before implementing it on a buffer subtraction, obviously if it was a regular fixed width integer (char, short, long, etc.) then it would be better to leave it to the compiler with the - character as it is easier to read as well. I've yet to learn how to use assembler code so I can't write a function to show it in practice. If you want to try yourself then please use these as the function headers:
1
2
3
4
5
6
7
8
9
10
11
12
typedef unsigned char uchr;
/* like -= should return src */
uchr* vluRemEq( uchr* src, size_t sbits, uchr* val, size_t vbits ); /*focus on this one */
uchr* vlsRemEq( uchr* src, size_t sbits, uchr* val, size_t vbits );
uchr* vlusRemEq( uchr* src, size_t sbits, uchr* val, size_t vbits );
uchr* vlsuRemEq( uchr* src, size_t sbits, uchr* val, size_t vbits );
/* like - should return modified copy of src, should wrap around vl*RemEq() */
uchr* vluRem( uchr* src, size_t sbits, uchr* val, size_t vbits );
uchr* vlsRem( uchr* src, size_t sbits, uchr* val, size_t vbits );
uchr* vlusRem( uchr* src, size_t sbits, uchr* val, size_t vbits );
uchr* vlsuRem( uchr* src, size_t sbits, uchr* val, size_t vbits );
/* signed ones should wrap around vluRem */

Just in case you didn't pick up on it:
* vl stands for variable length,
* u stands for unsigned,
* s standas for signed,
* Eq stands for Eqauls
Last edited on
> Have you tried it on a buffer?
¿how would be different with a buffer?

> I've yet to learn how to use assembler code so I can't write a function to show it in practice.
¿why are you saying that the subtraction would be faster then?
As far as I know those are only supposed to work on integers types the processor already supports, if I'm wrong then please correct me.

As for the subtraction being faster if you read what I originally wrote you'll notice I said it was faster than standard mathematical rules ie:
1
2
3
4
5
6
7
8
9
10
11

  100101
- 100010
========
  100101
to
  100101 ( 1 - 0 )
to
  100011 ( 100 - 010 )
to
  000011 ( 100000 - 100000 )

With that method you need to enter a loop every time you encounter 0 - 1 just so you can set every 0 you encounter to 1 until you encounter a 1, on a buffer that can be very time consuming if the integer is long, my way takes advantage of addition's natural speed as it only needs a carry bit in addition to the 2 buffers handed to it. If it's possible to use the above assembler code with bits instead of bytes then I would prefer that since it is simpler and faster.

BTW for reference I have some pre-made functions in this thread:
http://www.cplusplus.com/forum/general/109259/
Last edited on
> With that method you need to enter a loop every time you encounter 0 - 1
> just so you can set every 0 you encounter to 1 until you encounter a 1
You don't need to do that.

> my way takes advantage of addition's natural speed
> as it only needs a carry bit in addition to the 2 buffers handed to it
Subtraction can be done that way too
A	B	Ci		Z	Co
0	0	0		0	0	
0	0	1		1	1	
0	1	0		1	1	
0	1	1		0	1	
1	0	0		1	0	
1	0	1		0	0	
1	1	0		0	0	
1	1	1		1	1



> BTW for reference I have some pre-made functions in this thread:
> http://www.cplusplus.com/forum/general/109259/
You need to check precedence rules
1
2
3
4
5
6
  if ( !src || val )
    return src;
//equivalent forms
if( not src or val )
if( (not src) or val)
if( src==NULL or val!=NULL)
I'll try the carry at a later point, but why would I need to check precedence rules? From my understanding the ! operator returns true if it receives 0, NULL or false since they all evaluate to 0 anyway and it always returns false if it receives anything other than those 3.
As I said
1
2
3
4
//equivalent forms
if ( !src || val )
if( src==NULL or val!=NULL )
if( (src==NULL) or (val!=NULL) )
but seeing your code it seems that your intention was
1
2
if( src==NULL or val==NULL )
if( !(src||val) )
I get that bit but why precedence, that's all about order of expressions not the tests themselves.
Topic archived. No new replies allowed.