SQRT using FPU

Programming, for all ages and all languages.
Post Reply
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

SQRT using FPU

Post by AlfaOmega08 »

Sometimes ago I found a small asm inline code for gcc.
I've unfortunately lost it.
I need it to "double sqrt(double x);"...

Does anyone know how to do it?
Else, I've to implement the Newton or Babilonian method :'(

Thanks in advance...
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

I thought there was a sqrt instruction... did you check the manuals?
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

Post by AlfaOmega08 »

I remember there are lots of fpu instructions like this:
fsqrt
fsin
fcos
ftan
[...]
But you have to store and read values in fpu registers, and there is specific inline asm to do that
User avatar
lukem95
Member
Member
Posts: 536
Joined: Fri Aug 03, 2007 6:03 am
Location: Cambridge, UK

Post by lukem95 »

the linux kernel has a whole section in arch/i386/math-emu

but it looks complex as hell:

Code: Select all

static void fsqrt_(FPU_REG *st0_ptr)
{
  char st0_tag = st0_ptr->tag;

  clear_C1();
  if ( !(st0_tag ^ TW_Valid) )
    {
      int expon;
      
      if (st0_ptr->sign == SIGN_NEG)
	{
	  arith_invalid(st0_ptr);  /* sqrt(negative) is invalid */
	  return;
	}

#ifdef DENORM_OPERAND
      if ( (st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) )
	return;
#endif DENORM_OPERAND

      expon = st0_ptr->exp - EXP_BIAS;
      st0_ptr->exp = EXP_BIAS + (expon & 1);  /* make st(0) in  [1.0 .. 4.0) */
      
      wm_sqrt(st0_ptr, control_word);	/* Do the computation */
      
      st0_ptr->exp += expon >> 1;
      st0_ptr->sign = SIGN_POS;
    }
  else if ( st0_tag == TW_Zero )
    return;
  else if ( st0_tag == TW_Infinity )
    {
      if ( st0_ptr->sign == SIGN_NEG )
	arith_invalid(st0_ptr);  /* sqrt(-Infinity) is invalid */
      return;
    }
  else
    { single_arg_error(st0_ptr); return; }

}
~ Lukem95 [ Cake ]
Release: 0.08b
Image
nick8325
Member
Member
Posts: 200
Joined: Wed Oct 18, 2006 5:49 am

Post by nick8325 »

glibc uses the following (public domain) code:

Code: Select all

double sqrt (double x)
{
  double res;
  asm ("fsqrt" : "=t" (res) : "0" (x));
  return res;
}
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

Post by AlfaOmega08 »

Thanks nick
It's exactly wath was I looking for
User avatar
bluecode
Member
Member
Posts: 202
Joined: Wed Nov 17, 2004 12:00 am
Location: Germany
Contact:

Post by bluecode »

lukem_95 wrote:the linux kernel has a whole section in arch/i386/math-emu
Well, from the pathname it should be obvious, that the code you presented tries to emulate the FPU behaviour (if no FPU is present or if it is deactivated through the bit in Cr0).
User avatar
lukem95
Member
Member
Posts: 536
Joined: Fri Aug 03, 2007 6:03 am
Location: Cambridge, UK

Post by lukem95 »

i did wonder now you mention it, i thought it had something to do with... i don't know actually.

it may have been useful anyway
~ Lukem95 [ Cake ]
Release: 0.08b
Image
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post by Solar »

Note that sqrt() is defined to either set errno = EDOM or to raise an invalid floating point exception in case that the parameter is < 0. This can be quite tricky to get right and efficient.
Every good solution is obvious once you've found it.
Post Reply