modf.s   [plain text]

```
/*
*  modf.s
*
*      by Steve Canon (scanon)
*
*
*  Rewritten by Steve Canon in December '08 to fix
*  behavior of small signaling nans and to get the
*  sign of a zero fractional part correct.
*/

// double modf(double x, double *iptr);
//
// breaks x into integral and fractional parts, each of which has the same sign as the argument.
// the fractional part is returned, and iptr holds the integral part.
//
// Special Cases:
//
//		Input	Fractional Part		Integral Part
//		+-inf		+-0					+-inf
//		NaN			NaN					NaN

#if defined __i386__

.text
.align 4
.globl _modf
_modf:
movl	   8(%esp),		%eax	// high word of x
andl	   \$0x7fffffff,	%eax	// high word of |x|
subl	   \$0x3ff00000,	%eax	// subtract off exponent bias

movsd	   4(%esp),		%xmm0	// x
pcmpeqb		%xmm3,		%xmm3
psllq	   \$63,			%xmm3
movapd		%xmm3,		%xmm4	// set aside signbit mask for later use
andpd		%xmm0,		%xmm3	// signbit(x)

cmpl	   \$0x03400000,	%eax	// compare to unbiased 2**52
jae			1f

//	1.0 <= |x| < 2**52
shrl	   \$20,			%eax	// unbiased exponent of x
movl	   \$52,			%edx
subl		%eax,		%edx
movd		%edx,		%xmm2	// 52 - unbiased exponent of x
pcmpeqb		%xmm1,		%xmm1
psllq		%xmm2,		%xmm1	// mask for integral bits of x
andpd		%xmm0,		%xmm1	// trunc(x)
subsd		%xmm1,		%xmm0	// fractional part, except that sign of zero may be wrong
andnpd		%xmm0,		%xmm4	// |fractional part|
orpd		%xmm3,		%xmm4	// copysign(fractional part, x)

movl	  12(%esp),		%ecx	// iptr
movsd		%xmm4,	   4(%esp)
movsd		%xmm1,	    (%ecx)	// store integral part to iptr
fldl	   4(%esp)				// return fraction part on the x87 stack
retl

1:	movl	  12(%esp),		%ecx	// iptr
jge			2f

//	|x| < 1.0
movsd		%xmm3,		(%ecx)	// *iptr = copysign(0.0, x)
fldl	   4(%esp)				// fractional part = x
retl

2:	ucomisd		%xmm0,		%xmm0	// check for NaN
jp			3f

//	|x| >= 2**52
movsd		%xmm3,	   4(%esp)	// fractional part = copysign(0.0, x)
3:	movsd		%xmm0,		(%ecx)	// *iptr = x
fldl	   4(%esp)
retl

#else // __x86_64__

.const
.align 4
one:

.text
.align 4
.globl _modf
_modf:
andpd		%xmm0,		%xmm1	// |x|
movd		%xmm1,		%rax
xorpd		%xmm0,		%xmm1	// copysign(0.0, x)
subq	one(%rip),		%rax	// subtract off exponent bias
movq	   \$52,			%rcx
sarq		%cl,		%rax
cmpq		%rcx,		%rax	// compare exponent of x to 52
jae			1f

//	1.0 <= |x| < 2**52
subq		%rax,		%rcx	// 52 - unbiased exponent of x
pcmpeqb		%xmm2,		%xmm2
movd		%rcx,		%xmm3
psllq		%xmm3,		%xmm2	// mask for integral bits of x
andpd		%xmm0,		%xmm2	// trunc(x)
subsd		%xmm2,		%xmm0	// fractional part, except sign of zero may be wrong
andpd	absmask(%rip),	%xmm0	// |fractional part|
orpd		%xmm1,		%xmm0	// copysign(fractional part, x)
movsd		%xmm2,		(%rdi)	// *iptr = trunc(x)
retq

1:	jge			2f

//	|x| < 1.0
movsd		%xmm1,		(%rdi)	// *iptr = copysign(0.0, x)
retq

2:	ucomisd		%xmm0,		%xmm0	// check for NaN
jp			3f

//	|x| >= 2**52
movsd		%xmm0,		(%rdi)	// *iptr = x
movapd		%xmm1,		%xmm0	// fractional part = copysign(0.0, x)
retq

3:	movsd		%xmm0,		(%rdi)	// *iptr = x
retq

#endif // __ARCH__
```