Hello my ASM addicted friends. :thumbsup:
I have a question as a newbie that has surely a simple answer.
If I have to compare 1 million Integer number between themselves, and a million
Single precision numbers between themselves, which operation will cost more time?
Thanks for any help
Frank
Hi
Well formed REAL4 numbers can be compared using the CPU as if they were DWORDs.
Particular caution is required with infinities and NANs. If you can rule out these cases, the comparison should take the same amount of time.
Biterider
I don't know the answer, should be a testcase.
As noted, you can compare real4 as being dword integers, a xor instruction for equality gives you an answer.
New cpu's can use packed (paralell) comparisions, in one xmm (128 bits) register you can perform 4 real4 comparisions with 1 load to register operation, but if you have a 64 bits and using xor as a test for equality you can perform 2 comparisions at time spending 2 loads to register operations.
But, if you're trying to find for real4/8 bigger than, less than, I think packed instructions can do better; or you can try to mix logic/arithmetic operations with integers to do the same job (bit scan).
There is a long thread in the old forum (http://fpu%20compare%20real%20to%20integer%20problem) (it led to the Fcmp macro (http://www.jj2007.eu/MasmBasicQuickReference.htm#Mb1200)). Basically, the problem is that "equal" is a tough concept for floating point values. They rarely are equal. For example, PI is not 3.141592653589793238
I imagine that a float "1234.5678" can be compared to another float to see if its the same or different. Its when the numbers have many integers after the decimal point that the chances of an exact match become much harder. You could probably make a rounding theory set to a range that equated to a match or not, depends on the required precision level.
Thanks everybody for your answers.
My problem to solve is a bit more simple, and a bit more long, because I don't need to have
a perfect match for equal. I only need to test if a value is bigger or smaller than another one.
I also need to perform a subtraction in order to know also the
quantity of the difference between the two numbers.
Let's say, for a first example, that I need to know if the difference is >= +/-10.
The real situation is that I just have ASCII to represent the single digit, not real REAL NUMBERS.
So I have the ASCII "1234.1234" and I have to compare it with the ASCII "1246.2431".
The numbers are in the range NNNN.NNNN to NNNN.NNNN (four digits for integer part and the same for decimals. 8 digits in all.
It is a double step operation to do, I think.
First I have to to transform 2 STRINGS into 2 NUMBERS and then to compare them.
In my mind I think a feasible solution is to skip the decimal point, convert the STRING into a LONG INTEGER or a REAL NUMBER
and then subtract the two INTEGER/REAL numbers. Instead of testing for a difference of 10, I can test for 1,000 or 10,000 or 100,000
depending on the numbers of digit after the decimal point.
Moreover, because I don't need an extreme precision, but just a raw > 10 or < -10 difference between the two numbers, I could
probably skip the decimals without compromising my solution.
Any thought around this goal?
I have to find a fast way to convert a million strings into a million numbers.
Then I have to compare them for a difference of > +10 or < -10
Enjoy your day
I have been trying doing SIMD solution as exercise on ascii to float
Otherwise you get (digit-48)* with multipliers 1000,100,10,1,0.1,0.01,0.001,0.0001
And add together scalar
(8 subs,8 Fmul,7 adds) x 1 million, wonder if an ascii math library would be faster?
You really need to convert or just get an answer!?
I was thinking something like this, but need a bit more work and need check if really works:
align 4
output db "1000","1000","1000","1000","1000","1000","1000","1000"
db "0100","0100","0100","0100","0100","0100","0100","0100"
db "0010","0010","0010","0010","0010","0010","0010","0010"
db "0001","0001","0001","0001","0001","0001","0001","0001"
mov esi,"<"
mov edi,">"
mov eax,"1234" ;31323334h
mov ebx,"1246" ;31323436h
mov ecx,eax
xor ecx,ebx ;00000702h
jz after_dot ;integer part equal
and eax,ecx ;00000300h
and ebx,ecx ;00000402h
mov ecx,eax ;assume eax>ebx
mov edx,edi ;>
cmp eax,ebx ;.if eax > ebx, print ">", mov ecx,eax
cmovb ecx,ebx ;avoid jumps ;else print "<", mov ecx,ebx
cmovb edx,esi ;<
;print edx
bsr ecx,ecx ;count digits
;----------------------------
lea edx,output
mov eax,dword ptr [edx+ecx*4]
;print eax
jmp next_number
;----------------------------
.if ecx > 23
;print "1000"
.elseif ecx > 15
;print "100"
.elseif ecx > 7
;print "10"
.else
;print "1"
.endif
;----------------------------
jmp next_number
after_dot:
Oh, sorry, I now read your other post, ignore this message.
I currently don't know what you intend to do following your comparisons. You can have a peek at the attached code and adapt it to your needs if it may help you. It could be simplified a lot depending on the ultimate purpose.
;assuming:
;a) the numbers to be compared are in List1 and List2
;b) the numbers to be compared are always positive and are always 8 bytes long in the form of ascii text
; with an 'assumed' decimal point after the 4th integer digit
;c) if the integer part is less than 1000, it is padded with ascii spaces, i.e. 20h
xor ecx,ecx
lea esi,List1
lea edi,List2
mov eax,List1[ecx]
mov ebx,List2[ecx]
bswap eax
bswap ebx
and eax,0f0f0f0fh ;get rid of ascii code
and ebx,0f0f0f0fh ;id
cmp eax,ebx
jz equal ;their integer parts are equal
.if !CARRY? ;List1 number is greater
push eax ;AH could be affected
sub al,bl ;subtract lower digits
aas ;subtract adjust
mov dl,al ;store result
pop eax ;retrieves unchanged AH
mov al,ah
sbb al,bh ;subtract with carry 2nd lower digit
aas
mov dh,al ;store result
bswap edx
bswap eax
bswap ebx ;get to 3rd and 4th digits
push eax
xchg al,ah
sbb al,bh
aas
mov dh,al
pop eax
sbb al,bl
aas
mov dl,al
bswap edx
cmp edx,100h ;compare result of subtraction to 10
jbe nodiff
jmp list1_greater
.else ;subtract the List1 number from the List2 one
xchg eax,ebx
push eax ;AH could be affected
sub al,bl ;subtract lower digits
aas ;subtract adjust
mov dl,al ;store result
pop eax ;retrieves unchanged AH
mov al,ah
sbb al,bh ;subtract with carry 2nd lower digit
aas
mov dh,al ;store result
bswap edx
bswap eax
bswap ebx ;get to 3rd and 4th digits
push eax
xchg al,ah
sbb al,bh
aas
mov dh,al
pop eax
sbb al,bl
aas
mov dl,al
bswap edx
cmp edx,100h ;compare result of subtraction to 10
jbe nodiff
jmp list2_greater
.endif
nextone:
add ecx,8
cmp ecx,maxfilesize
jb start1
jmp finish
equal: ;the integer parts of both numbers are equal
;do whatever is needed
jmp nextone
nodiff: ;the integer parts of both numbers are within 10
;do whatever is needed
jmp nextone
list1_greater:
;do whatever is needed
jmp nextone
list2_greater:
;do whatever is needed
jmp nextone
Getting the difference of two ascii numbers was a little trickier than I had originally assumed.
Great raymond :thumbsup:
Please see my modified post (which will be made within a short time from now)
just some SIMD code,from my avxcalculator exercise
.data
mulint dq 0001000A006403E8h ;1000,100,10,1 in words
.code
movd xmm3, mulint
xorps xmm2,xmm2
mov eax, 030303030h
movd xmm2, eax
psubb xmm6, xmm2 ;subtract all bytes with 48
xorps xmm0, xmm0 ;xmm0=highbytes in unpack
PUNPCKLBW xmm6,xmm0 ; xmm0, xmm6 ;unpack bytes->words
pmullw xmm6, xmm3 ;1000*,100*,10*,1*
xorps xmm0,xmm0
PUNPCKLWD xmm6, xmm0
cvtdq2ps xmm6,xmm6
haddps xmm6,xmm6 ;horizontal add digit 1+2,digit 3+4
haddps xmm6,xmm6 ;horizontal add (1+2)+(3+4)
movss tmp2,xmm6