comp.lang.ada
 help / color / mirror / Atom feed
From: "Robert I. Eachus" <rieachus@attbi.com>
Subject: Re: how to round integers (Figured it out!)
Date: Wed, 18 Jun 2003 09:32:13 GMT
Date: 2003-06-18T09:32:13+00:00	[thread overview]
Message-ID: <3EF03178.9000908@attbi.com> (raw)
In-Reply-To: 3EEF6A62.5010809@spam.com

Jeffrey Carter wrote:
> Robert I. Eachus wrote:
> 
>>   function Rounding(Dividend, Divisor: Int) return Int is
>>   begin
>>     return (Dividend + Dividend + Divisor) / (Divisor + Divisor);
>>   exception
>>     when Constraint_Error =>
>>       declare
>>         Temp: Int;
>>       begin
>>         Temp := Dividend rem Divisor;
>>         if Temp > Int'Last/2 or else Temp * 2 >= Divisor
>>         then return Dividend/Divisor + 1;
>>         -- Divisor is always less than or equal to Int'Last
>>         else return Dividend/Divisor;
>>         end if;
>>       end;
>>   end Rounding;
>>
>>   function Round is new Rounding(Integer);
> 
> 
> What happens in the case of negative arguments?

Oops!  New version for the new requirement. ;-) And if you think it is 
messy, it is, that is the nature of division, as Intel and others have 
found out. (It is actually the corner cases that are tricky--and you 
really have to test all of them.)

Oh, the rounding is towards +inifinity, if you want anything else, you 
write it.  Or modify this, it shouldn't be too hard.

-----------------------------------------------------------------------

