【問題】
我們都會手算除法,比如:123除以13。
當然,有的時候會出現無限迴圈小數。
1 請模擬手算除法的過程,計算a除以b的小數後100位。
2 發現無限迴圈小數的迴圈節,並標識出來。
比如:123除以13,表示為:
9.[461538]
這個題目要求我們模擬手算除法的過程。初看,用命令式的思考更直觀,但因為要儲存處理計算的過程,也並不佔便宜。。。。
換用 haskell 呢? 如果覺得有障礙,就是不能改變變數的值了。這可以通過傳入傳出狀態來解決。先模擬命令式的想法:
import
data
.list (elemindex)
----求真分數的十進位制小數形式,保證: n分子 < n分母
----返回值 (商的不迴圈部分,商的迴圈部分),都是逆序的
f真分數 :: integral a =
> a -
> a -
>
([a]
,[a]
)f真分數 n分子 n分母 = f [
][n分子]
where
f l商 l餘 =
case
(head l餘 *10)
`divmod` n分母 of
(t,0)-
>
(t:l商,
)(t, u)
->
case u `elemindex` l餘 of
just n -
>
(drop n l商, t:take n l商)
nothing -
> f (t:l商)
(u:l餘)
f分數 :: (
show a, integral a)
=> a -
> a -
> string
f分數 n分子 n分母 = let
(n整數部分, n餘數)
= n分子 `divmod` n分母
(l商, l商迴圈)
= f真分數 n餘數 n分母
inshow n整數部分
++"."++
(concat . map show
. reverse $ l商)++
"["+
+(concat . map show
. reverse $ l商迴圈)++
"]"main :: io (
)main =
do putstrln $ f分數 1
3 putstrln $ f分數 123
13 putstrln $ f分數 23
56
這裡,我們用 l商 l餘 分別表示商和餘數的序列,並在 f 函式中傳遞。
遞迴的出口是:要以餘數遇到了 0, 要麼餘數出現了迴圈。
之所以都用逆序,是因為 ( : ) 比 ( ++ ) 更有效率而已。
然後再把輸出安排一下就好了。
既然是函式式程式設計,就要跳出命令式的圈子。我們需要的是。。定義。。。定義。。不是步驟。。。不是步驟。。。
如上口訣念了 n 遍之後,得出一解:
import
data
.list (elemindex, splitat)
--- 把真分數表示為迴圈小數的形式
--- 1/3 = 0.3333 --> (,[3])
--- 23/56 = 0.410714285771428... ---> ([4,1,0], [7,1,4,2,8,5])
--- 1/5 = 0.200.... --> ([2],[0]) 能除盡的小數,看作以 [0] 為其小數的迴圈部分
f真分數迴圈 :: integral a =
> a -
> a -
>
([a]
,[a]
)f真分數迴圈 n分子 n分母 =
let
xs =
iterate
(\(_,u)
->
(u *10)
`divmod` n分母)(0
,n分子)
l商 = tail $ map fst xs --從小數點後記商,甩掉頭0
l餘 = map snd xs
ys = map (
`elemindex` l餘) l餘 ---元素在餘數列中首次出現位置
(n節尾, n節首)
= head [
(a,b)
|(just a,just b)
<
- ys `zip` tail ys, a>=b]
in splitat n節首 (take (n節尾+
1) l商)
ok :: (
show a, integral a)
=> a -
> a -
> string
ok n分子 n分母 = let
(n整部, n零部)
= n分子 `divmod` n分母
(xs,ys)
= f真分數迴圈 n零部 n分母
inshow n整部 +
+"."
++ concatmap show xs
++"["
++ concatmap show ys +
+"]"
main :: io (
)main =
do putstrln $ ok 1
3 putstrln $ ok 123
13 putstrln $ ok 23
56
這裡首先構造出 商 和 餘數 的無限列。
再從列中算出迴圈節的起始和結束位置。
然後就是簡單的拼接了。
haskell 基礎題解(06)
題目 如果乙個數的所有真因子 不包含它自身的因子 之和恰等於其自身,則該數為完全數,也稱為完美數 perfect number 完全數有許多奇妙的性質。但它們很稀少,你來求前幾個吧。最小的乙個是 6,因為 6 1 2 3 這個完全數的定義已經很清楚了,如果沒有什麼妙法,就地毯式搜尋也可以。下法就是 ...
haskell 基礎題解(07)
題目 11 1 1 2 1 1 3 3 1 1 4 6 4 1 這個陣勢叫楊輝三角,國外叫帕斯卡三角。前一行的數字中,每兩個相鄰的數字相加就得到下一行的數字。左右兩邊的數永遠是 1 寫個程式,輸出前幾行的楊輝三角。import data.list intersperse yang hui int y...
haskell基礎題解(14)
題目 用自然數蛇形填充乙個 n 階的方陣。當n 5時,形如 這個問題用 haskell 解決時與 題目13 差別甚微。實際上,從函式式的思考習慣看,只要讓有些行作成後反轉一下就可以了。上 ju n f x x 0.n 1 where f row even row take n row n 1.odd...