Bug 23103 - <math.h> lacks many ISO C99 features (NAN, isfinite,...)
Summary: <math.h> lacks many ISO C99 features (NAN, isfinite,...)
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: misc (show other bugs)
Version: 4.2-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: Bill Fenner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2000-11-26 02:20 UTC by pfeifer
Modified: 2004-02-17 17:18 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description pfeifer 2000-11-26 02:20:00 UTC
	<math.h> AKA /usr/include/math.h lacks a couple of features
	required by ISO C99. ISO compliant programs will thus fail to
 	compile; one (more or less) prominent one is Wine.

	Features missing include macros FP_INFINITE, FP_NAN, FP_NORMAL,
	FP_SUBNORMAL, FP_ZERO, fpclassify(), and isfinite().

Fix: 

Implement the following (and probably further macros); the
	descriptions are copied from a draft of ISO C99.

       7.12  Mathematics <math.h>

       [#6] The macros

               FP_INFINITE
               FP_NAN
               FP_NORMAL
               FP_SUBNORMAL
               FP_ZERO

       are for number classification.  They represent the  mutually
       exclusive  kinds  of  floating-point values.  They expand to
       integer constant expressions with distinct values.

       7.12.3.1  The fpclassify macro

       Synopsis

       [#1]

               #include <math.h>
               int fpclassify(real-floating x);

       Description

       [#2]  The  fpclassify macro classifies its argument value as
       NaN,  infinite,  normal,  subnormal,  or  zero.   First,  an
       argument  represented  in  a  format wider than its semantic
       type is converted to its semantic type.  Then classification
       is based on the type of the argument.184)

       Returns

       [#3]  The  fpclassify  macro returns the value of the number
       classification  macro  appropriate  to  the  value  of   its
       argument.

       [#4]  EXAMPLE  The  fpclassify macro might be implemented in
       terms of ordinary functions as

               #define fpclassify(x) \
                       ((sizeof (x) == sizeof (float)) ? \
                               __fpclassifyf(x) \
                       : (sizeof (x) == sizeof (double)) ? \
                               __fpclassifyd(x) \
                       :       __fpclassifyl(x))


       7.12.3.2  The isfinite macro

       Synopsis

       [#1]

               #include <math.h>
               int isfinite(real-floating x);

       Description

       [#2] The isfinite macro determines whether its argument  has
       a finite value (zero, subnormal, or normal, and not infinite
       or NaN).  First, an argument represented in a  format  wider
       than  its  semantic  type is converted to its semantic type.
       Then determination is based on the type of the argument.

       Returns

       [#3] The isfinite macro returns a nonzero value if and  only  
       if its argument has a finite value.
Comment 1 Garrett A. Wollman 2000-11-26 02:28:17 UTC
<<On Sun, 26 Nov 2000 03:12:55 +0100 (CET), pfeifer@dbai.tuwien.ac.at (Gerald Pfeifer) said:

>> Synopsis:       <math.h> lacks many ISO C99 features (NAN, isfinite,...)

That's because we don't have a C99 compiler.  Some of these will need
to be implemented in the library, sure, but I don't see any rush.

-GAWollman
Comment 2 pfeifer 2000-11-26 02:41:47 UTC
On Sat, 25 Nov 2000, Garrett Wollman wrote:
> That's because we don't have a C99 compiler.  Some of these will need
> to be implemented in the library, sure, but I don't see any rush.

First of all, you don't exactly need a C99 compiler to have a (mostly)
C99 library.


Second, GCC 3.0 will be a (nearly fully compliant) C99 compiler, so
FreeBSD 5.0 will need this at the very latest, I guess.

Current snapshots of GCC are (nearly fully compliant) already, so -CURRENT
users do have a (nearly fully compliant) C99 compiler as do 4.x users
compiling GCC on their own.


And finally, but probably most important: GLIBC 2.1 and especially GLIBC
2.2 are already closely compliant, so many developers will now use C99
library features -- as evidenced by Wine (where I just had to hack around
FreeBSD being limited) and surely other programs as well.

So, in my opinion, this is a critical issue if we want to avoid the -- all
too common impression among users -- that FreeBSD is playing catch up. :-(

Gerald
-- 
Gerald "Jerry" pfeifer@dbai.tuwien.ac.at http://www.dbai.tuwien.ac.at/~pfeifer/
Comment 3 Mike Barcroft freebsd_committer 2002-04-29 22:55:20 UTC
Responsible Changed
From-To: freebsd-bugs->standards


Assign this to -standards, until someone volunteers to implement these 
C99 additions to <math.h>.
Comment 4 dschultz 2002-05-09 11:09:26 UTC
Thus spake Gerald Pfeifer:
> <math.h> AKA /usr/include/math.h lacks a couple of features
> required by ISO C99. ISO compliant programs will thus fail to
> compile; one (more or less) prominent one is Wine.
> 
> Features missing include macros FP_INFINITE, FP_NAN, FP_NORMAL,
> FP_SUBNORMAL, FP_ZERO, fpclassify(), and isfinite().

I've made some patches to add most of these features for i386.  The
remaining ones are mostly trivial extensions to the ones I've already
added.  I would just like to get some assurance that I'm on the right
track with these changes before I go ahead and write the rest of the
C99 stuff for all supported architectures.  Notes:

- Some of the symbolic constants in math.h are architecture-dependant,
  and I don't know if anything special needs to be done about this.
  Architecture-dependent assumptions are:
    o ints are 32 bits					FP_ILOG*
    o doubles are 64-bit IEEE 754's			DECIMAL_DIG
    o `long double' is an appropriate choice for	FLT_EVAL_METHOD
      float_t and double_t

- The necessary support needs to be added to libc in all architectures
  before the math.h changes can be committed.  The i386 code I wrote
  should work fine on any architecture on which floats, doubles, and
  long doubles have 32, 64, and 80 bits of precision, respectively,
  but fpclassify() can be done more efficiently on 64-bit architectures.

Please CC me any responses; I'm not subscribed to -standards.

Here are the patches:

Index: math.h
===================================================================
RCS file: /home/ncvs/src/lib/msun/src/math.h,v
retrieving revision 1.8.2.2
diff -u -r1.8.2.2 math.h
--- math.h	2001/11/23 16:16:18	1.8.2.2
+++ math.h	2002/05/09 09:35:02
@@ -21,7 +21,39 @@
  * ANSI/POSIX
  */
 extern char __infinity[];
+extern char __infinity_f[];
+extern char __infinity_l[];
+extern char __nan[];
 #define HUGE_VAL	(*(double *) __infinity)
+#define HUGE_VALF	(*(float *) __infinity_f)
+#define HUGE_VALL	(*(long double *) __infinity_l)
+#define INFINITY	HUGE_VALF
+#define NAN		(*(float *) __nan)
+#define FP_ILOGB0	(-0x7fffffff - 1)	/* INT_MIN */
+#define FP_ILOGBNAN	0x7fffffff		/* INT_MAX */
+#define DECIMAL_DIG	15
+
+#define FLT_EVAL_METHOD	2
+typedef long double float_t;
+typedef long double double_t;
+
+/* Symbolic constants to classify floating point numbers */
+#define FP_INFINITE	1
+#define FP_NAN		2
+#define FP_NORMAL	3
+#define FP_SUBNORMAL	4
+#define FP_ZERO		5
+#define fpclassify(x) \
+	((sizeof (x) == sizeof (float)) ? \
+		__fpclassifyf(x) \
+	: (sizeof (x) == sizeof (double)) ? \
+		__fpclassifyd(x) \
+	:       __fpclassifyl(x))
+
+/* XXX missing: C99 7.12.7 FP_FAST_FMA*
+ *     need to add or fix up isfinite(), isinf(), isnan(),
+ *                           isnormal(), signbit()
+ */
 
 /*
  * XOPEN/SVID
Index: Makefile.inc
===================================================================
RCS file: /home/ncvs/src/lib/libc/i386/gen/Makefile.inc,v
retrieving revision 1.10.2.1
diff -u -r1.10.2.1 Makefile.inc
--- Makefile.inc        2001/02/07 00:12:45     1.10.2.1
+++ Makefile.inc        2002/05/09 09:57:13
@@ -1,5 +1,5 @@
 #      @(#)Makefile.inc        8.1 (Berkeley) 6/4/93
 # $FreeBSD: src/lib/libc/i386/gen/Makefile.inc,v 1.10.2.1 2001/02/07 00:12:45 peter Exp $
 
-SRCS+= _setjmp.S alloca.S fabs.S frexp.c infinity.c isinf.c ldexp.c modf.S \
-       rfork_thread.S setjmp.S sigsetjmp.S
+SRCS+= _setjmp.S alloca.S fabs.S fpclassify.c frexp.c infinity.c isinf.c \
+       ldexp.c modf.S rfork_thread.S setjmp.S sigsetjmp.S
Index: infinity.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/i386/gen/infinity.c,v
retrieving revision 1.5
diff -u -u -r1.5 infinity.c
--- infinity.c  1999/08/27 23:59:21     1.5
+++ infinity.c  2002/05/09 09:44:05
@@ -7,3 +7,8 @@
 
 /* bytes for +Infinity on a 387 */
 char __infinity[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
+char __infinity_f[] = { 0, 0, 0x80, 0x7f };
+char __infinity_l[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f, 0, 0 };
+
+/* bytes for NaN */
+char __nan[] = { 0, 0, 0xc0, 0x7f };

--- /dev/null	Thu May  9 02:44:57 2002
+++ fpclassify.c	Wed May  8 06:30:05 2002
@@ -0,0 +1,81 @@
+/*
+ * $FreeBSD: $
+ */
+
+#include <sys/types.h>
+#include <math.h>
+
+int
+__fpclassifyf(f)
+	float f;
+{
+	register union flt2d {
+		float fv;
+		u_int32_t dv;
+	} u;
+
+	u.fv = f;
+	u.dv &= 0x7fffffff;
+	if (u.dv == 0)
+		return FP_ZERO;
+	else if (u.dv < 0x00800000)
+		return FP_SUBNORMAL;
+	else if (u.dv == 0x7f800000)
+		return FP_INFINITE;
+	else if (u.dv > 0x7f800000)
+		return FP_NAN;
+	else
+		return FP_NORMAL;
+}
+
+int
+__fpclassifyd(d)
+	double d;
+{
+	register struct IEEEdp {
+		u_int manl : 32;
+		u_int manh : 20;
+		u_int  exp : 11;
+		u_int sign :  1;
+	} *p = (struct IEEEdp *)&d;
+
+	if (p->exp == 0) {
+		if ((p->manl | p->manh) == 0)
+			return FP_ZERO;
+		else
+			return FP_SUBNORMAL;
+	} else if (p->exp == 2047) {
+		if ((p->manl | p->manh) == 0)
+			return FP_INFINITE;
+		else
+			return FP_NAN;
+	} else
+		return FP_NORMAL;
+}
+
+int
+__fpclassifyl(l)
+	long double l;
+{
+	register struct IEEElp {
+		u_int manl : 32;
+		u_int manh : 31;
+		u_int  exp : 16;
+		u_int sign :  1;
+		u_int junk : 16;
+	} *p = (struct IEEElp *)&l;
+
+        if (p->exp == 0) {
+                if ((p->manl | p->manh) == 0)
+                        return FP_ZERO;
+                else
+                        return FP_SUBNORMAL;
+        } else if (p->exp == 32767) {
+                if ((p->manl | p->manh) == 0)
+                        return FP_INFINITE;
+                else
+                        return FP_NAN;
+        } else
+                return FP_NORMAL;
+
+}
Comment 5 pfeifer 2002-05-15 18:21:11 UTC
On Thu, 9 May 2002, David Schultz wrote:
>> Features missing include macros FP_INFINITE, FP_NAN, FP_NORMAL,
>> FP_SUBNORMAL, FP_ZERO, fpclassify(), and isfinite().
> I've made some patches to add most of these features for i386.  The
> remaining ones are mostly trivial extensions to the ones I've already
> added.

Cool.  Unfortunately, I'm not enough of an expert to be really able to
review your improvements in detail, but have only been bitten by missing
features while maintaining our emulators/wine port.

But apart from isfinite(), everything originally require by Wine seems
to be there with your patch, thanks!

(Hopefully someone with more in-depth knowledge than me will review
your patch soon!)

Gerald
-- 
Gerald "Jerry" pfeifer@dbai.tuwien.ac.at http://www.dbai.tuwien.ac.at/~pfeifer/
Comment 6 dschultz 2002-05-15 19:55:01 UTC
Thus spake Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at>:
> But apart from isfinite(), everything originally require by Wine seems
> to be there with your patch, thanks!

isfinite() is a really easy addition, since it's just a special case
of fpclassify().  I just want to verify that someone is willing to
support the work before I finish hacking up math.h and research any
changes necessary for architectures other than i386.
Comment 7 dschultz 2002-09-07 03:16:10 UTC
I no longer have the time and interest to implement the rest of
C99 math, and nobody else seems to care either.  Upon request, I
can provide some old patches that are more extensive than the ones
I posted to this PR and address a bug.
Comment 8 harry685 2002-09-11 02:03:26 UTC
Why not have an "is()" function that can do all of this?  Here is the x86 source code for is():

PROC IS
PUSH BP
MOV BP,SP
FLD [BP+4]
FTST
;Get the status register from the FPU into AX
AND AX,[BP+10]
FCOMP
POP BP
RET
ENDP IS

And here is the addition to math.h:

int is(double x, int bitmask);

Lucas Thode
Comment 9 Mike Barcroft freebsd_committer 2002-09-16 03:51:41 UTC
Responsible Changed
From-To: standards->fenner


Over to Bill Fenner.
Comment 10 KAREN THODE 2003-05-18 01:55:15 UTC
I made an error in my original posting.  The ftst opcode should be changed to fxam.

Lucas
Comment 11 Lukas Ertl 2003-07-01 14:26:07 UTC
Hi there,

I think that PR misc/23103 can be closed, most if not all of that stuff is
in -CURRENT.

regards,
le

--=20
Lukas Ertl                             eMail: l.ertl@univie.ac.at
UNIX-Systemadministrator               Tel.:  (+43 1) 4277-14073
Zentraler Informatikdienst (ZID)       Fax.:  (+43 1) 4277-9140
der Universit=E4t Wien                   http://mailbox.univie.ac.at/~le/
Comment 12 Colin Percival freebsd_committer 2004-02-17 17:17:30 UTC
State Changed
From-To: open->closed

Fixed about a year ago.