Page 1 of 2

If a>255: a=255?

Posted: Fri Oct 09, 2020 10:35 am
by AMpos
Hi!

is there a faster/better method for this?

Code: Select all

a=a+b
if a>255
 a=255
endif
I want to add any valor to "a" (byte/ascii size), and any number greater than 255 crop to 255.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 11:06 am
by NicTheQuick
If a is of type Ascii, you will never be able to get a value above 255. It will always overflow. So you condition "a > 255" will never be true.

Code: Select all

b.a = 100
a.a = 200

a + b
Debug a ; shows 44
Well, it works like this without branching, and therefore the prefetching of your CPU can help to make it faster. But I never tested it. And I guess there will be an assembler instruction which can do all of this in one clock cycle:

Code: Select all

b.a = 100
a.u = 200

a = a + b

;1. version (assumes a and b were < 256 before the addition)
a = ((a >> 8) * $ff) | (a & $ff)

;2. version (works for every value of a and b)
;a = (Bool(a > 255) * $ff) | (a & $ff)

Debug a
If you make lots of these clampings you also may want to use some SSE instructions which can to 4 (or more?) of these comparisons at the same time. And when I remember right there should also be a simple ASM instruction which can set a value if a given condition is met which should also make this faster. But unfortunately I am not an Assember guru.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 11:30 am
by AMpos
Yeah, I know.

If I define "a" as ascii, I will never get a value over 255, so I can't know if it was.

In my code (it is an "image color levels / gamma" ), I use this:

Code: Select all

Protected *red.Ascii, *green.Ascii, *blue.Ascii, x,y,r,g,b,gwhite.f,gblack.f
r=*red\a*gwhite:If r>255:r=255:EndIf:*red\a=r
(I am modifying viewtopic.php?f=12&t=67262&hilit=GammaCorrectImage to accept White and Black values, and need it to be as fast as possible)

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 11:35 am
by Jac de Lad
But if you use a single byte the outcome is different:
In the original 200+100 is 300 and shall be lowered to 255.
As a byte it is 44, like Nic said. That's not the same.

Am I wrong?

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:18 pm
by AMpos
If you have a byte/ascii variable, and add over 255, then it start again:

a.ascii=200+100=300, and a is really 300-256=44, so a=44

so

Code: Select all

a.ascii=200
a=a+100
if a>255
 a=255
endif
will never work as the "a.ascii" is a loop between 0 to 255.

Code: Select all

a.q=200
a=a+100
if a>255
 a=255
endif
does work.

I was asking for a faster method to do the second code, if it does exist.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:21 pm
by Jac de Lad
That's exactly what I said...

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:34 pm
by AMpos
Jac de Lad wrote:That's exactly what I said...
Problems of not speaking non-native language. :oops:

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:41 pm
by AMpos
NicTheQuick wrote:If a is of type Ascii, you will never be able to get a value above 255. It will always overflow. So you condition "a > 255" will never be true.

Code: Select all

b.a = 100
a.a = 200

a + b
Debug a ; shows 44
Well, it works like this without branching, and therefore the prefetching of your CPU can help to make it faster. But I never tested it. And I guess there will be an assembler instruction which can do all of this in one clock cycle:

Code: Select all

b.a = 100
a.u = 200

a = a + b

;1. version (assumes a and b were < 256 before the addition)
a = ((a >> 8) * $ff) | (a & $ff)

;2. version (works for every value of a and b)
;a = (Bool(a > 255) * $ff) | (a & $ff)

Debug a
My bad, the code I really need is this:

Code: Select all

define a.q, b.f

a=200: b=1.3

a=a*b
if a>255
 a=255
endif
I try to modify your code, but I am unable.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:42 pm
by Jac de Lad
Sorry for that. But I guess now it's clear to everyone.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 12:44 pm
by Jac de Lad
Btw, depending on how high the factor can be I think

Code: Select all

a=a*1.3
a=a-256*Mod(a,256)
would be safer
Not faster though...

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 1:38 pm
by Olli
not tested (from smartphone, sorry...)

Code: Select all

define.a a, b
a = 251
b = 6
! xor ax,ax ; reset registers
! xor bx,bx
! mov dx,65280 ; dh = 255
! mov ah, [v_a] ; input a and b values
! mov bh, [v_b]
! add ah,bh ; does the sum and updates carry flag if the result requires it
! cmovc ax,dx ; if carry is set, then ah = dh = 255
! mov [v_a], ah
debug a

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 1:41 pm
by Jac de Lad
I just realized that my solution is crap. Working but unnecessary...

If someone makes a function that could limit the top to 255 and bottom to 0 I would be very happy. I guess some of us could need that for graphics functions but I don't speak asm.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 1:48 pm
by Olli
Jac de Lad wrote:[...]and bottom to 0[...]
Please test asm code before, in the way it has already a bug you find. (just the version for over than 255 for now)

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 1:54 pm
by NicTheQuick
If you multiply an Ascii value with a Float there are many things happening in the background because numbers have to be converted between types. No wonder it is slow.
If you want to make it fast either use only Floats or only Integers but not both at the same time. You should use the format your original image data is stored with. I guess you are working with 24 or 32 bit image data and each color channel is a byte wide. Then you should definitely use integers. For your gamma problem I would suggest something like this:

Code: Select all

#IGammaShift = (SizeOf(Integer) - 2) * 8 - 1
#IGammaFactor = 1 << #IGammaShift

Define gamma.f = 1.3

;convert gamma value to integer BEFORE iterating over all the pixel values
Define iGamma.i

If gamma >= 256
	iGamma = #IGammaFactor << 8
Else
 	iGamma = gamma * #IGammaFactor
EndIf


; No iterate over the values and apply the gamma

Define a.i, ag.i

For a = 0 To 255
	ag = (a * iGamma) >> #IGammaShift
	ag = (ag | (Bool(ag > $ff) * $ff)) & $ff
	Debug "a = " + a + " -> " + ag
Next
So just precalculate `iGamma` beforehand and then do the thing in the loop for every channel and every pixel. Or try your `if` version again.

Re: If a>255: a=255?

Posted: Fri Oct 09, 2020 1:54 pm
by Jac de Lad
Seems to work, for 255.

I though of a function or macro like:

Code: Select all

Procedure Limit(iData)
If iData>255:iData=255:EndIf
If iData<0:iData=0:EndIf
ProedureReturn iData
EndProcedure
...just in asm.