From owner-freebsd-amd64@FreeBSD.ORG Mon Apr 18 22:20:10 2011 Return-Path: Delivered-To: freebsd-amd64@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 854BE1065680 for ; Mon, 18 Apr 2011 22:20:10 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 672CF8FC0C for ; Mon, 18 Apr 2011 22:20:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p3IMKA3G004114 for ; Mon, 18 Apr 2011 22:20:10 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p3IMKAYG004113; Mon, 18 Apr 2011 22:20:10 GMT (envelope-from gnats) Date: Mon, 18 Apr 2011 22:20:10 GMT Message-Id: <201104182220.p3IMKAYG004113@freefall.freebsd.org> To: freebsd-amd64@FreeBSD.org From: Bruce Evans Cc: Subject: Re: amd64/156464: fpsetprec does not work X-BeenThere: freebsd-amd64@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Bruce Evans List-Id: Porting FreeBSD to the AMD64 platform List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 22:20:10 -0000 The following reply was made to PR amd64/156464; it has been noted by GNATS. From: Bruce Evans To: Michirou & Cc: FreeBSD-gnats-submit@FreeBSD.org, freebsd-amd64@FreeBSD.org Subject: Re: amd64/156464: fpsetprec does not work Date: Tue, 19 Apr 2011 06:02:02 +1000 (EST) On Mon, 18 Apr 2011, Michirou & wrote: >> Description: > > In default, fpgetprec() returns FP_PE, but results show FP_PD. > if fpsetprec(FP_PE) is called, results are never changed. amd64 uses SSE except for long doubles, so fpsetprec() and no effect on the results for long doubles. Since the precision defaults to FP_PE on amd64, fpsetprec() can only be used to break long doubles on amd64, while on i386 the precision defaults to FP_PD and fpsetprec() is needed to unbreak this. fpsetprec() on i386 can also be used to: - break doubles by setting the precision to FP_PS - reduce the precision for floats by setting the precision to FP_PS. This is sometimes useful for getting the same precision for floats as on other arches like amd64, to test that nothing depends on the extra precision without being ifdefed for this. - give increased precision for floats and doubles by setting the precision to FP_PE. This may be useful, but is difficult to program. It requires almost never actually using floats or doubles, except for converting them to and from long double on input and output. > This is not happen on FreeBSD8.2-RELEASE i386 version. amd64 behaviour in this area hasn't changed. >> How-To-Repeat: > > #include > #include > #include > int main() > { > double a, b, c, d; This only uses doubles, so fpsetprec() has no effect on it. > > printf("fpgetprec %d\n", fpgetprec()); // 3 on amd64, 2 on i386 > > a = 10.0; > b = 2.718281810; > c = a / (b * b); > printf("%20.16e\n", c); // 1.3533528507465618e+00 on both > > fpsetprec(FP_PE); It is still 3 on amd64, but is not used for doubles. It was changed from 2 to 3 on i386. > a = 10.0; > b = 2.718281810; > c = a / (b * b); > printf("%20.16e\n", c); > // 1.3533528507465618e+00 on amd64 > // 1.3533528507465620e+00 on i386 So result is more accurate on i386, but this behaviour is fragile and requires more care to program than the above in general. With FP_PE on i386, b*b is evaluated in extra precision, but there is nothing to prevent it being stored to memory, which would lose its extra precision, especially since gcc doesn't understand precision stuff. In practice, gcc won't store to memory in the middle of a simple expression like the above, even with -O0, so the above works like you want. The careful version is: a = 10.0; b = 2.718281810; long double la, lb; la = a; lb = b; c = la / (lb * lb); /* compiler bugs -- extra precision not lost * yet unless there is an acidental or * forced store (-ffloat-store) */ printf("%20.16e\n", c); /* ABI gives a store which loses the bugs * so we see only double precision for * the result */ An even more careful version to avoid the compiler bugs by forcing a store for this variable only is: ... volatile double vc; vc = la / (lb * lb); c = vc; /* c reduced to double prec -- now ready for * output, but probably not useful for * furthe calculations */ -ffloat-store should never be used since it pessimizes speed and precision globally. > > exit(0); > } fpsetprec() is very unportable due to its only affecting the i387 register set. Even on i386, you can break its effect on doubles by using '-msse2 -mfpmath=sse'. This bug is the default for clang. Bruce