with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Rounding is

   generic
     type Int is range <>;
   function Rounding(Dividend, Divisor: Int) return Int;

   function Rounding(Dividend, Divisor: Int) return Int is
   begin
     if (Dividend >= 0 and Divisor > 0) or else
        (Dividend <= 0 and Divisor < 0)
     then return (Dividend + Dividend + Divisor) /
           (Divisor + Divisor);
     elsif Dividend <= 0 and Divisor > 0
     then return (Dividend + Dividend - Divisor + 1) /
          (Divisor + Divisor);
     else return (Dividend + Dividend - Divisor - 1) /
          (Divisor + Divisor);
     end if;
   exception
     when Constraint_Error =>
       if Divisor = 0 then raise Constraint_Error; end if;
       -- get the case we can't handle out of the way...
       declare
         Temp: Int;
       begin
         Temp := abs Dividend rem Divisor;
         if Divisor < 0 and Dividend > 0 then
           if Temp > -(Int'First/2)
               or else (Temp-1) * 2 >= -(Divisor + 1)
           then return Dividend/Divisor - 1;
           else return Dividend/Divisor;
           end if;
         elsif Divisor < 0 and Dividend < 0 then
           if Temp > -(Int'First/2)
               or else (Temp-1) * 2 >= -(Divisor + 2)
           then return Dividend/Divisor + 1;
           else return Dividend/Divisor;
           end if;
         elsif Divisor > 0 and Dividend > 0 then
           if Temp > Int'Last/2 or else Temp * 2 >= Divisor
           then return Dividend/Divisor + 1;
           else return Dividend/Divisor;
           end if;
        else -- Divisor > 0 and Dividend < 0 then
           if Temp > Int'Last/2 or else (Temp-1) * 2 >= Divisor - 1
           then return Dividend/Divisor - 1;
           else return Dividend/Divisor;
           end if;
         end if;
       end;
   end Rounding;

   function Round is new Rounding(Integer);

begin

   Put_Line(" Rounding (2,3) is " & Integer'Image(Round(2,3)));
   Put_Line(" Rounding (7,5) is " & Integer'Image(Round(7,5)));
   Put_Line(" Rounding (25, 10) is " & Integer'Image(Round(25,10)));
   Put_Line(" Rounding (1_000_000_000, 1_500_000_000) is " &
                   Integer'Image(Round(1_000_000_000, 1_500_000_000)));
   Put_Line(" Rounding (1_000_000_000, 2_000_000_000) is " &
                   Integer'Image(Round(1_000_000_000, 2_000_000_000)));
   Put_Line(" Rounding (1_500_000_000, 2_000_000_000) is " &
                   Integer'Image(Round(1_500_000_000, 2_000_000_000)));
   Put_Line(" Rounding (1_000_000_000, 2_000_000_001) is " &
                   Integer'Image(Round(1_00_000_000, 2_000_000_001)));
   Put_Line(" Rounding (1_500_000_000, Integer'Last) is " &
                   Integer'Image(Round(1_500_000_000, Integer'Last)));
   Put_Line(" Rounding (1_073_741_824, Integer'Last) is " &
                   Integer'Image(Round(1_073_741_824, Integer'Last)));
   Put_Line(" Rounding (1_073_741_823, Integer'Last) is " &
                   Integer'Image(Round(1_073_741_823, Integer'Last)));
   Put_Line(" Rounding (1_000_000_000, Integer'Last) is " &
                   Integer'Image(Round(1_000_000_000, Integer'Last)));

   Put_Line(" Rounding (-2,3) is " & Integer'Image(Round(-2,3)));
   Put_Line(" Rounding (-7,5) is " & Integer'Image(Round(-7,5)));
   Put_Line(" Rounding (-25, 10) is " & Integer'Image(Round(-25,10)));
   Put_Line(" Rounding (-1_000_000_000, 1_500_000_000) is " &
                   Integer'Image(Round(-1_000_000_000, 1_500_000_000)));
   Put_Line(" Rounding (-1_000_000_000, 2_000_000_000) is " &
                   Integer'Image(Round(-1_000_000_000, 2_000_000_000)));
   Put_Line(" Rounding (-1_500_000_000, 2_000_000_000) is " &
                   Integer'Image(Round(-1_500_000_000, 2_000_000_000)));
   Put_Line(" Rounding (-1_000_000_000, 2_000_000_001) is " &
                   Integer'Image(Round(-1_00_000_000, 2_000_000_001)));
   Put_Line(" Rounding (-1_500_000_000, Integer'Last) is " &
                   Integer'Image(Round(-1_500_000_000, Integer'Last)));
   Put_Line(" Rounding (-1_073_741_824, Integer'Last) is " &
                   Integer'Image(Round(-1_073_741_824, Integer'Last)));
   Put_Line(" Rounding (-1_073_741_823, Integer'Last) is " &
                   Integer'Image(Round(-1_073_741_823, Integer'Last)));
   Put_Line(" Rounding (-1_000_000_000, Integer'Last) is " &
                   Integer'Image(Round(-1_000_000_000, Integer'Last)));

   Put_Line(" Rounding (2,-3) is " & Integer'Image(Round(2,-3)));
   Put_Line(" Rounding (7,-5) is " & Integer'Image(Round(7,-5)));
   Put_Line(" Rounding (25, -10) is " & Integer'Image(Round(25,-10)));
   Put_Line(" Rounding (1_000_000_000, -1_500_000_000) is " &
                   Integer'Image(Round(1_000_000_000, -1_500_000_000)));
   Put_Line(" Rounding (1_000_000_000, -2_000_000_000) is " &
                   Integer'Image(Round(1_000_000_000, -2_000_000_000)));
   Put_Line(" Rounding (1_500_000_000, -2_000_000_000) is " &
                   Integer'Image(Round(1_500_000_000, -2_000_000_000)));
   Put_Line(" Rounding (1_000_000_000, -2_000_000_001) is " &
                   Integer'Image(Round(1_00_000_000, -2_000_000_001)));
   Put_Line(" Rounding (1_500_000_000, Integer'First) is " &
                   Integer'Image(Round(1_500_000_000, Integer'First)));
   Put_Line(" Rounding (1_073_741_824, Integer'First) is " &
                   Integer'Image(Round(1_073_741_824, Integer'First)));
   Put_Line(" Rounding (1_073_741_823, Integer'First) is " &
                   Integer'Image(Round(1_073_741_823, Integer'First)));
   Put_Line(" Rounding (1_000_000_000, Integer'First) is " &
                   Integer'Image(Round(1_000_000_000, Integer'First)));

   Put_Line(" Rounding (-2,-3) is " & Integer'Image(Round(-2,-3)));
   Put_Line(" Rounding (-7,-5) is " & Integer'Image(Round(-7,-5)));
   Put_Line(" Rounding (-25,-10) is " & Integer'Image(Round(-25,-10)));
   Put_Line(" Rounding (-1_000_000_000, -1_500_000_000) is " &
                   Integer'Image(Round(-1_000_000_000, -1_500_000_000)));
   Put_Line(" Rounding (-1_000_000_000, -2_000_000_000) is " &
                   Integer'Image(Round(-1_000_000_000, -2_000_000_000)));
   Put_Line(" Rounding (-1_500_000_000, -2_000_000_000) is " &
                   Integer'Image(Round(-1_500_000_000, -2_000_000_000)));
   Put_Line(" Rounding (-1_000_000_000, -2_000_000_001) is " &
                   Integer'Image(Round(-1_000_000_000, -2_000_000_001)));
   Put_Line(" Rounding (-1_500_000_000, Integer'First) is " &
                   Integer'Image(Round(-1_500_000_000, Integer'First)));
   Put_Line(" Rounding (-1_073_741_824, Integer'First) is " &
                   Integer'Image(Round(-1_073_741_824, Integer'First)));
   Put_Line(" Rounding (-1_073_741_823, Integer'First) is " &
                   Integer'Image(Round(-1_073_741_823, Integer'First)));
   Put_Line(" Rounding (-1_000_000_000, Integer'First) is " &
                   Integer'Image(Round(-1_000_000_000, Integer'First)));

