From owner-freebsd-questions Wed Mar 3 10:48:43 1999 Delivered-To: freebsd-questions@freebsd.org Received: from cc942873-a.ewndsr1.nj.home.com (cc942873-a.ewndsr1.nj.home.com [24.2.89.207]) by hub.freebsd.org (Postfix) with ESMTP id 638F515011 for ; Wed, 3 Mar 1999 10:48:24 -0800 (PST) (envelope-from cjc@cc942873-a.ewndsr1.nj.home.com) Received: (from cjc@localhost) by cc942873-a.ewndsr1.nj.home.com (8.9.3/8.8.8) id NAA05394; Wed, 3 Mar 1999 13:56:30 -0500 (EST) (envelope-from cjc) From: "Crist J. Clark" Message-Id: <199903031856.NAA05394@cc942873-a.ewndsr1.nj.home.com> Subject: Re: FP Math In-Reply-To: <19990303083216.1046.qmail@alpha.comkey.com.au> from Greg Black at "Mar 3, 99 06:32:16 pm" To: gjb@comkey.com.au (Greg Black) Date: Wed, 3 Mar 1999 13:56:30 -0500 (EST) Cc: cjclark@home.com, freebsd-questions@FreeBSD.ORG Reply-To: cjclark@home.com X-Mailer: ELM [version 2.4ME+ PL40 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-freebsd-questions@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG Greg Black wrote, > > > > #include > > > > > > > > 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 ), 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 #include 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