OT: missing C99 math pieces in gcc 4.x on Solaris 8 (sparc)

J

jacob navia

Le 06/06/11 15:09, Joel C. Salomon a écrit :
Not sure what you mean; the MinGW project supplies GCC running under
windows, without requiring a Cygwin/MSys UNIX-emulation layer.

Yes, but that compiler compiles C99 and uses a C90 library. So we
have had here all those beginners that ask why the C99 printf features
produce nonsense, etc.

(Of course, as you pointed out, since the MS C runtime it links to is
not C99-compliant, the best the compiler can do is present a
free-standing environment -- but with a library *resembling* that of a
hosted implementation. See also<http://mingw.org/wiki/C99>.)

--Joel

Yes, a "free standing" but with a library resembling a hosted
environment... That's another way of saying that it will
produce bugs without end.
 
D

David Mathog

If so, how do you cope with the other dependencies?  Not just technical,
but documentation.  Do you provide replacement man pages?

Not so much replacement pages as additional ones. For instance, it
might be in a different section or be called "gcc printf" so it
doesn't interfere with the system "printf" man page.

On a somewhat related note, anybody know of freely available source
for
a test program that exercises all the differences between c99 and c89?
 How about
linking to libraries built with the system libc?

Well, let's say that the underlying system is c89 and the compiler
wants to (really) support c99. That means any function that differs
needs a different version, and in some cases replacement header files
are needed, but in others [like for log()], not. Imagine then
"c99_features.h" which consists of something like:

#ifdef STDC99
#define log(a) c99_log(a)
#define fprintf() c99_fprintf() /* args omitted for brevity */
etc.
/* no difference between func() in c89 and c99? Then
no entry in here is needed. */
#endif /* STDC99 */

and the compiler provides a library libc99.a (or whatever). I don't
see what the problem would be, except if the underlying system simply
doesn't support some bit or test needed for c99 compliance (if such
bits or tests exist). When compiled with -std=c99 generated code
would actually call the c99_ routines and not the native ones. If the
program is linked to a library which is in turn linked to the system
library those would all use the native log() and fprintf(), and
presumably would not include any code that would exercise c99
features. Even if a pointer to a c99 routine is passed in to a native
lib function to be used as a callback, because of the defines, it
would be the c99_ version that is called, and those are presumably all
upwardly compatible.

I don't know, it just seems strange that user level code should be
forever tied to whatever C standard is provided by the system's libc.
Other languages do not have this constraint, and newer standards can
be supported on older platforms. Why should C be hobbled just because
the underlying OS happened to be written in the same language?

Anyway, for reference purposes, this is what I added to my program to
get it to compile on Solaris 8. With this it passes all but 5 of 172
tests, and of those 5 failures, 4 have to do with minor c99
incompatibilities (log(-1) returns -inf and not NaN, case differences
for inf/nan when output by fprintf, one instance where the result is
-0 instead of 0). The 5th test failure seems to be an algorithm
difference for tan(), where tan(pi/2) comes out slightly different
(and not inf in either case, but 16331239353195370.000000 vs.
16331778728383844.000000).
No c99 additions to printf were used, so that wasn't a problem:

#ifdef SOL8
#include <sys/inttypes.h> /* because no stdint.h, needed for
uintptr_t */
#include "sol8.h"
#else
#include <stdint.h> /* for uintptr_t */
#endif

where sol8.h is:

#if !defined(SOL8_GUARD)
#define SOL8_GUARD 1
#include <ieeefp.h> /* get Solaris FP_SNAN etc.*/

/* these are the C99 flags */
# define FP_NAN 0
# define FP_INFINITE 1
# define FP_ZERO 2
# define FP_SUBNORMAL 3
# define FP_NORMAL 4

# define NAN ( ((double) 0.0)/ ((double) 0.0) )

# define isnormal(x) (fpclass (x) >=
FP_NZERO ? FP_NORMAL : 0)
# define isinf(x) (fpclass (x) == FP_NINF || fpclass (x) ==
FP_PINF ? FP_INFINITE : 0)
# define isnan(x) (fpclass (x) == FP_SNAN || fpclass (x) ==
FP_QNAN ? FP_NAN : 0)
# define iszero(x) (fpclass (x) == FP_NZERO || fpclass (x) ==
FP_PZERO ? FP_ZERO : 0)
#define fmax(A,B) ( A>=B ? A : B)
#define fmin(A,B) ( A<=B ? A : B)
#define round(A) ( A >= 0 ? floor(A+0.5) : -floor(-A+0.5) )

