From owner-freebsd-hackers Mon Nov 6 18:43:28 1995 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.6.12/8.6.6) id SAA29116 for hackers-outgoing; Mon, 6 Nov 1995 18:43:28 -0800 Received: from godzilla.zeta.org.au (godzilla.zeta.org.au [203.2.228.19]) by freefall.freebsd.org (8.6.12/8.6.6) with ESMTP id SAA29110 for ; Mon, 6 Nov 1995 18:43:21 -0800 Received: (from bde@localhost) by godzilla.zeta.org.au (8.6.9/8.6.9) id NAA07332; Tue, 7 Nov 1995 13:32:49 +1100 Date: Tue, 7 Nov 1995 13:32:49 +1100 From: Bruce Evans Message-Id: <199511070232.NAA07332@godzilla.zeta.org.au> To: bde@zeta.org.au, markd@grizzly.com Subject: Re: NPX still broken in 2.1.0-951104-SNAP... Cc: freebsd-hackers@freebsd.org, jkh@time.cdrom.com, julian@ref.tfs.com Sender: owner-hackers@freebsd.org Precedence: bulk >>I tried masking overflow and division by 0, leaving only invalid operand >>exceptions unmasked. This works quite well for detecting bugs without >>breaking things that IEEE arithmetic can do well: >> >> pow(0.0, -1.0) = Inf; >> int i = pow(0.0, -1.0) => SIGFPE >>... >Isn't pow (0.0, -1.0) return an error instead of SIGFPEing? Here is pow() returns OK (see the previous line of the test). Then the assignment to the int traps. It should trap because infinity can't be represented by an int. (For the same reason, 1/0 should trap although 1.0/0.0 doesn't.) >what the SCO manual page says: > The pow function returns 0 and sets errno to [EDOM] when x is 0 and y is > non-positive, or when x is negative and y is not an integer. In these > cases, a message indicating DOMAIN error is printed on the standard error. > When the correct value for pow would overflow or underflow, pow returns +/- > HUGE or 0 respectively, and sets errno to [ERANGE]. >Seems like its pretty straight forwarded to change __kernel_standard() to >return NaN instead of zero. Am I missing something? The 18 other cases handled by e_pow.c :-). pow(0.0, -1.0) isn't even a domain error for a version of pow() as careful as the one in e_pow.c (NaN would be returned for a domain error). >If there is not going to be another SNAP, it would obviously be foolish >to make this change beform the final. If there is going to be SNAP or too, >editing the 50 w_*.c files to save the old mask, zero it and then >restore it on exit would be pretty straight forward. I could probably The following works for acos(2.0): ----- *** w_acos.c~ Wed May 31 19:13:32 1995 --- w_acos.c Tue Nov 7 10:51:03 1995 *************** *** 33,39 **** --- 33,46 ---- return __ieee754_acos(x); #else double z; + int s = fpgetmask(); + if (s != 0) + fpsetmask(0); z = __ieee754_acos(x); + if (s != 0) { + fpresetsticky(FP_STKY_FLD); + fpsetmask(s); + } if(_LIB_VERSION == _IEEE_ || isnan(x)) return z; if(fabs(x)>1.0) { return __kernel_standard(x,x,1); /* acos(|x|>1) */ ---- (also #include in math_private.h). The fp functions generate poor code (`fnstcw; fnstenv; fldenv; ... fnstenv; fldenv; fnstenv; fldenv' plus bitfield fiddling where `fnstcw; fldcw; ... fnclex; fldcw' plus less bitfield fiddling would be sufficient). The (s != 0) test reduces the cost if all exceptions are already masked. I'm not sure whether isnan(), fabs() or __kernel_standard() can trap. If the can the the mask would have to be restored before each return. I wouldn't want to edit the files that much for a temporary change and would use another layer of wrapping. Bruce