Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Mar 1999 13:56:30 -0500 (EST)
From:      "Crist J. Clark" <cjc@cc942873-a.ewndsr1.nj.home.com>
To:        gjb@comkey.com.au (Greg Black)
Cc:        cjclark@home.com, freebsd-questions@FreeBSD.ORG
Subject:   Re: FP Math
Message-ID:  <199903031856.NAA05394@cc942873-a.ewndsr1.nj.home.com>
In-Reply-To: <19990303083216.1046.qmail@alpha.comkey.com.au> from Greg Black at "Mar 3, 99 06:32:16 pm"

next in thread | previous in thread | raw e-mail | index | archive | help
Greg Black wrote,
> > > > #include <stdio.h>
> > > > 
> > > > int main()
> > > > {
> > > >   float a = -1.0e-41;
> > > 
> > > At this point your program has entered the domain of undefined
> > > behaviour and from here on the compiler is free to do absolutely
> > > anything it likes, including generating the code represented by
> > > the following fragment:
> > > 
> > >     execl("/bin/rm", "rm", "-rf", "/", 0);
> > >
> > > If you assign a double constant to a float and that constant is
> > > outside the range of the float (as defined precisely in the
> > > header <float.h>), then the behaviour is undefined.
> > 
> > OK, your sarcasm aside, now that you mention it, I see how assigning a
> > constant outside of the float range is different than running into
> > overflows during processing.
> 
> There was *no* sarcasm in what I wrote above, just facts --
> albeit unpalatable facts.

So, when I rolled my eyes at those who claim that C is a "dangerous"
language, I was wrong. A single typo in a constant expression will
erase my home diretory. I think the use of C should be stopped
everywhere in the world now. A typo in a constant expression could
produce undefined code, and undefined code could do _anything,_ like
inadvertantly finds a security hole in the kernel and sends a broken
packet out onto the local net, which triggers a before unknown bug in
the local router which floods the local and external nets with these
packets until the whole global Internet comes to a complete halt. Hey,
it could happen.

> I suggested the Standard for a very good reason.  It's the right
> place to get answers to this kind of question.  However, a few
> seconds with K&R2 will find the same thing I've been saying (in
> Section A6.4) if you don't want to read the Standard.

Ah, good. Now I understand why you had such objections to my silly
test programs. I was under the impression that converting from a
floating point type with higher overflow to one with lower was
defined. I was confused by the fact that the analogous operation is
defined for integer types.

> As for the hope that you can really coerce something with a
> cast, you can't (but I'm not going to get into the full saga of
> why that is here).  And, as a general rule, your cast above in:
> 
> >   b = (float)a;
> 
> is utterly pointless, since it describes the operation that is
> going to happen anyway.  Even Brian Kernighan and Dennis Ritchie
> have been known to put in a cast where they shouldn't have, so
> it's easy to get this wrong.  A good rule, however, is: "don't
> use casts".  (It's like that other good rule about not using
> gotos, which has to be broken sometimes too.)

Do you mean do not use casts in arithmetic operations? If you don't
use casts at all, you must get lots of grief from compilers when you
have all of those null pointers from memory allocations being assigned
to typed pointers. 

> > If my motivation is of any help, I have computational programs that
> > I sometimes run on my FreeBSD machine and sometimes on IRIX. The main
> > reason I sometimes resort to the IRIX is because I do not get the
> > pesky FP exceptions there.
> 
> So surely the sensible solution is to correct the bugs in your
> programs rather than persevere with trying to do things which
> are explicitly undefined?

I have fixed the bug in the test program. No casting goes on in the RL
programs that cause troublesome FPEs. I am still trying to get a
handle on how the FP works and where the problems are. It's been
getting more interesting. I have tossed aside the attempts to create
overflows by casting, since, a pointed out, they are undefined
operations. The program below (finally, I think) has no such issues
yet creates a SIGFPE core dump,

#include <stdio.h>
#include <floatingpoint.h>

int main()
{

  double a = 1e200;
  double b;

  printf("fpgetmask: %o\n",fpgetmask());

  printf("a:         %e\n",a);

  b = a*a;

  b = *(double *)(&b);

  printf("isinf:     %d\n",isinf(b));

  printf("isnan:     %d\n",isnan(b));

  printf("b:         %e\n",b);

  return 0;
}

Which returns, 

fpgetmask: 15
a:         1.000000e+200
isinf:     0
isnan:     0
Floating exception (core dumped)

I went back and checked and the previous programs do the same thing,
they have been core dumping in the fprintf(). So I tracked the problem
to vfprintf.c which dies at the line with the arrow (->),

		case 'e':
		case 'E':
		case 'f':
			goto fp_begin;
		case 'g':
		case 'G':
			if (prec == 0)
				prec = 1;
fp_begin:		if (prec == -1)
				prec = DEFPREC;
			if (flags & LONGDBL)
				/* XXX this loses precision. */
				_double = (double)GETARG(long double);
			else
->				_double = GETARG(double);
			/* do this before tricky precision changes */
			if (isinf(_double)) {
				if (_double < 0)
					sign = '-';
				cp = "Inf";
				size = 3;
				break;
			}
			if (isnan(_double)) {
				cp = "NaN";
				size = 3;
				break;
			}

Note the use of a gratuitous cast on the previous barnch of the
if-statement (and the fact that casting a long double to a double can
be undefined. GETARG() is a macro defined in the same file,

#define GETARG(type) \
        ((argtable != NULL) ? *((type*)(argtable[nextarg++])) : \
            (nextarg++, va_arg(ap, type)))

'argtable' is NULL at the time of death. 'va_arg' is also a macro
defined in /usr/include/stdarg.h, 

#define va_arg(ap, type) \
        (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))

'__va_size' is also defined in the same include file,

#define __va_size(type) \
        (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))

This all reduces to assigning '_double,'

   _double = *(double *)(ap)

As so, correct? But I do that in the code and it does not have an
issue with it. I am quite confused.

I have been digging into the isinf() code... but... energy... 
falling... I think I'll just put up with the annoyances of IRIX.
I don't know what is going on here.


BTW, I have forgotten to include this up to now,

[121:~] uname -a
FreeBSD pc252.mydomain.org 2.2.8-STABLE FreeBSD 2.2.8-STABLE #0: Mon Mar  1 14:25:39 EST 1999     cjc@pc252.mydomain.org:/mnt/jaz/src/sys/compile/PC252  i386

-- 
Crist J. Clark                           cjclark@home.com


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199903031856.NAA05394>