int fpclassify(double x){
int status;
switch(fpclass(x)){
case FP_SNAN:
case FP_QNAN: status=FP_NAN; break;
case FP_NINF:
case FP_PINF: status=FP_INFINITE; break;
case FP_NDENORM:
case FP_PDENORM: status=FP_SUBNORMAL; break;
case FP_NZERO:
case FP_PZERO: status=FP_ZERO; break;
case FP_NNORM:
case FP_PNORM: status=FP_NORMAL; break;
}
return(status);
}

#endif /* SOL8_GUARD */





Regards,

David Mathog
 
I

Ian Collins

where sol8.h is:

#if !defined(SOL8_GUARD)
#define SOL8_GUARD 1
#include<ieeefp.h> /* get Solaris FP_SNAN etc.*/

/* these are the C99 flags */
# define FP_NAN 0
# define FP_INFINITE 1
# define FP_ZERO 2
# define FP_SUBNORMAL 3
# define FP_NORMAL 4

# define NAN ( ((double) 0.0)/ ((double) 0.0) )

# define isnormal(x) (fpclass (x)>=
FP_NZERO ? FP_NORMAL : 0)
# define isinf(x) (fpclass (x) == FP_NINF || fpclass (x) ==
FP_PINF ? FP_INFINITE : 0)
# define isnan(x) (fpclass (x) == FP_SNAN || fpclass (x) ==
FP_QNAN ? FP_NAN : 0)
# define iszero(x) (fpclass (x) == FP_NZERO || fpclass (x) ==
FP_PZERO ? FP_ZERO : 0)
#define fmax(A,B) ( A>=B ? A : B)
#define fmin(A,B) ( A<=B ? A : B)
#define round(A) ( A>= 0 ? floor(A+0.5) : -floor(-A+0.5) )

int fpclassify(double x){

Shouldn't this be declared "inline"?
 
D

David Mathog

Shouldn't this be declared "inline"?

probably, but since the final version is compiled with gcc -O3, that
happens anyway.

Here is one more piece in the puzzle, making the Solaris log (probably
any log) C99 compatible:

# define log(x) ( x < 0 ? NAN : log(x) )

Regards,

David Mathog
 
K

Keith Thompson

David Mathog said:
probably, but since the final version is compiled with gcc -O3, that
happens anyway.

Here is one more piece in the puzzle, making the Solaris log (probably
any log) C99 compatible:

# define log(x) ( x < 0 ? NAN : log(x) )

There's a domain error for negative arguments, and a possible range
error for an argument of 0. Should there be special handling for
x==0, or does the Solaris log already handle that correctly?

(And "x" should be "(x)" in the macro definition, but that still
fails if the argument has side effects.)
 
D

David Mathog

There's a domain error for negative arguments, and a possible range
error for an argument of 0.  Should there be special handling for
x==0, or does the Solaris log already handle that correctly?

log(0) was already emitting -Inf on Solaris. log() sets errno
properly
on Solaris:

dv=log(0.0);
fprintf(stdout,"log 0 errno %d\n",errno);
dv=log(-1.0);
fprintf(stdout,"log -1 errno %d\n",errno);

prints

log 0 errno 34
log -1 errno 33

as it does on Linux.

As long as we're on the subject, it turns out my round() wasn't good
enough either, it was rounding -0 to 0, so instead of this:

#define round(A) ( A >= 0 ? floor(A+0.5) : -floor(-A+0.5) )

it should be this:

#define round(A) ( (A) > 0 ? floor((A)+0.5) : \
( (A) < 0 ? -floor(-(A)+0.5) : (A) ) )

Regards,

David Mathog
 
I

Ian Collins

probably, but since the final version is compiled with gcc -O3, that
happens anyway.

The inline is required for linkage, not optimisation. The function was
defined in a header, so it must be declared inline if that header is
included in more than one compilation unit.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top