Path: csiph.com!news.mixmin.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.std.c Subject: Re: casts and contraction of floating expressions Date: Mon, 27 Nov 2023 11:11:27 -0800 Organization: A noiseless patient Spider Lines: 56 Message-ID: <86jzq3vwo0.fsf@linuxsc.com> References: <20231122162220$3bc5@qaa.vinc17.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: dont-email.me; posting-host="7d98286dbd687c0424bff5d7e57fa81b"; logging-data="4090333"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18fcjGL5sWWKv/4LtmTS6ZP2AALQWDgmOc=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:UjdHoTlamT89xscDMgYnqY82db8= sha1:YC4y+qUleQbFs/0TNhEnYG7Ci9E= Xref: csiph.com comp.std.c:6602 Vincent Lefevre writes: > The C standard says in 6.5: > > A floating expression may be contracted, that is, evaluated as > though it were a single operation, thereby omitting rounding errors > implied by the source code and the expression evaluation method. > > with the following note: > > The intermediate operations in the contracted expression are > evaluated as if to infinite range and precision, while the final > operation is rounded to the format determined by the expression > evaluation method. [...] > > But it says nothing about casts, which are explicit conversion > operations that normally remove any intermediate extended precision, > as if they were assimilated to a real rounding operation (rather > than something that would just give an additional rounding error), > just like the rint() function. > > So my question is: > > In the following code > > volatile double a = 0x1.00000001p+0; > volatile double b = -1.0; > > printf ("%a\n", (double) (a * a) + b); > printf ("%a\n", (float) (a * a) + b); > > may the (double) (a * a) + b and (float) (a * a) + b FP expressions > be contracted with the use of a FMA, i.e. as if fma(a,a,b) were used? > > Based on my above remark, I would say "no". > > But GCC (at least until a 14.0.0 20231017 snapshot), Clang (at least > until version 17) and Intel's oneAPI compiler 2021.3.0.20210619 all > contract (double) (a * a) + b with the use of a FMA; thus they output > 0x1.000000008p-31 instead of 0x1p-31. > > However, these compilers do not contract (float) (a * a) + b: > they output 0x1p-31. It is rather surprising that they treat it > differently. I can see how an argument might be made that contraction is allowed for the (double) cast line, and not allowed for the line with the (float) cast. A good test to do would be the same exression but with a (long double) cast in place of the (double) or (float) cast. I think an argument could be made either way that contraction is allowed in that situation. I think I'm mostly on your side, the cast not preventing the contraction is unexpected and at least at first blush at odds with what else the standard says. I completely agree that the point needs clarifying.