From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00,FORGED_GMAIL_RCVD, FREEMAIL_FROM autolearn=no autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Natasha Kerensikova Newsgroups: comp.lang.ada Subject: Re: How to round to the nearest fixed-point value? Date: Sun, 26 Jan 2014 14:19:11 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Injection-Date: Sun, 26 Jan 2014 14:19:11 +0000 (UTC) Injection-Info: mx05.eternal-september.org; posting-host="31d6bde745a337034b005384ef225743"; logging-data="27119"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/ZzVffhfFDurZeiG0rtVWc" User-Agent: slrn/0.9.9p1 (FreeBSD) Cancel-Lock: sha1:Xv9RQr7HgzCv/o87chdaumMX7D4= Xref: news.eternal-september.org comp.lang.ada:18299 Date: 2014-01-26T14:19:11+00:00 List-Id: On 2014-01-24, Randy Brukardt wrote: > "Natasha Kerensikova" wrote in message >> In case anyone is interested, the following rewrite works around the >> problem: >> >> function Convert (Value : High) return Low is >> begin >> return Low'Round (Value * 1.0); >> end Convert; > > I believe the above should be illegal - but in any case, it's not clear from > the RM what this means. > > The only multiply operations available for fixed point types either have one > operand that is an integer (not the case above), or produce a > Universal_Fixed result. 4.5.5(19.1/2) requires that the result be used in a > context where the result type is identified, and specifically disallows the > result from being Universal_Fixed. > > The type of the operand of 'Round is Universal_Real. This appears to meet > the letter of the rule, but not the intent (which is that the expected type > determine the scaling and respresentation for the result). Could it be somehow be "made legal" by G.2.3(4), merging "*" and Low'Round into a single operation? (sounds a bit weird though, that would mean an optional annex affecting legality) This gets me worried, because in the "real" application where I encountered this, Low'Round (Value) is one possibility of a case statement, and all others are like Low'Round (Value * decimal_literal) most of those literals being more precise than what can be handled by High or Low (e.g. 6.55957). I expected the math to be handled properly, but maybe I should look a bit closer at those cases too. Is there a better way of expressing it? Maybe something along the lines of Low'Round (Value * High'(6.559) + (Value / 1000) * High'(0.57)) but with better thought on rounding. However I would expect the compiler to be better than me at coming up with a formula to accurately compute that. On a site note, using Low'Round (Value * 1) behave in the same (wrong?) way as Low'Round (Value). >> I would have thought that the optimizer would have quickly brought both >> version to the same generated code, but from -O0 to -O3 I get the >> correct rounding with the latter but not with the former. > > No, the result of the operand here is Universal_Real. I believe the language > says that runtime universal values are evaluated using the largest possible > numeric type; in this case, that would be a large float type. It's very > difficult to optimize out float operations (because of precision issues - > you have to be very careful that the precision of the result is the same > after optimization), so it probably can't be changed. So you're getting > vastly different code. Funnily, both versions lead to very similar code in GNAT internal ada-ish language (output by -gnatD): Low'Round (Value) yields: T2b : constant lib__TlowB := lib__TlowB?({lib__TlowB?(value #{/} 1.0E-2)}); Low'Round (Value * 1.0) yeilds: T2b : constant lib__TlowB := lib__TlowB?({lib__TlowB?(value #@{/} 1.0E-2)}); As far as 64-bit intel assembly code goes, it indeed looks vastly different, but it involves only integer arithmetic, without any obvious bound restriction. Thanks for your help, Natasha