View previous topic :: View next topic |
Author |
Message |
Arera
Joined: 23 Sep 2007 Posts: 386 Location: Wuppertal, Germany
|
Posted: Tue Jul 02, 2019 9:12 am Post subject: absolute value of difference |
|
|
Hi all,
working with unsigned vars, calculating the absolute value of the difference between to vars afforts a couple of steps.
Example using byte-constants:
89-5 = 84 'OK
5-89 = 171 'not the wanted result
So what I do is to take care to always substract the lower value from the higher one.
Pseudocode:
if a > b then
result = a - b
else
result = b - a
end if
My question:
Is there a more elegant way tho achieve the same?
(BASCOM-AVR version : 2.0.8.1 ) |
|
Back to top |
|
|
Duval JP
Joined: 22 Jun 2004 Posts: 1161 Location: France
|
Posted: Tue Jul 02, 2019 10:43 am Post subject: |
|
|
I test
Code: |
Dim J As Byte
Dim K As Byte
J = 89 - 5
Print J
K = 5 - 89
Print K
|
I have an Error : 49 Line : 17 Value doesn't fit into BYTE [-84] , in File : D:\pré poubelle\soustraction.bas
it is normal ! you can't do that with bascom
if you declare K as an integer you don't have error
Code: |
Dim J As Byte
Dim K As Integer
J = 89 - 5
Print J
K = 5 - 89
Print K
|
see the foundamentals in help
About your speudocode , you find the elegant way
JP _________________ pleasure to learn, to teach, to create |
|
Back to top |
|
|
laborratte
Joined: 27 Jul 2005 Posts: 299 Location: Berlin
|
Posted: Tue Jul 02, 2019 11:49 am Post subject: |
|
|
Don't know if it is more elegant, but it is faster to do it in assembler by checking the carry flag and - if necessary - negate the result:
Code: | dim a as byte
dim b as byte
dim c as byte
a = 18
b = 88
gosub SubtractLowerFromHigher
print c
a = 77
b = 27
gosub SubtractLowerFromHigher
print c
end
SubtractLowerFromHigher:
!LDS r16,{a}
!LDS r17,{b}
!SUB r16,r17
!BRCC SubtractLowerFromHigher_1
!NEG r16
SubtractLowerFromHigher_1:
!STS {c},r16
!RET |
|
|
Back to top |
|
|
Arera
Joined: 23 Sep 2007 Posts: 386 Location: Wuppertal, Germany
|
Posted: Tue Jul 02, 2019 1:28 pm Post subject: |
|
|
Thank you folks for your thougts!
Laborratte:
If often used, I find ASM in a sub to be quite elegant. Not for single use, but I'm sure I'll make use of it once in a while.
Marc |
|
Back to top |
|
|
laborratte
Joined: 27 Jul 2005 Posts: 299 Location: Berlin
|
Posted: Tue Jul 02, 2019 5:27 pm Post subject: |
|
|
Just for fun as function:
Code: | dim c as byte
CONFIG SUBMODE = NEW
function SubtractLowerFromHigher(byval a as byte, byval b as byte) as byte
'Load a
!LDD r26 , y + 2
!LDD r27 , y + 3
!ld r16,x
'Load b
!LDD r26 , y + 0
!LDD r27 , y + 1
!ld r17,x
'Substraction
!sub r16,r17
'Overflow?
!BRCC SubtractLowerFromHigher_1
'Yes: negate
!NEG R16
SubtractLowerFromHigher_1:
'Save to Result
!LDD r26 , y + 4
!LDD r27 , y + 5
!ST x,r16
end function
'Test it!
c = SubtractLowerFromHigher(18,88)
print c
c = SubtractLowerFromHigher(77,27)
print c
end
|
|
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jul 02, 2019 7:45 pm Post subject: |
|
|
More simple:
Code: | C = A - B
If SREG.0 = 1 Then C = 256 - C |
|
|
Back to top |
|
|
Micha
Joined: 03 Oct 2006 Posts: 56
|
Posted: Mon Jul 15, 2019 8:41 pm Post subject: |
|
|
What about this:
Code: |
Dim a as Byte
Dim b as Byte
Dim c as Byte
a = 5
b = 3
Do
!LDS r24,{a}
!LDS r25,{b}
!SUB r24,r25 ' Subtraction
!SBIC SREG,2 ' Test if negative
!NEG r24 ' conversation to positive value
!STS {c},r24
print c
Incr b
Loop
|
[/code] |
|
Back to top |
|
|
laborratte
Joined: 27 Jul 2005 Posts: 299 Location: Berlin
|
Posted: Tue Jul 16, 2019 5:08 pm Post subject: |
|
|
@ Micha:
Testing the negative flag of SREG ( !SBIC SREG,2 ) will not work with unsigned byte vars, as it represents the high-bit of the result (=sign of signed number). So it will be set if you calculate 240 - 1 = 239, because 239 represents -17 in 2's complement.
Using !sbic sreg,0 instead of !brcc does not make a difference in terms of speed on a mega device. On a Xmega it is even slower.
@ MWS:
For this specific situation your code will work, but it is - in general - not a good idea to use SREG in that way in basic code. The compiler adds several assembler commands between the actual subtraction and the if-then directive. You can't be sure that this commands doesn't affect SREG. Obviously this variant will not work:
Code: | C(I) = A - B
If SREG.0 = 1 Then C(I) = 256 - C(I) |
as the compiler will generate code for calculating the memory address of C(I), which kills the carry status of the previous subtraction.
I know that you are aware of that, but other people with less knowledge about assembler will also read the forum thread. |
|
Back to top |
|
|
Micha
Joined: 03 Oct 2006 Posts: 56
|
Posted: Tue Jul 16, 2019 7:04 pm Post subject: |
|
|
OK, this code works:
Code: | Dim a as Byte
Dim b as Byte
Dim c as Byte
a = 230
b = 3
Do
!LDS r24,{a}
!LDS r25,{b}
!SUB r24,r25 ' Subtraction
!SBIC SREG,0 ' Carry-Flag
!NEG r24
!STS {c},r24
print c
Incr b
Loop
|
|
|
Back to top |
|
|
|