Re: remainder() is not right

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

jacques deschĂȘnes wrote:
> 
> In fact remainder(x,y) means   q*y+r=x
> so 
>    remainder(-27,3600)= (-27) is ok as  0*3600+(-27)=(-27)
>    remainder(-3627,3600)=(-27) is ok as -1*3600+(-27)=(-3627)
>    remainder(-3627,-3600) = -27 is ok as 1*(-3600)+(-27)=(-3627)
>    remainder(27,-3600) = 27 is ok as 0*3600+ 27 = 27
> 
> Jacques DeschĂȘnes
> 

True. And signed_remainder() also respects this identity. But see, there are at
least two ways of defining it, the mathematic way and the C way.

CChris

> CChris wrote:
> > 
> > 
> > The remainder of x by y, which remainder() is supposed to return, is the
> > number
> > with the smallest magnitude and the sign of y such that, if we call it z,
> > x-z
> > is a multiple of y.
> > 
> > But remainder() has a quirkier response. For instance:
> > ?remainder(-27,3600) -- -27, instead of 3573
> > ?remainder(-3627,3600) -- ditto
> > ?remainder(-3627,-3600) -- -27 is correct here
> > ?remainder(27,-3600)    -- 27, instead of -3573
> > 
> > Changing remainder()'s behaviour will break any code that works around this
> > behaviour. So perhaps should we add another function with the appropriate
> > return
> > values; perhaps signed_remainder()?
> > 
> > Notionally, it might work like this:
> > }}}
<eucode>
> > global function signed_remainder(object a,object b)
> >     integer atom_a,atom_b
> >     atom c
> > 
> >     if find(b,{{},0.0} then
> >         return {} -- not a valid 2nd argument
> >         -- crash("Invalid 2nd argument to remainder()")
> >     end if
> >     atom_a=atom(a)
> >     atom_b=atom(b)
> >     if atom_a!=atom_b then
> >         if atom_a then -- atom,sequence
> >             for i=1 to length(b) do
> >                 b[i]=signed_remainder(a,b[i])
> >             end for
> >             return b
> >          else -- sequence,atom
> >              for i=1 to length(a) do
> >                  a[i]=signed_remainder(a[i],b)
> >              end for
> >              return a
> >         end if
> >     elsif atom_a=0 then -- two sequences
> >         if length(a)!=length(b) then
> >             return {} -- let caller handle the mismatch
> >             -- crash("Sequence lengths don't match")
> >         else
> >             for i=1 to length(a) do
> >                 a[i]=signed_remainder(a[i],b[i])
> >             end for
> >             return a
> >         end if
> >     else -- two atoms
> >         c=remainder(a,b) -- smallest magnitude and sign of a
> >         if a<0!=b<0 then
> >             return c+b
> >         else
> >             return c
> >         end if
> > end function
> > </eucode>
{{{

> > 
> > It will be probably better implemented as a builtin if there is a
> > corresponding
> > C stdlib function with the desired behaviour. If only to take advantage of
> > the
> > sequence extension mechanism binary_op() in be_runtime.c provides.
> > 
> > CChris

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

Search



Quick Links

User menu

Not signed in.

Misc Menu