about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--math/test-misc.c37
-rw-r--r--sysdeps/i386/fpu/s_frexpl.S20
3 files changed, 63 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index b85c7d10be..ed1ddafee7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2000-12-03  Ulrich Drepper  <drepper@redhat.com>
+
+	* math/test-misc.c (main): Add tests for frexp.
+	Reported by Fred J. Tydeman <tydeman@tybor.com>.
+	* sysdeps/i386/fpu/s_frexpl.S: Don't overflow during the computation.
+
 2000-12-02  H.J. Lu  <hjl@gnu.org>
 
 	* locale/lc-time.c (_nl_init_era_entries): Pass L'\0' instead of
diff --git a/math/test-misc.c b/math/test-misc.c
index 515277f5ad..c0b8d0ff77 100644
--- a/math/test-misc.c
+++ b/math/test-misc.c
@@ -39,6 +39,43 @@ main (void)
 	result = 1;
       }
   }
+
+# if __GNUC__ >= 3 || __GNUC_MINOR__ >= 96
+  {
+    long double x = LDBL_MAX / ldexpl (1.0L, LDBL_MANT_DIG + 1);
+    long double m;
+    int i;
+
+#  if LDBL_MANT_DIG == 64
+    m = 0xf.fffffffffffffffp-4L;
+#  else
+#   error "Please adjust"
+#  endif
+
+    for (i = 0; i < LDBL_MANT_DIG + 1; ++i, x *= 2.0L)
+      {
+	long double r;
+	int e;
+
+	printf ("2^%d: ", LDBL_MAX_EXP - (LDBL_MANT_DIG + 1) + i);
+
+	r = frexpl (x, &e);
+	if (r != m)
+	  {
+	    printf ("mantissa incorrect: %.20La\n", r);
+	    result = 1;
+	    continue;
+	  }
+	if (e != LDBL_MAX_EXP - (LDBL_MANT_DIG + 1) + i)
+	  {
+	    printf ("exponent wrong %d (%.20Lg)\n", e, x);
+	    result = 1;
+	    continue;
+	  }
+	puts ("ok");
+      }
+  }
+# endif
 #endif
 
   {
diff --git a/sysdeps/i386/fpu/s_frexpl.S b/sysdeps/i386/fpu/s_frexpl.S
index cb943f74c2..2645d220ee 100644
--- a/sysdeps/i386/fpu/s_frexpl.S
+++ b/sysdeps/i386/fpu/s_frexpl.S
@@ -32,6 +32,12 @@
 	ASM_TYPE_DIRECTIVE(two64,@object)
 two64:	.byte 0, 0, 0, 0, 0, 0, 0xf0, 0x43
 	ASM_SIZE_DIRECTIVE(two64)
+	/* The following is LDBL_MAX / ldexp (1.0, 64), the largest
+	   number we can handle the normal way.  */
+	ASM_TYPE_DIRECTIVE(largest,@object)
+largest:
+	.byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbe, 0x7f, 0, 0
+	ASM_SIZE_DIRECTIVE(largest)
 
 #ifdef PIC
 #define MO(op) op##@GOTOFF(%edx)
@@ -63,12 +69,16 @@ ENTRY (BP_SYM (__frexpl))
 	cmpl	$0, %eax
 	je	2f
 
+	cmpl	$0x7fbe, %eax
+	ja	4f
+
 	fldt	VAL0(%esp)
 #ifdef	PIC
 	call	3f
 3:	popl	%edx
 	addl	$_GLOBAL_OFFSET_TABLE_+[.-3b], %edx
 #endif
+
 	fmull	MO(two64)	/* It's not necessary to use a 80bit factor */
 	movl	$-64, %ecx
 	fstpt	VAL0(%esp)
@@ -92,5 +102,15 @@ ENTRY (BP_SYM (__frexpl))
 
 	LEAVE
 	ret
+
+4:	movl	VAL2(%esp), %ecx
+	movl	%ecx, %edx
+	andl	$0x7fff, %ecx
+
+	andl	$0x8000, %edx
+	subl	$16382, %ecx
+	orl	$0x3ffe, %edx
+	movl	%edx, VAL2(%esp)
+	jmp	1b
 END (BP_SYM (__frexpl))
 weak_alias (BP_SYM (__frexpl), BP_SYM (frexpl))