1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
module Stream (Stream, carry, addStream, rationalToStream,
streamToFloat, addFiniteStream, negate', average) where
import Data.Ratio
type Digit = Integer
type Stream = [Integer]
-- Convert from a Rational fraction to its stream representation
rationalToStream :: Rational -> Stream
rationalToStream x
|t<1 = 0:rationalToStream t
|otherwise = 1:rationalToStream (t-1)
where t = 2*x
-- Convert from a stream to the Float value
streamToFloat :: Stream -> Float
streamToFloat x = f x (1)
f :: Stream -> Integer -> Float
f [] n = 0
f (y:ys) n = (fromIntegral)y/(fromIntegral(2^n)) + f ys (n+1)
-- Add two stream
addStream :: Stream -> Stream -> Stream
addStream (x1:x2:x3:xs) (y1:y2:y3:ys) = (u+c):(addStream (x2:x3:xs) (y2:y3:ys))
where u = interim x1 x2 y1 y2
c = carry x2 x3 y2 y3
-- Compute carry, the C(i) value, given x(i) and y(i)
carry :: Digit -> Digit -> Digit -> Digit -> Digit
carry x1 x2 y1 y2
|t>1 = 1
|t<(-1) = -1
|t==1 && (minus1 x2 y2) = 0
|t==1 && not (minus1 x2 y2) = 1
|t==(-1) && (minus1 x2 y2) = -1
|t==(-1) && not (minus1 x2 y2) = 0
|t==0 = 0
where t = x1+y1
-- Computer the interim sum, the U(i) value, given x(i), y(i) and c(i)
interim :: Digit -> Digit -> Digit -> Digit -> Digit
interim x1 x2 y1 y2
|t>1 = 0
|t<(-1) = 0
|t==1 && (minus1 x2 y2) = 1
|t==1 && not (minus1 x2 y2) = -1
|t==(-1) && (minus1 x2 y2) = 1
|t==(-1) && not (minus1 x2 y2) = -1
|t==0 = 0
where t = x1+y1
-- Check if at least one of 2 digits is -1
minus1 :: Digit -> Digit -> Bool
minus1 x y = (x==(-1))|| (y==(-1))
-- Algin two stream so that they have the same length
align :: Stream -> Stream -> (Stream, Stream)
align xs ys
|x>y = (xs, (copy 0 (x-y)) ++ys)
|otherwise = ((copy 0 (y-x)) ++ xs, ys)
where x = toInteger(length xs)
y = toInteger(length ys)
-- Generate a list of x
copy :: Integer -> Integer -> [Integer]
copy x n = [x| i<- [1..n]]
-- Add two finite stream (to add the integral part)
addFiniteStream :: Stream -> Stream -> Stream
addFiniteStream xs ys = add' u v
where (u,v) = align xs ys
-- Utility function for addFinitieStream
add' :: Stream -> Stream -> Stream
add' u v = normalise (f u v)
where f [] [] = []
f (x:xs) (y:ys) = (x+y):f xs ys
-- Normalise the sum
normalise :: Stream -> Stream
normalise = foldr f [0]
where f x (y:ys) = (u:v:ys)
where u = (x+y) `div` 2
v = (x+y) `mod` 2
-- Negate a stream
negate' :: Stream -> Stream
negate' = map (*(-1))
-- Compute average of two stream
-- Using [-2,-1,0,1,2] to add, and then divide by 2
average :: Stream -> Stream -> Stream
average xs ys = div2 (add xs ys)
-- Addition of two streams, using [-2,-1,0,1,2]
add :: Stream -> Stream -> Stream
add (x:xs) (y:ys) = (x+y):(add xs ys)
-- Then divided by 2, [-2,-1,0,1,2] -> [-1,0,1]
div2 :: Stream -> Stream
div2 (2:xs) = 1:div2 xs
div2 ((-2):xs) = (-1):div2 xs
div2 (0:xs) = 0:div2 xs
div2 (1:(-2):xs) = div2 (0:0:xs)
div2 (1:(-1):xs) = div2 (0:1:xs)
div2 (1:0:xs) = div2 (0:2:xs)
div2 (1:1:xs) = div2 (2:(-1):xs)
div2 (1:2:xs) = div2 (2:0:xs)
div2 ((-1):(-2):xs) = div2 ((-2):0:xs)
div2 ((-1):(-1):xs) = div2 ((-2):1:xs)
div2 ((-1):0:xs) = div2 (0:(-2):xs)
div2 ((-1):1:xs) = div2 (0:(-1):xs)
div2 ((-1):2:xs) = div2 (0:0:xs)
test = take 100 (average (rationalToStream (1%2)) (rationalToStream (1%3)))
|