Round

new topic     » topic index » view thread      » older message » newer message

The following code may be of interest:

global function unary_function(integer id,object Param)
   if atom(Param) then return call_func(id,{Param}) end if
   for i=1 to length(Param) do
      Param[i]=call_func(id,{Param[i]})
   end for
   return Param
end function

global function binary_function(integer id,object Param1,object Param2)
   integer len1,len2
   if atom(Param1) then len1=-1 else len1=length(Param1) end if
   if atom(Param2) then len2=-1 else len2=length(Param2) end if
   if len1=-1 and len2=-1 then
      return call_func(id,{Param1,Param2})
   end if
   if len1=-1 then
      Param1=repeat(Param1,len2)
      len1=len2
   elsif len2=-1 then
      Param2=repeat(Param2,len1)
      len2=len1
   end if
   if len1!=len2 then
      puts(2,"\nSequence length mismatch.\n")
      ? 1/0
   end if
   for i=1 to len1 do
      Param1[i]=call_func(id,{Param1[i],Param2[i]})
   end for
   return Param1
end function

constant TOLERANCE=1e-10

function round_atom(atom a,integer places)
   integer int
   atom adjust
   adjust=power(10,places)
   a=a*adjust+.5
   int=floor(a)
   if a-int<TOLERANCE and remainder(int,2)!=0 then int-=1 end if
   return int/adjust
end function

constant ROUND_ATOM=routine_id("round_atom")

global function round(object x,object places)
   return binary_function(ROUND_ATOM,x,places)
end function

First look at round_atom().  This rounds an atom to the specified number of
places (use 0 to round to an integer).  The floor(a+.5) idea works except
for exact .5 remainders--it can round these wrong.  The code I have given
above aproximates the IEEE standard "Banker's Rounding":  round .4999999
down, round .5000001 up, round exactly .5 to the nearest even number.  This
can't be done exactly with Euphoria's binary floating point atoms, but the
tolerance factor gets it right most of the time.  (Getting it right every
time requires binary coded decimal fp.)

If you prefer a 5/4 roundoff, where exactly .5 is rounded up change

if a-int<TOLERANCE and remainder(int,2)!=0 then int-=1 end if

to

if a-int<TOLERANCE and a<=0 then int-=1 end if

The function round() extends this to allow for sequences so that

? round(1.5,0) -->prints 2
? round(3.14159,{0,1,2,3,4}) -->prints {3,3.1,3.14,3.142,3.1416}
? round({15.786,12.3455},2) -->prints {15.79,12.35}

and so forth.

The utility functions unary_function() and binary_function() are used apply
functions written to use atoms to sequences.  Use unary_function() if the
atomic function takes 1 argument, binary_function() if 2.

-- Mike Nelson

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu