From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 15 Nov 91 20:58:35 GMT From: sdd.hp.com!mips!murphy@hplabs.hpl.hp.com (Mike Murphy) Subject: Re: Red-faced professor gets bitten in search for portability Message-ID: <11919@spim.mips.COM> List-Id: In article <1991Nov15.185959.5002@milton.u.washington.edu> mfeldman@milton.u.wa shington.edu (Michael Feldman) writes: >Asked by students whether Ada has an equivalent of the Pascal "Trunc" >operation, which just returns the integer part of its argument, >I put together a function based on the old trick we used >in the Fortran days. > > FUNCTION Trunc (X: Float) RETURN Integer IS > BEGIN > RETURN Integer(X - 0.5); > END Trunc; > >Since conversion of Float to Integer is, in Ada, a rounding operation, >this looks like a good solution, right? WRONG! The trouble is that, >according to the LRM, the result of the conversion is implementation- >dependent if the fractional part of the float quantity lies just >between the two integers (that is, = 0.5). (LRM sect. 4.6) > >To see the hidden nastiness here, suppose Y has an integral value. >If Y = 10.0 (say), then Trunc(Y) returns 10 on compilers where the 0.5 >case rounds _up_, and returns 9 on compilers where the 0.5 case rounds >_down_. Oops! A simple bit of code falls right into a portability trap. > >The only solution seems to lie in forcing an integer division, since integer >division indeed truncates, portably. So our new function is > > FUNCTION Trunc (X: Float) RETURN Integer IS > BEGIN > RETURN Integer(2.0 * X) / 2; > END Trunc; > >which, I suppose, can be optimized efficiently, but seems like a >kludgy way to do a simple truncation. I think this is an example of >an operation that's much more easily done as an intrinsic than as >a programmer-defined function. > >Any thoughts in net-land? You are right about your first version not being portable, but your second version seems a bit convulated to me. Why not just check whether you indeed rounded down after doing the integer conversion? For example: FUNCTION Trunc (X: Float) RETURN Integer IS itrunc : integer = integer(x - 0.5); BEGIN if x - float(itrunc) >= 1.0 then -- rounded down, so add back a 1 return itrunc+1; else return itrunc; end if; END Trunc; --mike p.s. btw, some machines, e.g. MIPS, can either round down, or round up, or round to the even number (the default setting).