end Test_Rounding;
-----------------------------------------------------------------------
The tests should probably be rewritten to only print results if there is 
a problem...
E:\Ada\Bug>test_rounding
test_rounding
  Rounding (2,3) is  1
  Rounding (7,5) is  1
  Rounding (25, 10) is  3
  Rounding (1_000_000_000, 1_500_000_000) is  1
  Rounding (1_000_000_000, 2_000_000_000) is  1
  Rounding (1_500_000_000, 2_000_000_000) is  1
  Rounding (1_000_000_000, 2_000_000_001) is  0
  Rounding (1_500_000_000, Integer'Last) is  1
  Rounding (1_073_741_824, Integer'Last) is  1
  Rounding (1_073_741_823, Integer'Last) is  0
  Rounding (1_000_000_000, Integer'Last) is  0
  Rounding (-2,3) is -1
  Rounding (-7,5) is -1
  Rounding (-25, 10) is -2
  Rounding (-1_000_000_000, 1_500_000_000) is -1
  Rounding (-1_000_000_000, 2_000_000_000) is  0
  Rounding (-1_500_000_000, 2_000_000_000) is -1
  Rounding (-1_000_000_000, 2_000_000_001) is  0
  Rounding (-1_500_000_000, Integer'Last) is -1
  Rounding (-1_073_741_824, Integer'Last) is -1
  Rounding (-1_073_741_823, Integer'Last) is  0
  Rounding (-1_000_000_000, Integer'Last) is  0
  Rounding (2,-3) is -1
  Rounding (7,-5) is -1
  Rounding (25, -10) is -2
  Rounding (1_000_000_000, -1_500_000_000) is -1
  Rounding (1_000_000_000, -2_000_000_000) is  0
  Rounding (1_500_000_000, -2_000_000_000) is -1
  Rounding (1_000_000_000, -2_000_000_001) is  0
  Rounding (1_500_000_000, Integer'First) is -1
  Rounding (1_073_741_824, Integer'First) is  0
  Rounding (1_073_741_823, Integer'First) is  0
  Rounding (1_000_000_000, Integer'First) is  0
  Rounding (-2,-3) is  1
  Rounding (-7,-5) is  1
  Rounding (-25,-10) is  3
  Rounding (-1_000_000_000, -1_500_000_000) is  1
  Rounding (-1_000_000_000, -2_000_000_000) is  1
  Rounding (-1_500_000_000, -2_000_000_000) is  1
  Rounding (-1_000_000_000, -2_000_000_001) is  0
  Rounding (-1_500_000_000, Integer'First) is  1
  Rounding (-1_073_741_824, Integer'First) is  1
  Rounding (-1_073_741_823, Integer'First) is  0
  Rounding (-1_000_000_000, Integer'First) is  0




  reply	other threads:[~2003-06-18  9:32 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-06-16  2:55 how to round integers Cephus�
2003-06-16  4:03 ` Charles LaCour
2003-06-16 12:12   ` Cephus�
2003-06-16 21:59   ` Jeffrey Creem
2003-06-16 10:09 ` Martin Dowie
2003-06-16 10:49 ` David C. Hoos
2003-06-16 12:18 ` how to round integers (Figured it out!) Cephus�
2003-06-16 12:34   ` David C. Hoos
2003-06-16 12:36     ` Cephus�
2003-06-16 13:12       ` David C. Hoos
2003-06-17  4:44         ` Robert I. Eachus
2003-06-17 19:20           ` Jeffrey Carter
2003-06-18  9:32             ` Robert I. Eachus [this message]
2003-06-18 18:07               ` Jeffrey Carter
2003-06-19  0:34                 ` Robert I. Eachus
2003-06-19 23:40                   ` Jeffrey Carter
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox