Author Topic: Problem with calculating root  (Read 14933 times)

Offline andyz74

  • Jr. Member
  • *
  • Posts: 29
Problem with calculating root
« on: January 29, 2025, 09:35:26 PM »
Hello all of you,
I am sure, this is a absolutely stupid failure of mine, but I don' get it...  so, please have a look and see, if you are able to find the problem

Code: [Select]
get_wu:
mov rbx, qword [para_w] ; load my value to rbx to ensure I can see in debugger if it is right
movsd xmm1, qword [para_w]                                ;  get my value to xmm1 
sqrtsd xmm0, xmm1                                          ; take root of xmm1 and save it to xmm0
cvttsd2si rbx, xmm0                                               ; convert (and truncate) xmm0 to integer and store it in rbx
inc rbx
ret


in the debugger I see, that rbx and xmm1 are correct loaded with my value,
after the sqrtsd , I see "something" in xmm0, which I assume it is my packed calculated root
and after the cvttsd2si, I have always 0 (zero)  in my rbx. not a correct calculated root.

Please, what am I doing wrong?

Note:  I do not need the correct root, but the integer part has to be correct.  (sqrt(10)  => 3) is good for me

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 383
  • Country: br
Re: Problem with calculating root
« Reply #1 on: January 30, 2025, 06:47:16 PM »
First of all: What do you want to do?

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 383
  • Country: br
Re: Problem with calculating root
« Reply #2 on: January 30, 2025, 07:07:16 PM »
I'll assume you just want to extract the square root of an integer value and get an integer result using `sqrtsd` instruction...

First: double type has 53 bits of precision and 11 bits in the expoent of the scale factor plus the signal bit. This means a double is 64 bits long (but with less precision than an long long int)... Let's say your function is defined to obey SysV ABI for x86-64 (not for Windows):

Code: [Select]
; unsigned long long int sqrtroot( unsigned long long int x );
; Entry: RDI = x
; Exit: RAX
  global sqrtroot

  align 4
sqrtroot:
  cvtsi2sd xmm0,rdi      ; Convert RDI to double scalar in XMM0.
  sqrtsd xmm0,xmm0       ; xmm0 = sqrt(xmm0)
  cvtsd2si rax,xmm0      ; Convert XMM0 double scalar to RAX (this convertion applies rounding).
  ret
For Windows change RDI to RCX.

If you want to use unsigned int, instead, you need to zero the upper 32 bits of RDI:
Code: [Select]
; unsigned int sqrtroot( unsigned int x );
; Entry: EDI = x
; Exit: EAX
  global sqrtroot

  align 4
sqrtroot:
  mov edi,edi
  cvtsi2sd xmm0,rdi      ; Convert RDI to double scalar in XMM0.
  sqrtsd xmm0,xmm0       ; xmm0 = sqrt(xmm0)
  cvtsd2si rax,xmm0      ; Convert XMM0 double scalar to RAX (this convertion applies rounding).
  ret
PS: GCC makes sure the upper double from xmm0 is zero beginning with pxor xmm0,xmm0, but we don't need to do this since we're dealing only with an scalar...
« Last Edit: January 30, 2025, 07:17:10 PM by fredericopissarra »

Offline andyz74

  • Jr. Member
  • *
  • Posts: 29
Re: Problem with calculating root
« Reply #3 on: January 30, 2025, 07:31:00 PM »
This works great! Many thanks, Frederico!

For learning purposes I try to make programs to find primes. And to reduce calculation times I will divide the actual number through a cycle from [sqrt(actual number)] downto 3.   (I test only the odd ones...)
Therefor I need to calculate the squareroots.

Many thanks, I've learned just a little bit. :-)

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 383
  • Country: br
Re: Problem with calculating root
« Reply #4 on: January 30, 2025, 07:44:59 PM »
A note of caution... If you intend to calculate the square root of an unsigned long long int, the double precision has only 53 bits of precision (while unsigned long long int has 64)... So the first example is insufficient: You need a bigger floating point precision that is not available to SSE... You must use fp87 instead:
Code: [Select]
; Input: RDI = x
; Output RAX = sqrt(x)
squareroot:
  fild qword [rsp-8],rdi   ; using red zone here.
  fsqrt
  fistp qword [rsp-8]
  mov rax,[rsp-8]
  ret

Offline andyz74

  • Jr. Member
  • *
  • Posts: 29
Re: Problem with calculating root
« Reply #5 on: January 30, 2025, 08:04:23 PM »
I have another version of my program, in which I use the fp87 for getting the squareroot.  I test both.

The huge amount of divisions to see, what is prime and what not, is in the moment done by normal DIV command. But later, I will try to do this with fp87, and a third version to do it with sse2.

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 383
  • Country: br
Re: Problem with calculating root
« Reply #6 on: January 30, 2025, 08:44:01 PM »
I have another version of my program, in which I use the fp87 for getting the squareroot.  I test both.

The huge amount of divisions to see, what is prime and what not, is in the moment done by normal DIV command. But later, I will try to do this with fp87, and a third version to do it with sse2.

You don't need floating point or square root... Here:
Code: [Select]
_Bool isprime( unsigned int n )
{
  unsigned int d;
  unsigned long long int f;

  if ( n <= 3 )
    return n >= 2;

  d = n % 6;
  if ( d != 1 && d != 5 )
    return 0;

  for ( f = 5; f * f <= n; f += 2 )
    if ( ( n % f ) == 0 )
      return 0;

  return 1;
}
« Last Edit: January 31, 2025, 11:41:30 PM by fredericopissarra »

Offline andyz74

  • Jr. Member
  • *
  • Posts: 29
Re: Problem with calculating root
« Reply #7 on: January 30, 2025, 09:37:52 PM »
Main topic for me is  learning Assembler a bit. :-)
Good night now, in Germany we habe 10 pm, time to sleep.