|
1 " |
|
2 COPYRIGHT (c) 1989-93 by Claus Gittinger |
|
3 All Rights Reserved |
|
4 |
|
5 This software is furnished under a license and may be used |
|
6 only in accordance with the terms of that license and with the |
|
7 inclusion of the above copyright notice. This software may not |
|
8 be provided or otherwise made available to, or used by, any |
|
9 other person. No title to or ownership of the software is |
|
10 hereby transferred. |
|
11 " |
|
12 |
|
13 Number subclass:#Fraction |
|
14 instanceVariableNames:'numerator denominator' |
|
15 classVariableNames:'FractionOne FractionZero' |
|
16 poolDictionaries:'' |
|
17 category:'Magnitude-Numbers' |
|
18 ! |
|
19 |
|
20 Fraction comment:' |
|
21 |
|
22 COPYRIGHT (c) 1989-93 by Claus Gittinger |
|
23 All Rights Reserved |
|
24 |
|
25 %W% %E% |
|
26 '! |
|
27 |
|
28 !Fraction class methodsFor:'initialization'! |
|
29 |
|
30 initialize |
|
31 FractionZero := self numerator:0 denominator:1. |
|
32 FractionOne := self numerator:1 denominator:1 |
|
33 ! ! |
|
34 |
|
35 !Fraction class methodsFor:'constants'! |
|
36 |
|
37 zero |
|
38 ^ FractionZero |
|
39 ! |
|
40 |
|
41 unity |
|
42 ^ FractionOne |
|
43 ! ! |
|
44 |
|
45 !Fraction class methodsFor:'instance creation'! |
|
46 |
|
47 new |
|
48 "create and return a new fraction with value 0" |
|
49 |
|
50 ^ self basicNew setNumerator:0 denominator:1 |
|
51 ! |
|
52 |
|
53 numerator:num denominator:den |
|
54 "create and return a new fraction with numerator num and denominator den" |
|
55 |
|
56 %{ /* NOCONTEXT */ |
|
57 extern char *newNextPtr, *newEndPtr; |
|
58 |
|
59 if (self == Fraction) { |
|
60 if (_CanDoQuickNew(sizeof(struct fractionstruct))) { |
|
61 OBJ newFraction; |
|
62 |
|
63 _qCheckedAlignedNew(newFraction, sizeof(struct fractionstruct), __context); |
|
64 _InstPtr(newFraction)->o_class = Fraction; |
|
65 _FractionInstPtr(newFraction)->f_numerator = num; |
|
66 _FractionInstPtr(newFraction)->f_denominator = den; |
|
67 /* no store check needed - its definitely in newSpace */ |
|
68 RETURN ( newFraction ); |
|
69 } |
|
70 } |
|
71 %} |
|
72 . |
|
73 ^ self basicNew setNumerator:num denominator:den |
|
74 ! ! |
|
75 |
|
76 !Fraction methodsFor:'accessing'! |
|
77 |
|
78 numerator |
|
79 "return the numerator" |
|
80 |
|
81 ^ numerator |
|
82 ! |
|
83 |
|
84 denominator |
|
85 "return the denominator" |
|
86 |
|
87 ^ denominator |
|
88 ! ! |
|
89 |
|
90 !Fraction methodsFor:'private'! |
|
91 |
|
92 setNumerator:num denominator:den |
|
93 "set both numerator and denominator" |
|
94 |
|
95 numerator := num. |
|
96 denominator := den |
|
97 ! |
|
98 |
|
99 reduced |
|
100 "reduce the receiver" |
|
101 |
|
102 |gc| |
|
103 |
|
104 denominator == 1 ifTrue:[^ numerator]. |
|
105 numerator == 1 ifTrue:[^ self]. |
|
106 |
|
107 gc := numerator gcd:denominator. |
|
108 (gc == 1) ifFalse:[ |
|
109 numerator := numerator // gc. |
|
110 denominator := denominator // gc |
|
111 ]. |
|
112 (numerator < 0) ifTrue:[ |
|
113 (denominator < 0) ifTrue:[ |
|
114 numerator := numerator negated. |
|
115 denominator := denominator negated |
|
116 ] |
|
117 ]. |
|
118 (denominator == 1) ifTrue:[^ numerator]. |
|
119 ^ self |
|
120 ! ! |
|
121 |
|
122 !Fraction methodsFor:'coercing'! |
|
123 |
|
124 coerce:aNumber |
|
125 ^ aNumber asFraction |
|
126 ! |
|
127 |
|
128 generality |
|
129 ^ 60 |
|
130 ! ! |
|
131 |
|
132 !Fraction methodsFor:'converting'! |
|
133 |
|
134 asInteger |
|
135 "return an integer with my value - will usually truncate" |
|
136 |
|
137 ^ numerator // denominator |
|
138 ! |
|
139 |
|
140 asLargeInteger |
|
141 "return an integer with my value - will usually truncate" |
|
142 |
|
143 ^ self asInteger asLargeInteger |
|
144 ! |
|
145 |
|
146 asFloat |
|
147 "return a float with (approximately) my value" |
|
148 |
|
149 ^ (numerator asFloat) / (denominator asFloat) |
|
150 ! |
|
151 |
|
152 asFraction |
|
153 "return the receiver as fraction - thats itself" |
|
154 |
|
155 ^ self |
|
156 ! ! |
|
157 |
|
158 !Fraction methodsFor:'comparing'! |
|
159 |
|
160 = aNumber |
|
161 "return true, if the argument represents the same numeric value |
|
162 as the receiver, false otherwise" |
|
163 |
|
164 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
165 (denominator = 1) ifFalse:[^ false]. |
|
166 ^ numerator = aNumber |
|
167 ]. |
|
168 (aNumber isKindOf:Fraction) ifTrue:[ |
|
169 (numerator = aNumber numerator) ifFalse:[^ false]. |
|
170 ^ denominator = aNumber denominator |
|
171 ]. |
|
172 ^ self retry:#= coercing:aNumber |
|
173 ! |
|
174 |
|
175 > aNumber |
|
176 "return true if the receiver is greater |
|
177 than aNumber, false otherwise." |
|
178 "optional - could use inherited method ..." |
|
179 |
|
180 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
181 ^ numerator > (denominator * aNumber) |
|
182 ]. |
|
183 (aNumber isKindOf:Fraction) ifTrue:[ |
|
184 ^ (numerator * aNumber denominator) > (denominator * aNumber numerator) |
|
185 ]. |
|
186 ^ self retry:#> coercing:aNumber |
|
187 ! |
|
188 |
|
189 < aNumber |
|
190 "return true if the receiver is less |
|
191 than aNumber, false otherwise." |
|
192 |
|
193 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
194 ^ numerator < (denominator * aNumber) |
|
195 ]. |
|
196 (aNumber isKindOf:Fraction) ifTrue:[ |
|
197 ^ (numerator * aNumber denominator) < (denominator * aNumber numerator) |
|
198 ]. |
|
199 ^ aNumber lessFromFraction:self |
|
200 ! ! |
|
201 |
|
202 !Fraction methodsFor:'testing'! |
|
203 |
|
204 negative |
|
205 "return true if the receiver is negative" |
|
206 |
|
207 (numerator < 0) ifTrue:[ |
|
208 ^ (denominator < 0) not |
|
209 ]. |
|
210 ^ (denominator < 0) |
|
211 ! ! |
|
212 |
|
213 !Fraction methodsFor:'arithmetic'! |
|
214 |
|
215 + aNumber |
|
216 "return the sum of the receiver and the argument, aNumber" |
|
217 |
|
218 |n d| |
|
219 |
|
220 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
221 ^ (self class numerator:(numerator + (denominator * aNumber)) |
|
222 denominator:denominator) reduced |
|
223 ]. |
|
224 (aNumber isKindOf:Fraction) ifTrue:[ |
|
225 n := aNumber numerator. |
|
226 d := aNumber denominator. |
|
227 |
|
228 "save a multiplication if possible" |
|
229 denominator == d ifTrue:[ |
|
230 ^ (self class numerator:(numerator + n) denominator:d) reduced |
|
231 ]. |
|
232 |
|
233 ^ (self class numerator:((numerator * d) + (n * denominator)) |
|
234 denominator:(denominator * d)) reduced |
|
235 ]. |
|
236 ^ aNumber sumFromFraction:self |
|
237 ! |
|
238 |
|
239 - aNumber |
|
240 "return the difference of the receiver and the argument, aNumber" |
|
241 |
|
242 |n d| |
|
243 |
|
244 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
245 ^ (self class numerator:(numerator - (denominator * aNumber)) |
|
246 denominator:denominator) reduced |
|
247 ]. |
|
248 (aNumber isKindOf:Fraction) ifTrue:[ |
|
249 n := aNumber numerator. |
|
250 d := aNumber denominator. |
|
251 |
|
252 "save a multiplication if possible" |
|
253 denominator == d ifTrue:[ |
|
254 ^ (self class numerator:(numerator - n) denominator:d) reduced |
|
255 ]. |
|
256 |
|
257 ^ (self class numerator:((numerator * d) - (n * denominator)) |
|
258 denominator:(denominator * d)) reduced |
|
259 ]. |
|
260 ^ aNumber differenceFromFraction:self |
|
261 ! |
|
262 |
|
263 * aNumber |
|
264 "return the product of the receiver and the argument, aNumber" |
|
265 |
|
266 |n d| |
|
267 |
|
268 (aNumber isMemberOf:SmallInteger) ifTrue:[ |
|
269 ^ (self class numerator:(numerator * aNumber) |
|
270 denominator:denominator) reduced |
|
271 ]. |
|
272 (aNumber isKindOf:Fraction) ifTrue:[ |
|
273 n := numerator * aNumber numerator. |
|
274 d := denominator * aNumber denominator. |
|
275 ^ (self class numerator:n denominator:d) reduced |
|
276 ]. |
|
277 ^ aNumber productFromFraction:self |
|
278 ! |
|
279 |
|
280 / aNumber |
|
281 "return the quotient of the receiver and the argument, aNumber" |
|
282 |
|
283 |n d| |
|
284 |
|
285 (aNumber isKindOf:Fraction) ifTrue:[ |
|
286 n := numerator * aNumber denominator. |
|
287 d := denominator * aNumber numerator. |
|
288 ^ (self class numerator:n denominator:d) reduced |
|
289 ]. |
|
290 ^ aNumber quotientFromFraction:self |
|
291 ! |
|
292 |
|
293 // aNumber |
|
294 "return the integer quotient of the receiver and the argument, aNumber" |
|
295 |
|
296 self negative ifTrue:[ |
|
297 ^ ((numerator * aNumber denominator) // (denominator * aNumber numerator)) - 1 |
|
298 ]. |
|
299 ^ (numerator * aNumber denominator) // (denominator * aNumber numerator) |
|
300 ! |
|
301 |
|
302 negated |
|
303 "optional - could use inherited method ..." |
|
304 |
|
305 ^ self class numerator:(numerator negated) |
|
306 denominator:denominator |
|
307 ! |
|
308 |
|
309 reciprocal |
|
310 "optional - could use inherited method ..." |
|
311 |
|
312 numerator == 1 ifTrue:[^ denominator]. |
|
313 ^ self class numerator:denominator |
|
314 denominator:numerator |
|
315 ! ! |
|
316 |
|
317 !Fraction methodsFor:'truncation and rounding'! |
|
318 |
|
319 truncated |
|
320 "return the receiver truncated towards zero as Integer" |
|
321 |
|
322 ^ numerator // denominator |
|
323 ! |
|
324 |
|
325 rounded |
|
326 "return the receiver rounded to the nearest integer as integer" |
|
327 |
|
328 self negative ifTrue:[ |
|
329 ^ (self + (1/2)) truncated - 1 |
|
330 ]. |
|
331 ^ (self + (1/2)) truncated |
|
332 ! ! |
|
333 |
|
334 !Fraction methodsFor:'double dispatching'! |
|
335 |
|
336 sumFromInteger:anInteger |
|
337 "sent when an integer does not know how to add the recevier, a fraction" |
|
338 |
|
339 ^ (self class numerator:(numerator + (anInteger * denominator)) |
|
340 denominator:denominator) reduced |
|
341 ! |
|
342 |
|
343 differenceFromInteger:anInteger |
|
344 "sent when an integer does not know how to subtract the recevier, a fraction" |
|
345 |
|
346 ^ (self class numerator:((anInteger * denominator) - numerator) |
|
347 denominator:denominator) reduced |
|
348 ! |
|
349 |
|
350 productFromInteger:anInteger |
|
351 "sent when an integer does not know how to multiply the recevier, a fraction" |
|
352 |
|
353 ^ (self class numerator:(anInteger * numerator) |
|
354 denominator:denominator) reduced |
|
355 ! |
|
356 |
|
357 lessFromInteger:anInteger |
|
358 "sent when an integer does not know how to compare to the recevier, a fraction" |
|
359 |
|
360 ^ (denominator * anInteger) < numerator |
|
361 ! |
|
362 |
|
363 sumFromFloat:aFloat |
|
364 "sent when a float does not know how to add the recevier, a fraction" |
|
365 |
|
366 ^ (aFloat * denominator + numerator) / denominator |
|
367 ! |
|
368 |
|
369 differenceFromFloat:aFloat |
|
370 "sent when a float does not know how to subtract the recevier, a fraction" |
|
371 |
|
372 ^ (aFloat * denominator - numerator) / denominator |
|
373 ! |
|
374 |
|
375 productFromFloat:aFloat |
|
376 "sent when a float does not know how to multiply the recevier, a fraction" |
|
377 |
|
378 ^ aFloat * numerator / denominator |
|
379 ! |
|
380 |
|
381 quotientFromFloat:aFloat |
|
382 "sent when a float does not know how to divide by the recevier, a fraction" |
|
383 |
|
384 ^ (aFloat * denominator) / numerator |
|
385 ! ! |
|
386 |
|
387 !Fraction methodsFor:'printing'! |
|
388 |
|
389 printString |
|
390 ^ '(' , numerator printString, '/' , denominator printString, ')' |
|
391 ! ! |