Hello,


Something is wrong with  Ratio  in  ghc-0.29.  
I mean the efficiency.
It looses too much on the large numbers.
In the below example, my home-made  addition (and cancellation)  
for  Fraction Integer  win 10 times in speed 
- with NO optimisation.
------------------------------------------------------
Possible reason:  
in  Prelude (+) for Ratio,  before applying  
                                        reduce (x*y'+x'*y) (y*y')
it worths to pre-cancel things by  gcd(y,y')
------------------------------------------------------
- see the below script for  addFr  and  D.Knuth  
"The art of the programming".

In the benchmark,  nSum  costs near the same as  nSum'.
This means that the small fractions are good.
And  gSum  takes 10 time more than  gSum'  - probably because of
the above cancellation policy.  For in gSum the number sizes grow
much more than in  nSum.


Sergey Mechveliani   

[EMAIL PROTECTED]






------------------------------------------------------------------
------------------------------------------------------------------
-- comparing  Fraction - Ratio

main =  let  ns  = [1..500]  
             rns = reverse ns  
             xs  = zipWith (%)       ns rns  :: [Rational]
             xs' = zipWith (canF "") ns rns  :: [Fraction Integer]

             gSum  = foldl (+)   (0%1)      xs 
             gSum' = foldl addFr (zeroFr 0) xs'

             nSum  = foldl (+) 0 (map numerator xs )
             nSum' = foldl (+) 0 (map num       xs')
        in  
          writeFile "result" (show gSum)       -- gSum' nSum nSum'






------------------------------------------------------------------
addFr :: (GCDRing a,Fractional a) => 
                            Fraction a -> Fraction a -> Fraction a
addFr (n1:/d1) (n2:/d2) =  
  let  
    zr = zero d1  
  in
    case  (n1==zr, n2==zr) 
    of
      (True,_   ) -> n2:/d2
      (_   ,True) -> n1:/d1
      _           -> let  g   = gcD [d1,d2]  
                          dd1 = d1/g
                          dd2 = d2/g  
                          n   = n1*dd2+n2*dd1
                          gg  = gcD [n,g]
                     in   
                          canF "i" (n/gg) ((dd1*dd2)*(g/gg))



------------------------------------------------------------------
-- canF  is for bringing the intermediate result to the canonical 
--       fraction.
-- mode = "g"  means to cancel the pair by gcd.
--        "i"                           by canonical invertible,
--        ""                            by both.
                                

canF :: GCDRing a => String -> a -> a -> Fraction a
                                    
canF  mode n d =
  let
    (zr,un) = (zero d,unity d)
    g       = gcD [n,d]

    cancel a b dv =  if  dv==un  then  a:/b
                     else             (divide a dv):/(divide b dv)
  in
    case  (n==zr,d==zr)
    of
      (_   , True) -> error "(canF n d):  zero d \n"
      (True, _   ) -> zr:/un
      _            ->
        (case  mode  of
                "g" -> cancel n d g
                "i" -> cancel n d (canInv d)
                ""  -> let  
                           (n':/d') = cancel n d g
                       in  
                           cancel n' d' (canInv d')
                _   -> 
                     error( "(canFr mode fraction):  mode "++
                            "== \"\" | \"g\" | \"i\"  expected \n"
                          )
        )








Reply via email to