Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!uwm.edu!cs.utexas.edu!uunet!bfmny0!tneff From: tneff@bfmny0.UU.NET (Tom Neff) Newsgroups: comp.lang.perl Subject: Bad ulong cast on 80x86/87 machines Message-ID: <15335@bfmny0.UU.NET> Date: 8 Apr 90 03:41:24 GMT Reply-To: tneff@bfmny0.UU.NET (Tom Neff) Lines: 71 Ouch. Guess who else has problems with casting double to unsigned longs! Try this, 80x86 Perl users: perl -e '~~1' BOOM, right? Dies with my AT&T cc 4.1.5 anyway. Floating point exception. Here's the problem. Bitwise operators in Perl use unsigned long -- with Intel that's 32 bits. So ~1 yields 4294967294, which Perl stores as double float. You can print it (not printf "%d" though!), assign it, even add to it, no problem. But if you use it in an integer context (as a bitwise operand, for instance), Perl tries to cast the 'double' back to unsigned long and dies! The 80x87 only supports signed integers, so its range is -2147483648 <= x < 2147483647 and the attempt to store 4e+09 as a 32 bit integer blows up. The only solution is to use the castulong() function instead of the direct cast in C. But there are two problems. (1) Right now Configure doesn't test for the problem I just described, but only for problems casting SMALL negative floats (-123) to unsigned long, which the 80x87 does fine. So it doesn't even make use of castulong() on the 80x86 right now. The fix for this is for Configure to build this one-line program: unsigned long ul = 4294967295.0; and then try to compile it. If it compiles OK it probably means the direct cast will work. On my system you get "foo.c", line 1: floating point constant folding causes exception and a return code of 1 from cc. To create the test C file, you run main() { printf("unsigned long ul = %u.0;\n", (unsigned long) -1); } (2) Anyway, castulong() in its present form doesn't handle the condition -- it only checks for negative float values. It also has to check for large positives and fold them to negative before casting. Here is a tested patch to util.c that does this. *** /tmp/,RCSt1a00811 Sat Apr 7 22:55:33 1990 --- /tmp/,RCSt2a00811 Sat Apr 7 22:55:34 1990 *************** *** 1332,1337 **** --- 1335,1346 ---- double f; { long along; + + double longmax = 1+(((unsigned long) -1) / 2); + /* this should express LONG_MAX */ + + if (f >= longmax) + return (unsigned long)(f - longmax); if (f >= 0.0) return (unsigned long)f; -- The real problem with SDI is %/ Tom Neff that it doesn't kill anybody. /% tneff@bfmny0.UU.NET