23739
|
1 |
"{ Encoding: utf8 }"
|
|
2 |
|
7445
|
3 |
"
|
|
4 |
COPYRIGHT (c) 2003 by eXept Software AG
|
|
5 |
All Rights Reserved
|
|
6 |
|
|
7 |
This software is furnished under a license and may be used
|
|
8 |
only in accordance with the terms of that license and with the
|
|
9 |
inclusion of the above copyright notice. This software may not
|
|
10 |
be provided or otherwise made available to, or used by, any
|
|
11 |
other person. No title to or ownership of the software is
|
|
12 |
hereby transferred.
|
|
13 |
"
|
21803
|
14 |
"{ Package: 'stx:libbasic' }"
|
7445
|
15 |
|
21803
|
16 |
"{ NameSpace: Smalltalk }"
|
7445
|
17 |
|
|
18 |
LimitedPrecisionReal subclass:#LargeFloat
|
24202
|
19 |
instanceVariableNames:'biasedExponent mantissa precision'
|
22042
|
20 |
classVariableNames:'Zero One NaN PositiveInfinity NegativeInfinity Pi_1000 E_1000
|
22299
|
21 |
Ln10 DefaultPrecision'
|
7445
|
22 |
poolDictionaries:''
|
|
23 |
category:'Magnitude-Numbers'
|
|
24 |
!
|
|
25 |
|
|
26 |
!LargeFloat class methodsFor:'documentation'!
|
|
27 |
|
|
28 |
copyright
|
|
29 |
"
|
|
30 |
COPYRIGHT (c) 2003 by eXept Software AG
|
|
31 |
All Rights Reserved
|
|
32 |
|
|
33 |
This software is furnished under a license and may be used
|
|
34 |
only in accordance with the terms of that license and with the
|
|
35 |
inclusion of the above copyright notice. This software may not
|
|
36 |
be provided or otherwise made available to, or used by, any
|
|
37 |
other person. No title to or ownership of the software is
|
|
38 |
hereby transferred.
|
|
39 |
"
|
|
40 |
!
|
|
41 |
|
|
42 |
documentation
|
|
43 |
"
|
22108
|
44 |
Attention:
|
|
45 |
Experimental & Unfinished Code.
|
|
46 |
The implementation is neither complete nor tuned for performance - still being developed.
|
7547
|
47 |
|
22108
|
48 |
This class provides arbitrary precision floats.
|
22041
|
49 |
|
24202
|
50 |
I store floating point numbers in base 2 with some arbitrary precision (arbitrary number of bits).
|
|
51 |
I do inexact arithmetic like Float.
|
|
52 |
But I am very slow due to emulated (Large) Integer arithmetic... (compared to IEEE 754 hardwired)
|
|
53 |
|
|
54 |
Unlike Float, mantissa is not normalized under the form 1.mmmmmm
|
|
55 |
It is just stored as an integer.
|
|
56 |
The sign is stored in the mantissa.
|
|
57 |
biasedExponent is the power of two that multiply the mantissa to form the number. there is no limitation of exponent (overflow or underflow), unless you succeed in exhausting the VM memory...
|
|
58 |
|
|
59 |
Like Float, my arithmetic operations are inexact. They will round to nearest precision LargeFloat.
|
|
60 |
|
|
61 |
If two different precisions are used in arithmetic, the result is expressed in the higher precision.
|
|
62 |
|
|
63 |
Default operating mode is rounding, but might be one of the other possibility (truncate floor ceiling).
|
|
64 |
|
|
65 |
Instance Variables:
|
|
66 |
mantissa <Integer> the bits of mantissa including sign
|
|
67 |
exponent <Integer> the times two power to multiply the mantissa (floating binary scale)
|
|
68 |
precision <Magnitude> number of bits to be stored in mantissa when I am normalized
|
|
69 |
|
7445
|
70 |
[author:]
|
|
71 |
Claus Gittinger
|
|
72 |
|
|
73 |
[see also:]
|
|
74 |
Number
|
|
75 |
Float LongFloat ShortFloat Fraction FixedPoint
|
|
76 |
SmallInteger LargeInteger
|
|
77 |
"
|
|
78 |
!
|
|
79 |
|
|
80 |
examples
|
|
81 |
"
|
24217
|
82 |
pi should be (500 digits below):
|
|
83 |
3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912
|
|
84 |
|
|
85 |
'%500.498e' printf:{ (1.0 asLargeFloatPrecision:500) pi }
|
|
86 |
|
|
87 |
|
22108
|
88 |
1000 factorial as a LargeFloat:
|
|
89 |
(1 to:1000) inject:1 asLargeFloat into:[:p :m | p * m]
|
7445
|
90 |
|
22108
|
91 |
1000 factorial as an Integer:
|
7550
|
92 |
(1 to:1000) inject:1 into:[:p :m | p * m]
|
7445
|
93 |
|
22108
|
94 |
compute 20000.0 factorial:
|
7445
|
95 |
Time millisecondsToRun:[
|
|
96 |
(1 to:20000) inject:1 asLargeFloat into:[:p :m | p * m]
|
22108
|
97 |
] -> 210
|
7445
|
98 |
|
22108
|
99 |
compute 20000 factorial:
|
7445
|
100 |
Time millisecondsToRun:[
|
|
101 |
(1 to:20000) inject:1 into:[:p :m | p * m]
|
22108
|
102 |
] -> 160
|
7445
|
103 |
"
|
|
104 |
! !
|
|
105 |
|
|
106 |
!LargeFloat class methodsFor:'instance creation'!
|
|
107 |
|
24202
|
108 |
fromFraction:aFraction precision:n
|
|
109 |
|
|
110 |
"Note: form below would not be the closest approximation
|
|
111 |
^ (numerator asLargeFloatPrecision: n)
|
|
112 |
inPlaceDivideBy: (denominator asLargeFloatPrecision: n)"
|
|
113 |
|
|
114 |
| a b mantissa exponent nBits ha hb hm hasTruncatedBits numerator denominator |
|
|
115 |
|
|
116 |
numerator := aFraction numerator.
|
|
117 |
denominator := aFraction denominator.
|
|
118 |
|
24218
|
119 |
a := numerator abs.
|
|
120 |
b := denominator abs.
|
|
121 |
ha := a highBit.
|
|
122 |
hb := b highBit.
|
24202
|
123 |
|
|
124 |
"If both numerator and denominator are represented exactly in floating point number,
|
|
125 |
then fastest thing to do is to use hardwired float division"
|
24218
|
126 |
nBits := n + 1.
|
24202
|
127 |
(ha < nBits and: [hb < nBits])
|
|
128 |
ifTrue:
|
|
129 |
[^(numerator asLargeFloatPrecision: n)
|
|
130 |
inPlaceDivideBy: (denominator asLargeFloatPrecision: n)].
|
|
131 |
|
|
132 |
"Shift the fraction by a power of two exponent so as to obtain a mantissa with n+1 bits.
|
|
133 |
First guess is rough, the mantissa might have n+2 bits."
|
24218
|
134 |
exponent := ha - hb - nBits.
|
24202
|
135 |
exponent > 0
|
24218
|
136 |
ifTrue: [b := b bitShift: exponent]
|
|
137 |
ifFalse: [a := a bitShift: exponent negated].
|
|
138 |
mantissa := a quo: b.
|
|
139 |
hasTruncatedBits := a > (mantissa * b).
|
|
140 |
hm := mantissa highBit.
|
24202
|
141 |
|
|
142 |
"Remove excess bits in the mantissa."
|
|
143 |
hm > nBits
|
|
144 |
ifTrue:
|
24218
|
145 |
[exponent := exponent + hm - nBits.
|
|
146 |
hasTruncatedBits := hasTruncatedBits or: [mantissa anyBitOfMagnitudeFrom: 1 to: hm - nBits].
|
|
147 |
mantissa := mantissa bitShift: nBits - hm].
|
24202
|
148 |
|
|
149 |
"Check if mantissa must be rounded upward.
|
|
150 |
The case of tie (mantissa odd & hasTruncatedBits not)
|
|
151 |
will be handled by Integer>>asLargeFloatPrecision:."
|
|
152 |
(hasTruncatedBits and: [mantissa odd])
|
24218
|
153 |
ifTrue: [mantissa := mantissa + 1].
|
24202
|
154 |
|
|
155 |
"build the LargeFloat from mantissa and exponent"
|
|
156 |
^(aFraction positive
|
|
157 |
ifTrue: [mantissa asLargeFloatPrecision: n]
|
|
158 |
ifFalse: [mantissa negated asLargeFloatPrecision: n])
|
|
159 |
inPlaceTimesTwoPower: exponent
|
|
160 |
|
|
161 |
"
|
|
162 |
(1/2) asLargeFloat
|
|
163 |
"
|
|
164 |
|
|
165 |
"Created: / 26-05-2019 / 03:54:31 / Claus Gittinger"
|
24218
|
166 |
"Modified (format): / 28-05-2019 / 16:13:06 / Claus Gittinger"
|
24202
|
167 |
!
|
|
168 |
|
7445
|
169 |
fromInteger:anInteger
|
24202
|
170 |
^ (self basicNew
|
7445
|
171 |
mantissa:anInteger
|
24202
|
172 |
exponent:0) normalize
|
7445
|
173 |
|
|
174 |
"
|
|
175 |
LargeFloat fromInteger:123456
|
|
176 |
|
|
177 |
1 asLargeFloat
|
|
178 |
2 asLargeFloat
|
|
179 |
1000 factorial asLargeFloat
|
|
180 |
"
|
24202
|
181 |
|
|
182 |
"Modified: / 27-05-2019 / 16:47:15 / Claus Gittinger"
|
|
183 |
!
|
|
184 |
|
|
185 |
fromInteger:anInteger precision:n
|
|
186 |
^ (self basicNew
|
|
187 |
mantissa:anInteger
|
|
188 |
exponent:0
|
|
189 |
precision:n) normalize
|
|
190 |
|
|
191 |
"
|
|
192 |
LargeFloat fromInteger:123456 precision:6
|
|
193 |
1000 factorial asLargeFloat
|
|
194 |
1 asLargeFloat == 1 asLargeFloat
|
|
195 |
1.0 asLargeFloat == 1.0 asLargeFloat
|
|
196 |
"
|
|
197 |
|
|
198 |
"Created: / 26-05-2019 / 03:54:44 / Claus Gittinger"
|
|
199 |
"Modified: / 27-05-2019 / 16:46:59 / Claus Gittinger"
|
7445
|
200 |
!
|
|
201 |
|
|
202 |
fromLimitedPrecisionReal:aLimitedPrecisionReal
|
|
203 |
|shifty numBytes numBitsInMantissa maskMantissa numBitsInExponent maskExponent
|
24207
|
204 |
numIntegerBits numBits biasExponent sign expPart fractionPart fraction exp|
|
7445
|
205 |
|
|
206 |
aLimitedPrecisionReal isFinite ifFalse:[
|
|
207 |
aLimitedPrecisionReal isNaN ifTrue:[^ self NaN].
|
|
208 |
aLimitedPrecisionReal > 0 ifTrue:[^ self infinity].
|
|
209 |
^ self negativeInfinity
|
|
210 |
].
|
|
211 |
|
|
212 |
numBytes := aLimitedPrecisionReal basicSize.
|
24207
|
213 |
numBitsInMantissa := aLimitedPrecisionReal numBitsInMantissa. maskMantissa := (1 bitShift:numBitsInMantissa) - 1.
|
|
214 |
numBitsInExponent := aLimitedPrecisionReal numBitsInExponent. maskExponent := (1 bitShift:numBitsInExponent) - 1.
|
|
215 |
numIntegerBits := aLimitedPrecisionReal numBitsInIntegerPart.
|
7445
|
216 |
numBits := numBitsInMantissa + numBitsInExponent.
|
|
217 |
biasExponent := maskExponent bitShift:-1.
|
|
218 |
|
|
219 |
shifty := LargeInteger basicNew numberOfDigits:numBytes.
|
|
220 |
UninterpretedBytes isBigEndian ifTrue:[
|
|
221 |
1 to:numBytes do:[:i | shifty digitAt:(numBytes+1-i) put:(aLimitedPrecisionReal basicAt:i)].
|
|
222 |
] ifFalse:[
|
|
223 |
1 to:numBytes do:[:i | shifty digitAt:i put:(aLimitedPrecisionReal basicAt:i)].
|
|
224 |
].
|
|
225 |
sign := (shifty bitAt:numBits+1) == 0 ifTrue: [1] ifFalse: [-1].
|
|
226 |
expPart := (shifty bitShift:numBitsInMantissa negated) bitAnd: maskExponent.
|
|
227 |
fractionPart := shifty bitAnd:maskMantissa.
|
|
228 |
( expPart=0 and: [ fractionPart=0 ] ) ifTrue: [ ^ self zero ].
|
|
229 |
|
|
230 |
numIntegerBits == 0 ifTrue:[
|
|
231 |
" Replace omitted leading 1 in fraction (Notice: quadIEEE format does not do this)"
|
|
232 |
fraction := fractionPart bitOr: (maskMantissa + 1).
|
|
233 |
] ifFalse:[
|
|
234 |
fraction := fractionPart.
|
|
235 |
].
|
|
236 |
|
|
237 |
"Unbias exponent"
|
|
238 |
exp := biasExponent - expPart + (numBitsInMantissa - numIntegerBits).
|
|
239 |
|
24202
|
240 |
^ (self basicNew
|
7445
|
241 |
mantissa:(fraction * sign)
|
|
242 |
exponent:(exp negated)
|
24202
|
243 |
precision:(aLimitedPrecisionReal precision)) normalize
|
7445
|
244 |
|
|
245 |
"
|
22042
|
246 |
1.0 asLargeFloat
|
|
247 |
|
|
248 |
take a look at the precision...
|
|
249 |
|
|
250 |
1.0 asShortFloat asLargeFloat
|
|
251 |
1.0 asLongFloat asLargeFloat
|
|
252 |
1.0 asQDouble asLargeFloat
|
|
253 |
1 asLargeFloat
|
|
254 |
(5/3) asLargeFloat
|
|
255 |
(3/5) asLargeFloat
|
|
256 |
(1/2) asLargeFloat
|
|
257 |
|
7445
|
258 |
2.0 asLargeFloat
|
|
259 |
20000.0 asLargeFloat
|
|
260 |
2e6 asLargeFloat
|
|
261 |
1e300 asLargeFloat
|
|
262 |
2e300 asLargeFloat
|
|
263 |
|
|
264 |
0.5 asLargeFloat
|
|
265 |
0.25 asLargeFloat
|
|
266 |
(1.0/20000.0) asLargeFloat
|
|
267 |
2e-6 asLargeFloat
|
|
268 |
2e-300 asLargeFloat
|
|
269 |
|
|
270 |
-1.0 asLargeFloat
|
|
271 |
-0.5 asLargeFloat
|
|
272 |
|
|
273 |
Float NaN asLargeFloat
|
|
274 |
Float infinity asLargeFloat
|
|
275 |
Float negativeInfinity asLargeFloat
|
|
276 |
"
|
22042
|
277 |
|
|
278 |
"Modified (comment): / 17-07-2017 / 15:09:30 / cg"
|
24207
|
279 |
"Modified: / 28-05-2019 / 09:04:35 / Claus Gittinger"
|
7445
|
280 |
!
|
|
281 |
|
|
282 |
mantissa:m exponent:e
|
24202
|
283 |
^ (self basicNew mantissa:m exponent:e) normalize
|
7445
|
284 |
|
|
285 |
"
|
|
286 |
LargeFloat mantissa:1 exponent:0
|
|
287 |
LargeFloat mantissa:2 exponent:0
|
|
288 |
LargeFloat mantissa:4 exponent:0
|
|
289 |
LargeFloat mantissa:8 exponent:0
|
|
290 |
LargeFloat mantissa:1 exponent:-1
|
|
291 |
LargeFloat mantissa:1 exponent:-2
|
|
292 |
LargeFloat mantissa:1 exponent:-3
|
|
293 |
"
|
24202
|
294 |
|
|
295 |
"Modified: / 27-05-2019 / 16:48:33 / Claus Gittinger"
|
7445
|
296 |
!
|
|
297 |
|
|
298 |
mantissa:m exponent:e precision:p
|
24202
|
299 |
^ (self basicNew mantissa:m exponent:e precision:p) normalize
|
|
300 |
|
|
301 |
"Modified: / 27-05-2019 / 16:48:39 / Claus Gittinger"
|
7445
|
302 |
! !
|
|
303 |
|
|
304 |
!LargeFloat class methodsFor:'class initialization'!
|
|
305 |
|
|
306 |
initialize
|
|
307 |
NaN := self mantissa:0 exponent:999.
|
|
308 |
PositiveInfinity := self mantissa:0 exponent:1.
|
|
309 |
NegativeInfinity := self mantissa:0 exponent:-1.
|
|
310 |
One := self mantissa:1 exponent:0.
|
|
311 |
Zero := self mantissa:0 exponent:0.
|
|
312 |
|
22299
|
313 |
DefaultPrecision := 200.
|
|
314 |
|
|
315 |
|
7445
|
316 |
"
|
|
317 |
LargeFloat initialize
|
|
318 |
"
|
22299
|
319 |
|
|
320 |
"Modified: / 10-10-2017 / 15:56:36 / cg"
|
7445
|
321 |
! !
|
|
322 |
|
22042
|
323 |
!LargeFloat class methodsFor:'coercing & converting'!
|
|
324 |
|
|
325 |
coerce:aNumber
|
|
326 |
"return the argument as a LargeFloat"
|
|
327 |
|
|
328 |
^ aNumber asLargeFloat
|
|
329 |
! !
|
|
330 |
|
7445
|
331 |
!LargeFloat class methodsFor:'constants'!
|
|
332 |
|
|
333 |
NaN
|
|
334 |
^ NaN
|
|
335 |
|
|
336 |
"
|
|
337 |
LargeFloat NaN
|
|
338 |
(0.0 uncheckedDivide:0.0)
|
|
339 |
"
|
|
340 |
!
|
|
341 |
|
|
342 |
infinity
|
|
343 |
^ PositiveInfinity
|
|
344 |
|
|
345 |
"
|
|
346 |
LargeFloat infinity
|
|
347 |
(1.0 uncheckedDivide:0.0)
|
|
348 |
"
|
|
349 |
!
|
|
350 |
|
22042
|
351 |
ln10
|
22049
|
352 |
"return the ln(10) as largeFloat with approx. 500 bits of precision"
|
22042
|
353 |
|
|
354 |
Ln10 isNil ifTrue:[
|
22049
|
355 |
Ln10 := (10.0 asLargeFloat ln_withAccuracy:(LongFloat readFrom:'1e-100')) precision:100
|
22042
|
356 |
].
|
|
357 |
^ Ln10
|
|
358 |
|
|
359 |
"
|
|
360 |
LargeFloat ln10
|
|
361 |
"
|
|
362 |
|
|
363 |
"Created: / 17-07-2017 / 15:15:25 / cg"
|
22049
|
364 |
"Modified: / 17-07-2017 / 16:42:27 / cg"
|
22042
|
365 |
!
|
|
366 |
|
7445
|
367 |
negativeInfinity
|
|
368 |
^ NegativeInfinity
|
|
369 |
|
|
370 |
"
|
|
371 |
LargeFloat negativeInfinity
|
|
372 |
(-1.0 uncheckedDivide:0.0)
|
|
373 |
"
|
|
374 |
!
|
|
375 |
|
24202
|
376 |
one
|
|
377 |
^ One
|
|
378 |
|
|
379 |
"
|
|
380 |
LargeFloat one
|
|
381 |
"
|
|
382 |
|
|
383 |
"Created: / 26-05-2019 / 03:47:18 / Claus Gittinger"
|
|
384 |
!
|
|
385 |
|
7445
|
386 |
pi
|
|
387 |
Pi_1000 isNil ifTrue:[
|
|
388 |
Pi_1000 := FixedPoint pi asLargeFloat
|
|
389 |
].
|
|
390 |
^ Pi_1000.
|
|
391 |
|
|
392 |
"
|
|
393 |
LargeFloat pi
|
|
394 |
"
|
|
395 |
!
|
|
396 |
|
|
397 |
unity
|
|
398 |
^ One
|
|
399 |
|
|
400 |
"
|
|
401 |
LargeFloat unity
|
|
402 |
"
|
|
403 |
!
|
|
404 |
|
|
405 |
zero
|
|
406 |
^ Zero
|
|
407 |
|
|
408 |
"
|
|
409 |
LargeFloat zero
|
|
410 |
"
|
|
411 |
! !
|
|
412 |
|
8634
|
413 |
!LargeFloat class methodsFor:'queries'!
|
|
414 |
|
22299
|
415 |
defaultPrecision
|
|
416 |
^ DefaultPrecision
|
|
417 |
|
|
418 |
"Created: / 10-10-2017 / 15:58:03 / cg"
|
|
419 |
!
|
|
420 |
|
8634
|
421 |
radix
|
|
422 |
"answer the radix of a LargeFloats exponent"
|
|
423 |
|
|
424 |
^ 2
|
|
425 |
! !
|
|
426 |
|
7445
|
427 |
!LargeFloat methodsFor:'accessing'!
|
|
428 |
|
24202
|
429 |
biasedExponent
|
|
430 |
"anwser the raw exponent;
|
|
431 |
this is not what a standard floating point representation expects"
|
|
432 |
|
|
433 |
^ biasedExponent
|
|
434 |
|
|
435 |
"Created: / 27-05-2019 / 16:38:43 / Claus Gittinger"
|
|
436 |
!
|
|
437 |
|
24217
|
438 |
decimalPrecision
|
|
439 |
^ precision * (2 log: 10)
|
|
440 |
!
|
|
441 |
|
7445
|
442 |
exponent
|
24217
|
443 |
"anwser the floating point like exponent e,
|
|
444 |
of self normalized as
|
|
445 |
1.mmmmmm * (2 raisedTo: e)"
|
|
446 |
|
|
447 |
self isZero ifTrue: [^0].
|
|
448 |
^biasedExponent + self precisionInMantissa - 1
|
7445
|
449 |
!
|
|
450 |
|
|
451 |
mantissa
|
|
452 |
^ mantissa
|
|
453 |
!
|
|
454 |
|
24217
|
455 |
nextToward: aNumber
|
24218
|
456 |
"answer the nearest floating point number to self with same precision than self,
|
|
457 |
toward the direction of aNumber argument.
|
|
458 |
If the nearest one falls on the other side of aNumber, than answer a Number"
|
|
459 |
|
|
460 |
| next |
|
|
461 |
|
|
462 |
"if self is greater, decrease self, but never under aNumber"
|
|
463 |
self > aNumber
|
|
464 |
ifTrue:
|
|
465 |
[next := self predecessor.
|
|
466 |
^next >= aNumber
|
|
467 |
ifTrue: [next]
|
|
468 |
ifFalse: [aNumber]].
|
|
469 |
|
|
470 |
"if self is smaller, increase self, but never above aNumber"
|
|
471 |
self < aNumber
|
|
472 |
ifTrue: [next := self successor.
|
|
473 |
^next <= aNumber
|
|
474 |
ifTrue: [next]
|
|
475 |
ifFalse: [aNumber]].
|
|
476 |
|
|
477 |
"if we are equal, return self"
|
|
478 |
^self
|
|
479 |
|
|
480 |
"Modified (comment): / 28-05-2019 / 16:18:01 / Claus Gittinger"
|
24217
|
481 |
!
|
|
482 |
|
7445
|
483 |
precision
|
|
484 |
^ precision ? 200
|
24217
|
485 |
!
|
|
486 |
|
|
487 |
significand
|
|
488 |
^self timesTwoPower: self exponent negated
|
|
489 |
!
|
|
490 |
|
|
491 |
significandAsInteger
|
|
492 |
self normalize.
|
|
493 |
^mantissa abs
|
7445
|
494 |
! !
|
|
495 |
|
|
496 |
!LargeFloat methodsFor:'arithmetic'!
|
|
497 |
|
|
498 |
* aNumber
|
|
499 |
^ aNumber productFromLargeFloat:self
|
|
500 |
!
|
|
501 |
|
|
502 |
+ aNumber
|
|
503 |
^ aNumber sumFromLargeFloat:self
|
|
504 |
|
|
505 |
"
|
22042
|
506 |
1.0 asLargeFloat + 20 asLargeFloat
|
|
507 |
1.0 asLargeFloat + 20
|
|
508 |
1.0 asLargeFloat + 20.0
|
|
509 |
1.0 asLargeFloat + ( 2 / 5 )
|
|
510 |
1.0 asLargeFloat + 0.4 asLargeFloat
|
|
511 |
|
|
512 |
20 asLargeFloat + 1.0 asLargeFloat
|
|
513 |
20 + 1.0 asLargeFloat
|
|
514 |
20.0 + 1.0 asLargeFloat
|
|
515 |
( 2 / 5 ) + 1.0 asLargeFloat
|
7445
|
516 |
"
|
22042
|
517 |
|
|
518 |
"Modified (comment): / 17-07-2017 / 15:06:20 / cg"
|
7445
|
519 |
!
|
|
520 |
|
|
521 |
- aNumber
|
|
522 |
^ aNumber differenceFromLargeFloat:self
|
|
523 |
!
|
|
524 |
|
|
525 |
/ aNumber
|
|
526 |
^ aNumber quotientFromLargeFloat:self
|
|
527 |
!
|
|
528 |
|
22299
|
529 |
// aNumber
|
|
530 |
"return the integer quotient of dividing the receiver by aNumber with
|
|
531 |
truncation towards negative infinity."
|
|
532 |
|
|
533 |
^ (self / aNumber) asInteger
|
|
534 |
|
|
535 |
"
|
|
536 |
8 asFloat // 2
|
|
537 |
-8 asFloat // 2
|
|
538 |
9 asFloat // 2
|
|
539 |
-9 asFloat // 2
|
|
540 |
|
|
541 |
8 asLargeFloat // 2
|
|
542 |
-8 asLargeFloat // 2
|
|
543 |
9 asLargeFloat // 2
|
|
544 |
-9 asLargeFloat // 2
|
|
545 |
"
|
|
546 |
|
|
547 |
"Created: / 10-10-2017 / 15:50:01 / cg"
|
|
548 |
!
|
|
549 |
|
24202
|
550 |
naiveRaisedToInteger: n
|
24220
|
551 |
"Very naive algorithm: use full precision.
|
|
552 |
Use only for small n"
|
|
553 |
| m e |
|
|
554 |
m := mantissa raisedToInteger: n.
|
|
555 |
e := biasedExponent * n.
|
|
556 |
^(m asLargeFloatPrecision: precision) timesTwoPower: e
|
|
557 |
|
|
558 |
"Modified (comment): / 28-05-2019 / 17:43:40 / Claus Gittinger"
|
24202
|
559 |
!
|
|
560 |
|
7445
|
561 |
negated
|
|
562 |
mantissa = 0 ifTrue:[
|
24202
|
563 |
biasedExponent = 0 ifTrue:[ ^ self ].
|
7445
|
564 |
self == NaN ifTrue:[^ self].
|
|
565 |
self == NegativeInfinity ifTrue:[^ PositiveInfinity].
|
|
566 |
^ NegativeInfinity
|
|
567 |
].
|
|
568 |
|
|
569 |
^ self class
|
|
570 |
mantissa:(mantissa negated)
|
24202
|
571 |
exponent:biasedExponent
|
7459
|
572 |
precision:self precision.
|
7445
|
573 |
|
|
574 |
"
|
|
575 |
LargeFloat unity negated
|
|
576 |
"
|
24202
|
577 |
!
|
|
578 |
|
24217
|
579 |
one
|
|
580 |
^self class
|
|
581 |
mantissa: 1
|
|
582 |
exponent: 0
|
|
583 |
precision: precision
|
|
584 |
!
|
|
585 |
|
|
586 |
pi
|
24220
|
587 |
"answer the value of pi rounded to precision.
|
|
588 |
Note: use the Brent-Salamin Arithmetic Geometric Mean algorithm"
|
|
589 |
|
|
590 |
| a b c k pi oldpi oldExpo expo |
|
|
591 |
a := self one asLargeFloatPrecision: precision + 16.
|
|
592 |
b := (a timesTwoPower: 1) sqrt reciprocal.
|
|
593 |
c := a timesTwoPower: -1.
|
|
594 |
k := 1.
|
|
595 |
oldpi := Float pi.
|
|
596 |
oldExpo := 2.
|
|
597 |
|
|
598 |
[| am gm a2 |
|
|
599 |
am := a + b timesTwoPower: -1.
|
|
600 |
gm := (a * b) sqrt.
|
|
601 |
a := am.
|
|
602 |
b := gm.
|
|
603 |
a2 := a squared.
|
|
604 |
c inPlaceSubtract: (a2 - b squared timesTwoPower: k).
|
|
605 |
pi := (a2 timesTwoPower: 1) / c.
|
|
606 |
expo := (oldpi - pi) exponent.
|
|
607 |
expo isZero or: [expo > oldExpo or: [expo < (-1 - precision)]]]
|
|
608 |
whileFalse:
|
|
609 |
[oldpi := pi.
|
|
610 |
oldExpo := expo.
|
|
611 |
k := k + 1].
|
|
612 |
^pi asLargeFloatPrecision: precision
|
|
613 |
|
|
614 |
"Modified (comment): / 28-05-2019 / 17:43:46 / Claus Gittinger"
|
24217
|
615 |
!
|
|
616 |
|
|
617 |
piDoublePrecision
|
|
618 |
^ (self class mantissa: 0 exponent: 0 precision: precision + 1 * 2) pi
|
|
619 |
!
|
|
620 |
|
24202
|
621 |
raisedToInteger: anInteger
|
24218
|
622 |
| bitProbe highPrecisionSelf n result |
|
|
623 |
n := anInteger abs.
|
|
624 |
(n < 5 or: [n * precision < 512])
|
|
625 |
ifTrue: [^ self naiveRaisedToInteger: anInteger].
|
|
626 |
bitProbe := 1 bitShift: n highBit - 1.
|
|
627 |
highPrecisionSelf := self asLargeFloatPrecision: n highBit * 2 + precision + 2.
|
|
628 |
result := highPrecisionSelf one.
|
|
629 |
|
|
630 |
[(n bitAnd: bitProbe) = 0 ifFalse: [result := result * highPrecisionSelf].
|
|
631 |
(bitProbe := bitProbe bitShift: -1) > 0]
|
|
632 |
whileTrue: [result := result squared].
|
|
633 |
|
|
634 |
^ (anInteger negative
|
|
635 |
ifTrue: [result reciprocal]
|
|
636 |
ifFalse: [result])
|
|
637 |
asLargeFloatPrecision: precision
|
|
638 |
|
|
639 |
"Modified (format): / 28-05-2019 / 16:18:15 / Claus Gittinger"
|
24202
|
640 |
!
|
|
641 |
|
|
642 |
reciprocal
|
|
643 |
^self copy inPlaceReciprocal
|
24217
|
644 |
!
|
|
645 |
|
|
646 |
squared
|
24218
|
647 |
| result |
|
|
648 |
result := self copy.
|
|
649 |
result inPlaceMultiplyBy: self.
|
|
650 |
^result
|
|
651 |
|
|
652 |
"Modified (format): / 28-05-2019 / 16:18:29 / Claus Gittinger"
|
24217
|
653 |
!
|
|
654 |
|
|
655 |
timesTwoPower: n
|
|
656 |
^ self isZero
|
|
657 |
ifTrue: [self]
|
|
658 |
ifFalse: [self copy inPlaceTimesTwoPower: n]
|
|
659 |
!
|
|
660 |
|
|
661 |
zero
|
|
662 |
^self class
|
|
663 |
mantissa: 0
|
|
664 |
exponent: 0
|
|
665 |
precision: precision
|
7445
|
666 |
! !
|
|
667 |
|
|
668 |
!LargeFloat methodsFor:'coercing & converting'!
|
|
669 |
|
|
670 |
asInteger
|
|
671 |
"return an integer with same value - might truncate"
|
|
672 |
|
24202
|
673 |
biasedExponent = 0 ifTrue:[^ mantissa].
|
7445
|
674 |
|
|
675 |
mantissa == 0 ifTrue:[
|
|
676 |
"/ INF or NAN
|
|
677 |
^ self class
|
|
678 |
raise:#domainErrorSignal
|
|
679 |
receiver:self
|
|
680 |
selector:#asInteger
|
|
681 |
arguments:#()
|
|
682 |
errorString:'Cannot represent non-finite as integer'.
|
|
683 |
"/ ^ self asMetaNumber.
|
|
684 |
].
|
|
685 |
|
24202
|
686 |
biasedExponent > 0 ifTrue:[
|
|
687 |
^ mantissa * (2 raisedTo:biasedExponent)
|
7445
|
688 |
].
|
24202
|
689 |
^ mantissa // (2 raisedTo:biasedExponent negated)
|
7445
|
690 |
|
|
691 |
"
|
|
692 |
(self new exponent:0 mantissa:100) asInteger
|
|
693 |
(self new exponent:1 mantissa:100) asInteger
|
|
694 |
(self new exponent:-1 mantissa:100) asInteger
|
|
695 |
"
|
|
696 |
!
|
|
697 |
|
|
698 |
asLargeFloat
|
21803
|
699 |
"return a large float with same value - that's me"
|
7445
|
700 |
|
|
701 |
^ self
|
21803
|
702 |
|
|
703 |
"Modified (comment): / 12-06-2017 / 20:56:44 / cg"
|
7445
|
704 |
!
|
|
705 |
|
|
706 |
asTrueFraction
|
|
707 |
"Answer a fraction or integer that EXACTLY represents self."
|
|
708 |
|
24202
|
709 |
biasedExponent = 0 ifTrue: [ ^ mantissa].
|
7445
|
710 |
|
|
711 |
mantissa == 0 ifTrue:[
|
|
712 |
"/ INF or NAN
|
|
713 |
^ self class
|
24257
|
714 |
raise:#domainErrorSignal
|
7445
|
715 |
receiver:self
|
|
716 |
selector:#asTrueFraction
|
|
717 |
arguments:#()
|
|
718 |
errorString:'Cannot represent non-finite float as fraction'.
|
|
719 |
"/ ^ self asMetaNumber.
|
|
720 |
].
|
|
721 |
|
24202
|
722 |
biasedExponent > 0 ifTrue: [
|
|
723 |
^ mantissa bitShift:biasedExponent
|
7445
|
724 |
].
|
7552
|
725 |
^ Fraction
|
|
726 |
numerator: mantissa
|
24202
|
727 |
denominator: (1 bitShift:biasedExponent negated)
|
7445
|
728 |
|
|
729 |
"
|
|
730 |
0.3 asFloat asTrueFraction
|
|
731 |
0.3 asShortFloat asTrueFraction
|
|
732 |
0.3 asLongFloat asTrueFraction
|
|
733 |
0.3 asLargeFloat asTrueFraction
|
|
734 |
|
|
735 |
1 asLargeFloat asTrueFraction
|
|
736 |
2 asLargeFloat asTrueFraction
|
|
737 |
0.5 asLargeFloat asTrueFraction
|
|
738 |
|
|
739 |
0.25 asLargeFloat asTrueFraction
|
|
740 |
-0.25 asLargeFloat asTrueFraction
|
|
741 |
0.125 asLargeFloat asTrueFraction
|
|
742 |
-0.125 asLargeFloat asTrueFraction
|
|
743 |
|
|
744 |
1.25 asLargeFloat asTrueFraction
|
|
745 |
3e37 asLargeFloat asTrueFraction
|
|
746 |
|
|
747 |
LargeFloat NaN asTrueFraction -> error
|
|
748 |
LargeFloat infinity asTrueFraction -> error
|
|
749 |
LargeFloat negativeInfinity asTrueFraction -> error
|
|
750 |
"
|
24257
|
751 |
|
|
752 |
"Modified: / 05-06-2019 / 20:06:20 / Claus Gittinger"
|
7445
|
753 |
!
|
|
754 |
|
|
755 |
coerce:aNumber
|
|
756 |
"return the argument as a LargeFloat"
|
|
757 |
|
|
758 |
^ aNumber asLargeFloat
|
|
759 |
!
|
|
760 |
|
|
761 |
generality
|
|
762 |
"return the generality value - see ArithmeticValue>>retry:coercing:"
|
|
763 |
|
|
764 |
^ 100
|
|
765 |
! !
|
|
766 |
|
|
767 |
!LargeFloat methodsFor:'comparing'!
|
|
768 |
|
|
769 |
< aNumber
|
|
770 |
"return true, if the argument is greater"
|
|
771 |
|
|
772 |
^ aNumber lessFromLargeFloat:self
|
|
773 |
!
|
|
774 |
|
|
775 |
= aNumber
|
|
776 |
"return true, if the argument is equal in value"
|
|
777 |
|
|
778 |
^ aNumber equalFromLargeFloat:self
|
|
779 |
|
|
780 |
"
|
|
781 |
LargeFloat unity = LargeFloat zero
|
|
782 |
LargeFloat unity = LargeFloat unity
|
|
783 |
|
|
784 |
LargeFloat unity = nil
|
|
785 |
LargeFloat unity ~= nil
|
|
786 |
"
|
|
787 |
!
|
|
788 |
|
|
789 |
hash
|
|
790 |
"return a number for hashing; redefined, since floats compare
|
|
791 |
by numeric value (i.e. 3.0 = 3), therefore 3.0 hash must be the same
|
|
792 |
as 3 hash."
|
|
793 |
|
24202
|
794 |
biasedExponent == 0 ifTrue:[^ mantissa hash].
|
|
795 |
biasedExponent < 64 ifTrue:[^ (mantissa bitShift:biasedExponent) hash ].
|
|
796 |
^ mantissa hash bitXor:biasedExponent hash
|
7445
|
797 |
|
|
798 |
"
|
|
799 |
LargeFloat unity hash
|
|
800 |
LargeFloat zero hash
|
|
801 |
|
|
802 |
3 hash
|
|
803 |
3.0 hash
|
|
804 |
3.1 hash
|
|
805 |
3.14159 hash
|
|
806 |
31.4159 hash
|
|
807 |
3.141591 hash
|
|
808 |
1.234567890123456 hash
|
|
809 |
1.234567890123457 hash
|
|
810 |
Set withAll:#(3 3.0 99 99.0 3.1415)
|
|
811 |
"
|
|
812 |
! !
|
|
813 |
|
24217
|
814 |
!LargeFloat methodsFor:'converting'!
|
|
815 |
|
|
816 |
asFloat
|
24257
|
817 |
"Convert to a IEEE 754 double precision floating point."
|
|
818 |
|
|
819 |
mantissa == 0 ifTrue:[^ Float NaN].
|
|
820 |
precision > Float precision ifTrue: [^(self copy setPrecisionTo: Float precision) asFloat].
|
|
821 |
^mantissa asFloat timesTwoPower: biasedExponent
|
|
822 |
|
|
823 |
"Modified: / 05-06-2019 / 20:06:36 / Claus Gittinger"
|
24217
|
824 |
!
|
|
825 |
|
|
826 |
asFraction
|
|
827 |
^self asTrueFraction
|
|
828 |
!
|
|
829 |
|
|
830 |
asLargeFloatPrecision: n
|
|
831 |
^ precision = n
|
|
832 |
ifTrue: [self]
|
|
833 |
ifFalse: [self copy setPrecisionTo: n]
|
|
834 |
! !
|
|
835 |
|
24202
|
836 |
!LargeFloat methodsFor:'copying-private'!
|
|
837 |
|
|
838 |
postCopy
|
|
839 |
biasedExponent := biasedExponent copy.
|
|
840 |
mantissa := mantissa copy.
|
|
841 |
|
|
842 |
"Created: / 27-05-2019 / 14:56:59 / Claus Gittinger"
|
|
843 |
! !
|
|
844 |
|
7445
|
845 |
!LargeFloat methodsFor:'double dispatching'!
|
|
846 |
|
|
847 |
differenceFromLargeFloat:aLargeFloat
|
|
848 |
|otherExponent otherMantissa e m|
|
|
849 |
|
24202
|
850 |
otherExponent := aLargeFloat biasedExponent.
|
7445
|
851 |
otherMantissa := aLargeFloat mantissa.
|
|
852 |
|
|
853 |
otherMantissa == 0 ifTrue:[
|
|
854 |
otherExponent = 0 ifTrue:[^ self negated].
|
|
855 |
"/ INF or NaN
|
|
856 |
aLargeFloat isNaN ifTrue:[^ NaN].
|
|
857 |
self isFinite ifTrue:[^ aLargeFloat].
|
|
858 |
aLargeFloat sign ~~ self sign ifTrue:[^ self negated].
|
|
859 |
^ NaN
|
|
860 |
].
|
|
861 |
mantissa == 0 ifTrue:[
|
24202
|
862 |
biasedExponent = 0 ifTrue:[^ aLargeFloat].
|
7445
|
863 |
"/ INF or NaN
|
|
864 |
self isNaN ifTrue:[^ NaN].
|
|
865 |
^ self negated
|
|
866 |
].
|
|
867 |
|
24202
|
868 |
otherExponent = biasedExponent ifTrue:[
|
7445
|
869 |
m := otherMantissa - mantissa.
|
24202
|
870 |
e := biasedExponent
|
7445
|
871 |
] ifFalse:[
|
24202
|
872 |
otherExponent> biasedExponent ifTrue:[
|
|
873 |
m := (otherMantissa bitShift:(otherExponent-biasedExponent)) - mantissa.
|
|
874 |
e := biasedExponent
|
7445
|
875 |
] ifFalse:[
|
24202
|
876 |
m := otherMantissa - (mantissa bitShift:(biasedExponent-otherExponent)).
|
7445
|
877 |
e := otherExponent
|
|
878 |
]
|
|
879 |
].
|
|
880 |
^ self class
|
|
881 |
mantissa:m
|
|
882 |
exponent:e
|
7550
|
883 |
precision:(self precision min:aLargeFloat precision)
|
24202
|
884 |
|
|
885 |
"Modified: / 27-05-2019 / 16:39:06 / Claus Gittinger"
|
7445
|
886 |
!
|
|
887 |
|
|
888 |
equalFromLargeFloat:aLargeFloat
|
24202
|
889 |
aLargeFloat biasedExponent = biasedExponent ifTrue:[
|
7445
|
890 |
^ aLargeFloat mantissa = mantissa
|
|
891 |
].
|
|
892 |
"assuming normalized numbers, they cannot be equal then"
|
|
893 |
^ false
|
24202
|
894 |
|
|
895 |
"Modified: / 27-05-2019 / 16:39:09 / Claus Gittinger"
|
7445
|
896 |
!
|
|
897 |
|
|
898 |
lessFromLargeFloat:aLargeFloat
|
22041
|
899 |
"return true if aLargeFloat < self"
|
|
900 |
|
7445
|
901 |
|otherExponent otherMantissa|
|
|
902 |
|
24202
|
903 |
otherExponent := aLargeFloat biasedExponent.
|
7445
|
904 |
otherMantissa := aLargeFloat mantissa.
|
|
905 |
|
24202
|
906 |
biasedExponent < otherExponent ifTrue:[
|
22041
|
907 |
"/ my exponent is < than the other number's exponent.
|
|
908 |
"/ left-shift the other mantissa
|
24202
|
909 |
^ (otherMantissa bitShift:(otherExponent-biasedExponent)) < mantissa
|
7445
|
910 |
].
|
24202
|
911 |
otherExponent < biasedExponent ifTrue:[
|
22041
|
912 |
"/ my exponent is > than the other number's exponent.
|
|
913 |
"/ left-shift my mantissa
|
24202
|
914 |
^ otherMantissa < (mantissa bitShift:(biasedExponent-otherExponent))
|
7445
|
915 |
].
|
22041
|
916 |
|
|
917 |
"/ same exponents
|
7445
|
918 |
^ otherMantissa < mantissa
|
22041
|
919 |
|
|
920 |
"
|
22049
|
921 |
(LargeFloat
|
|
922 |
mantissa:16r73419B6C66183FC9AFD6C972CA17C5BDD9A3E1E589CCECF3D0934A9820699D6471CB8F5C0DEF275FA663B9BEB4387344FFFA2A9CFC8F38D9D45D2249228FCA5F6BA914F5B15F16A9DA13944E435769F32175977EFD55CD5DE8C1EEEBF127F8D4F222F63109CD9C7153E9C3D436D958404340F1A6918F7853DC28F1F6BB2BEBE93274C7E8BF88AAF6846620F323E2A9745CC6B79A230B35D8623FC8BE9DFFA01E93159C01BB42C0C072B101C42F461DF587EF2DA06F67C2E574D53346018E0D58D7FE0C38F1C3EF198C5628D5890FD8BCEE3E0E8CD4ADA9788E43B2C16D9ACA7E90921D1E41E14D2291440A5682AD65DF6769B2C9927E2104A533A4038B708EC6A554F9BB81F5CD026FCAFA11EE5316A2C3BB1FCE935D91E14123ABDA667BDB9CD8FBB08D3EF0A21000B2B1B0F98812B26B600D207685F1A15C4D8FD48D87E255A983D53565A546FA4C56240FCF68A17791768C90979043CE183112C0F8EBE52EF8AEE81CF0DFD8D22D77FEE27837CFC8EE9FECD043E7169972B048697E657F3B6088C929C3E5D17666EA540491782334587DE7263DE82778ED04DDE009F050905515F4525B2BC20EC274626C10C7873E1D80639FD9B2E5B25DD58EEBD5BCE8560F05B3A066E2082F1E01BFEEC9776A25E7CCD13F0264146748BF6F09721FAB18DBACD9C797ECD5B1896B0194266DA6FA0CD8DB214BF362D7145AF5D697EA98B99896340439387B6BAD623B59E50E54310AA8FD38D3B222519E37B55078020AD751CB029AC8B067C557F1E939003F8C88DE55842A485BB736CDAFD1FC0ED330A7BCD0E1D5727393201090FBB03B12D4C8F9B7D05843BF755DF745AD0F8EFB8F33FDD06B072BD79BBABE06CDEF89E3B7B02D951D7669C95F9FB3C602DC192960B534AB7729C0233C6B348DC1505806BCEF16C8E9548BB9A6F80E9D09E6D65ECE1F3CEAE137C9D8F5BD821C26E85D80196DB83BC4EF9ECD128BC5989C9237D7917D2FD9B14A69AF41373496945F70EFE605B681DA9DB61A0CFB3C8330EEF93D7238B7BD2116BA96A7AA9F7844FC3983D09E8A6D2DBE7BBA585D8802773B1E7E9FF846091D181FD532575186BE4A02F62C04D157AF16190B98A3E32C591EE8D4E01FB55351744B829C20D30834D3C423D5D708DF4A64DF51E65F28AC2752AA170B81962E14C618C7A916CB2B68BDCA92E8A9133B4AADBBCC0A13A85BC1F925E4CD9956C0639FA8EEAA72A975F7952E5DD960F8647CCDBD44D34E0B4591B3D8A905686E45F12D2D4FE4B6DA9D026089074D7ADA26BC7A18FADC641694A549EFABA3079387A31A1269E8FB0410A31BBD2D7ED12C8E07978FE61AEED0D546CEA13961D1C294FC277B57C7FF7CA5B0CAA9F714C673848B8C91D4162752A54EBF5F17710D19C62D78892EAF86EF1222C70B1F4986BB7F51876AC419B1CA90894E88328371AFBAD15433C2741830E870700635AA19F71F69A772F920716FBAF780343937AEE25CA0C50C93E47ADBAEC1D23068AD703CEDFD597229B8F84E74B2FD99D96707097310246A9581912298E6B6BAAF1D46F0A2454CDCDC5D62A0738B60D39DB542FC72142CAC9583DC3FE6664C30E42405664696A43AD55633E3380930805D0B33ED87FC6CED153BD9AC623F926273AEF825F8E6AF3080C731BE88705D314CC4275B9A0A959AB99F8B9D312208BD64E5C9848993F2E876EB9C4C3908D8946F9831B31D2124DCBC129EA20D4742CDAA19967BBEFA5135A9D7E546E22B607D3541D8FACC46E241D22CB1120A51AA6A761918F791EDEBD0CCE46CF287C9C5E97D1470A086216EC47EC7896650926123B3C2D0BDEC68B192490FFE4B164D6202E9AC38FFC9ED01A936667A02C6BDA448CC453ECAB674048C1C4F9464683E29A056510797ABC115E99642899463FE9CD0E3553A5D5940B4475555B2B27FCD407402EF9988DBCC49B8E213951C9C8303B1538A9E34310404DBDCB8B29B22822764779F4233DDB802ACD78434888EFC63B09F9F2283A015415D25B182DF6B8A5A6CA584012BFF5D7DBDDCDD3117375293BE18D64C5CB32D9356564DD2D1765C160846BC2F42FBD191802E0B30F6F543C103C93EC9A38306C8092A179895E1CE645ED100E1FF51F12E83EC97B0F9360B5E35959C667648D1343F228C05D3AFB419960153BC780908D62DE5A7B033C0926EBA69610B7F206E9C0A157650F85D05EE12831C254AECD2E3A013B8E0A176B205979B46F60F3104E46A6E667AD4613DB62038A09A7B772DB38AC81CAEA8538B0C266D1B604C9C24F1CCD9F891DF587CA169EDFA45AB7F57E71775D20238079F17433D1BFDD7FC537BF7A6BC02C627EBF7AAD3E5030E788EECEAE1CE0FE09CD0F46941272A54010756593FFA80669955701EA66AEDD96DB6CDAACC9064039C1C3A0D4250CF75A133D5D4314FFC9D678FC1B761B0652DE9DB14CCF1C0546BDC0BA6464EEB9667CFD3E6CF44A476471F0E1801F46C9F7FDD8094C2D08A668FF57A771B64CBAB9241CCDAB6C3A2112059BB67D8044DBA7A95C04FF9AE6D0B5C3FD3F8D76D83BBF28F4D44334895F9468708432BBCAC62458B899F5E400627F83F4F331A74638976401D9D924935B5F5D897AE08E984C9DFDCF457DB4DC5DBAE3D6CC1BF7004ECABFE6326105B9A98CAF4661614052ABB206D6F6C7C51FA0CD5EC2036F367095D0DBEA54F5CE718D1E21EF2DD251D4F1FC6A70D2F8D7F7AB7E3DA847ADC478789E89AE2740270B3B16648A59B40A0A865D9E8C2DF90681F3DA7460EC03C48278C19117FCAA575FF9896A4D467950C84F8794331A44475B1BF6A426CF64BA0C03BA6C862A8855963B99D94CF8062E9F19831D135DC3E1A98D4954D6FB4EC4C2663B6EF0CFCEB628B8FA43E3FDE18B34F3C0FCB63BD1E9CCA9F71007858DFC58AA4D6775C3E7F77746D1420956B9FC21408DFA4DC6A108905D443F9BB0A3D1A30B737787DFAEF96C2F0507799DAE84BBC030B7F423FBBB85D109DFC337BDD0D403A3C6859520F17FE35A39ABF6516A390616DD86ACAF554BC40203F269665A14D1CD40D65852206BE49C7778CEA3D46BEC1A9CD6DA70C36B32E616E41ED54B71DAF6DF38CB937D022EFD61B55A81431809132ECA1B28DFC40703B7E05DD46B77C6E147A596A6CCD1B5BB3E9A24B24BF7C36D2CE8170CB2B59B8558EDBEE28F1CEF80F56B5417E6F9F4776CB8DA0DDD13275BFB8860C63FF5D1EE8E3C9DFB30EFAB30C06C805F7492D5D7D3E9AD6C08560B1F39A09848CC9C165B59D380A3F7F4A8350F9E292486DB513BD32A9D69DFE4C0D8B42D31D623F0D7757DEC1456AD7459FBD4F1370775E79B008623969FB0D4967988A0ABCBFECC86A81F6F331196ED85CD88E7452014BE1B1FDCD6E745D97441CB15030E0FB0C4DFCFABB466FF405024273BA29D896DD17E37E40F795E49B573C3AFD978EC78AB83BB1ACB6E4803C3C12AF5B08ABCA664F352511EF0CC3D9C8F5C4C3E7A420B77E52479C77CE3487F12260633FB53F2FB73615E2C75D6C3B47CE34A6A3047EB437D93C51CD27E66B03E30F78D9EE36C51851115BBE90BB94AAF075FFBA93093928AF492EE832A4869FF5D0715523933E7F9ABFF3A1EC08A39D2FBF53A43A7C4D7FFD69AA907EFFF9B72CD9E285128BF916BC9715A61CB32B2C4E11E38E1621A8ECA1CD20CB2A3AA68E73CE573E38A97B97B7759F18FAC271D8AD7690FC8550091585E555E68833AA88FB4EE95004D4760428820855EF13F4FB0475B353BD9CA3FB6C9CE8A0B4AE63EF5DA7E9B98B9FBD3B1C7EF7B45A7014EB79939921848CC9BBF71287B145FBB55D207F5F0919111542E5352F2B2D00B8A32A0F40EC65810F23C92BF164F104552D3E9CDE975A696954942B435F3840469A4D4A321DE82C4AB109AA276CD777796A1C4186A47786E6DAE4B066D0060F7560B1A5ABD545ABDF70654F01C52EB870620E2C5D34CFA167FEBDC04DF13FE24AA2901F745B8D83613DC459E227903BF97EE0E4107B6B94860B3220CE3DCD04CF73EBDDF4617AB087FA9AB015F2563F786A4AE4F19B5386D68C525802E95CDE7E4469135A566ACAB0E1D4ADB99401A7712179593EAE5BAB70A9116A4AE999304538341B51E6038515D73FABCAD826A87106B3ABD18A95DC0E69B39C26703D5592B30F4C42A87CDBF94DD4681447A7ADD39231EB5E08261AEC134D4670988D59E847883AD1C4C0182D5F87436DF4710A1044613323C2617BB7DAE197CD01D015EDEB979A5760BCD39BEB4A3168A591B8421C578D060F6061AC0E3618C25804784B0431570CF59025DAD46651C392E38A620C588E004E80D4E14A0EFF7D237E6598BE8B0644855118456CFDFA507C6C660B9EBDCCB330CADE0DB4E1229F1DD8512A5921EC1759B4B37433A0E8CAB03BF65FA6FFB7AAD203E3D7410F0CFB0235B37B6C627EC266C68D9CF912AA0BB3E873ABBB1110C7F17CFE86352315E2E172725057BA78DA74C9AD6C1E06C1CE76941CD081027BC932CF296C17BFAE8B32B3D8B77BB6544FD75BA6A0E5E90614DB60000EFF2255600CAA598B8B11F5980FD0F70524BB4982857E1BA8E39A36BB08B2F18BB903CE3708258EB80998FB768FFB7A489959F610043FF2B5DA914A5AE479DAEC2BCFF0F055D1B40F2E7BCFFF14E753E5443420825A2442A362E1277F1D14BAEF6F591873578055DB53EA469F221FDBFA6FFC8F00403B503B1BAB2E9E62ED81BB06E6AF746136BE3500EE4089ACF56898A2333B03300407E841C7F3E6A17BC30E8DB340EF6F840CF64CAA04D86A5AFAC9EBE34A7201EB45B3DE177CB2AB56408CFBF33BC5DED12EB63E3F831993C978065A649417E5625B840709CB6A14610D60485C1DA48CFC8C3E867D5785D32F4E827D0B546B0D473E49CF358CF4F4CDF02A4BDA41938DA8E1E1184DDC76202305CC360F4E9F524B2A00A327C3F18217E4D64260C972D849DDCC375EACAD4B4976929E26C7CB798E34B70F87A73981452F257C8E45826F8A60323624313DAF37177F329D3939649FA9FCAC4D076E163DCBD313C43AEB67D207B5201F7D87AA91B39D9627C0C582BAEE8145387CF3C2827B426FDAB3930A68CE97BB45961F4DA22333CDF4525D8996A51F500456F41EA1486FD22048310AB7593C8D35DFA25CD15BA4D586574FACF98BA6B17CFFBE6B65A68FD3442910093F620AF83BC37C4E8BCDBCDE3D3F7837769D7602B68A1FF08E878198EF73E2A5EA512A4A2AC404B7E3863E36F91FD4E9A54F267164D5E05DAFAEE6037AE815A50B53F2D288185FC9C4C1D01A7EA2A53EFD2EC2B44B616FFCC6A98AEC9A2A36DA7C82B1400C07B6C73A809764E266978A972C71F485562280BB71375A61FF92620DB9A0B1ABEF6956A7BA0B703DFEAF755F0BBA79D11ED191AC25150456ECFB3D9B4CDAEE3C8D010C7EF7348FC44BDF656209361E439F6033A8692941488B5EC0B446B33D777D7A2434D169FD9237EA8963C766E198325A6B52054ABCE94AD928DAF76094397EB216FA8B780A619D93819D34DF2F2AB418FC3F7F2A344EC01F972CD8942509E076BB9A33C36ECA76B6005F14839429B217CAC37D462F58A371F248E635A010CF6108B7189405443A809D56B9959112680AA581A1E75B8B17270AD4A3CFE970E45ADC0779B4E3F6506758853A74782D49BBFF9D6091E1A556AEF45DC87451BBDE54C8174A28797913E3BEB9DB4D339CAC763D074300E03B2BE2CF7B1567D2C950A6169B5AE72C157D2F8F612F3012307E57A6EB1295F601A4496DBC4075A190FCD1876530B4EF87B744191A73BACBE2A0E773E404A70E3E1CAA3221C9DA573BC5F08825939C2078F73FFD566342D23FC1A30F45235CE4F4E6C8B632B26B666F53023D77A091F96AEF17472CE0C7E67A76D71A192A6C8E55F04832A3E1425A0E11FEFA281EB969C7FC27527130A3E7C9DFE7248177829C02CCDE592FBF4EE4D10B6623DA825C64647C0F576E0A65461EBA24D460184529FE288DBB1FCB810AE02879ED11810FD104D0F6BA7419BB803DDC7785661D87CF2CF7835D74951F5C6D8BB4A07692A742C667B93E268A13AFD09471FFA5240873A27962E07E2BE074D6FF0CC0A5BA51EB047F63A4DC51867377143773015F76E0D54EDB1CF91D1D0A2AD4B926788C210708053F49E9417E6C0827735D008C4BACE7FA902E019F696D765C1A7D94F922B0A1831305354F8477583A1C503B296F1467032332BF7EF994D64B876EF9AB6F2737C2E487F9C562BB09B4BC121461A80C46A459B2E455D0CB0C0DE84EDA61C4A41760239CC53202144C25841E8BAC38A8D73A621B1F273B0093593E3D7B5B533B583AD219077510043D086275F57278E4D0C833233077E03E4893F68969A244639F5FCA56E01DB205EDE8BA5A556CFF30E60FD4099CF2223A5743F1C05D1E67D793C82E8652E92C9407A5253AEF9092A5EA2AC4700FDB80323E5EC7440C6D051E33A6EDF44511532388E28F0867E4240ADCD61E75B202A7405E2E661973335D811A9EB71CD0F6730DA8275354B8E26386CE5F996772B00C1A6401B6B44D653A20552514AAE891967ACD3C4E7947BCCE78F845B6019E7CA47672A27A6B41E9B4744926F0FBFB5BC70F7E016F5BDF634397E3123B5B01AADE031B6A478EEED481EAB1FC7BEBBC824094F9A2B5E3341C4B2316384B265D864B2471289B839DC3337378B01FE9F66EFAF9C0A3E829D9CFC3F49F9ACDFCED72701B756C5524EB739CA2227D1592CAA74E476DD7DCD0C7BE8E7F6EF8C8A6935EA50ADF975E3D81AADCCD22B4D7AE60AC515E1971B6E009751CAACD14608B64CF764CE2452B708EC63AE9EF0BE2A3D6A180B2F45353C011C0C29DBDD1D144291F1E3D0719F909B49970664B53000122ABD011C4BE7BB33FF06CD694C5CFD60BDD321F45458C186964223465E0A25007AB28F3B843EE53BB60A65409F1DE6860B7B45A49EDE835F860A4054382A1486A4BFDC0963434BA913D8D891943E3779A3F9A3BEE50844443F7863652F0C2525F654C45A2B4BA9128E98D23A291B94BC52AF419B64BA3A845F7F066F4D98B8FD3765EC94F97676B08D071475EF8C109F15107455E86D8947341B5A089A47858CBBA802BA5F8B08C68C366D7DC14EFC2ACE1E4A3A09553351B9DE051690D88D09F9C9431C73A4FF5F488F29D3D19C98312844421663A31CBC513962B75E9EEFDFA4BF03FC7C9460E3CDA09215E0D55F66A4043676463F0D680D0BBF3C81348E67064E356DE16CE74C04B001DD6D7F6B32547466835F5B2B2C2790292F37CF1E24EE4689A816DC088FA6B923CBC355D829C337663840B89BEB6E4BD95402E81D152B88C5194FD45DEE2AE52970B9205F33E21A3C60BF8FB7AE5C6AD95E1C6C5D7BC2E7C69A86DC3002939DAC5D98A46DC97AEC834F6AAFF3838F06D757FF536422C1E8DBA283D4DDC954041333980C7F73D7E651EA0501253E667F520B553DA3039A7612A7053107ACC64FA7639D74E1AC0033476483C62DD340FDEC823ADAC5979433270F7CE55E66E86297D19A3370D95C653BC9E204338D4A50AD1F77CA8A21EFFDB9A596F625C9708B0C42FAF9A39ABB5E0B003C169854F5E52C0506BA25527876CF6AC5D220C4CA4047FE5891F762C8D02331A7730C9657FD1612232AA6EFEA532531774922394A10117AF4E1C4E93C834D9B9DB36A282E33B8F9AC6CA03D6684FC185DFD3BD5540B3FE98E7ABE26DE57C65A90E0341E92AC700E7C7863E9D9BD0CFB477F1832DA9C18DFABB0D8DA2214D5FB895F42E358A27A9907B40035A292A2BD0EFBC2F82EFAAA04D5D2FF34A3C09D3A449318C7EB326BB57BE88A52AE0B75E9DFD6E504C8512188350107A7CFFB9E9F8109C9CD131CE8419B53C3836E7806B7E24910D8A8F3C13649F497A0BE2CFB711294F8DE601FBE36913529B65E78997580AC9182353452BC742DAC6FA86A5598E6F8AF6BF215A49ADDE14151E57EFC39893A73FE531DE2C038B136D0801DF66135B1EAB463795E21758D55F096318DFC14AC020E58BD7FD47CC90D9D664C32620E63A6EFFF9C6463F8CC52E1DC5D69DC403F0708B02D212FB39CE7DB1443D76CA9F962BB15F28B8C9B6D1F3F28BF9308D84B782085C4A0389D4C725F3B08188C27D3EC81FFF152F15E59E1428D3363FE71718F4B64F7A7F3BABDB87DBF6233B8D5A3A62C5F99CFEFA0FD713EE1D112E066B93280D6A0A98DF95D0E471FFEE44FB832808B23022BFCDE7709D19F2456909DFDE6D9189CFD4868BAC1AE9F4EDB6F0DA3BB8A56FB7060E1C6B86770DD1089DD41BE093AE2887C5892C3B6AAA04671E77909099B8A9CBA8E0D45305954CEC7A76D38A5BE0368ACCE3FF52121705A7996FB0475B1ED152BE5B469E10A91D8B08B4D7B365EB56F40E5381BAD0E4E6A2FA2557653C4B1F0A5C19A06965CA9BA68DD3C16748E9BBB9112C37E1B3966D42CF04E136CC29AFCB124B919CF32DE8ECBCE2E4986448D9BC544E6BA30FCFE1EB1DE332F1ED4D9D11B862B7FE4FA23330461CF5A0E3364F420B3E062C895EA9D4B9A1782B48AEEF023C4034BC1164739406488BCB27BFE44E08A9F19254934DE309637A0A4F429087DE71D30D40E99EE92F3EEA666DD000CEB6A62335A3B1806C812B0584ECD764B5A39931D1F1D35B2C73436548FE7604F666868ECA7E87DA735FEADA16E8671ABC0A0374ABC8BACF3B5818A32F5CD304E5B08F0AB5F0578EE26E6A4651C54545B215C404CE15F13387EBAD29EB52C804555E8045BCA43D0025518C614A7409D608D0B91F8D6B5C678E64AF01BE1D4EB2B765CA248AE2896EC3A2E58045CBD31EFBA4F4D3DE6FB6DD3E649245043349476367C4B422151F4C2BC9BD4CC1CFBCE0155C99115E463B603450C2622A3AC209BD082145717C028AEAAA3F40E180E1CFF740280C6CFEC53D3438253DC3F90301226769077A0E47E3F4F9EA4CEE093860593C5CA3D2A2C9C34E948DF635CDA5D743732A0AEB6F5ADD5B77EEDFB6D5A5A96AF56D383556A796BCAA826205205785332CF4223536FB56FBA32BF3AFD4A76008F433AF2BB5C443CAA751980B49463C4451A2B822F4AA03FA4FEC320B70C1DEBD80873666AF8CFED6BFD622F5C99D9584EFAAA2AEFCBD1B77DEBD977BEE07ED760F722854F329A83C79A2D7474CD8A78099892BE889C437D1A2E1382987D137E8D5A51256A2D561B668F6295687020C095B8FAF3ED2B61703F89FAE4F3F8FAB92B1A8EC58D0ECAFC3517E4797FCDF1241397B49C23DE6EB1BFC42A150DAFF4BB43C936D8ECF25E2B9F7F646374EC2A6DDBF5C55EDC5055EB98E0F2BC7D9240111492DD2895D2367EEFEF6EBC4F217E564706103F257C3CBCC52292081530218D82338ADB0110641504E2086A07F3C74B03961ADC5FE94B0299FAE17F6F09FEE85F7D67B0B066088AF8A41E40CC79986B01DEE4F73AF386EEB0554A1FF6478EC0447BA64895BAA0F238AF9CB8C2EE5F7C3294F4FC5FC4B2E6808B29DCA7C768CA37949B4E9B42A31F1754175801DD92D205A35E77B5C6DF26B15E20B104108DEE7F5742CEBE1D886E68FFF894F4F77DB167DABDD5679018679036CB5FC91D764157DE04EE9EAF4F11F529D96FEAA486DBBE6850F1DF1504A8D65B20441088DDA0C9EE3F851FB134B9AD567411053D55BB50D964727BF14B7F540DAE69F95FC24BCE0769408516C1861B95CC7DB137AFE13715D2DDF72C240F04E607ADCFEBDC52612A12A954B5DD436660BC49C74E521B55B8FB62E99EA6F27E2AEDBA37DAECA2A9B98099004C278759AFF14D9C6BB7D30CC56E0E7DD1F458A2D64748657BACC59A1DED3FEE9CA308884DF5A69F5EF738948DCAAE04EDE0C7811813B92AF605CB631291998A54C00C1B880889AFA90D15DA0960C859AA1C0E050AF5C6A021685D95BCAF85AD37FB7DD1CECAB684BC3DB11DFA815B3E5760402A12EA512AC1E6010AB87C98D23E5D660454356AFBCD8ABE65E023AE1777D5AA187FA7B3E4A7D7480CF3472E876783BE57BA7CC1167A323B444CC9346619AB8B3DACDA8AD3A3054FECDFA98C338A4219EF79D3A7284987C6E664964259F7C960FBDB08F5EC1DAB2C0CBAD93DFB5D2098C2CF2009CCC213F640A506320A53253EFFCC780D881B1DF427C84E90F6460BD89708A7E4075F47F51725214BC4931E3D8940BB32B9E73D1D846CF142BAABA703BC2FEE6718478C2FBF334EA902677C6345F90BA9AD3BBCA778BB54C0B5CA4121DA3B6357771D918154E78B5E3FA921933C26F596B96660EFE988C64EE1672C22F3DC0A88E909EDEF10D5F31E544C96F61C31B483AD3942DD11903613BB496ED7490E9C95E6ED67C3B0CD88D18EF3C6913F722C10E6846DF1162D87A226C6F91835E6E215B1A1167A464CDBF9565382787110CFFE5665E80CF19EC907D0800CC86EE4622074AE171E7B717B440B26F832997960D96695C92D5226084EFA6E0ABCCB31424C69107798909B4CFFBACE608920ECAB318FE65252771C07B2CAB5846B5108D9FE8585391ECF43C6656425AA83EEC0A046A527364267E1DC57F4881E494304948479BB63EE2EFDDF5E9AD9487B454BED7ABEAAAEC16714F4EAF6EFDBB836B32F8DC9D7F81FFAAFF251BD41AAED70BF7313035E5DEB8CCE4BEB9A3AF9C7196A638474313D3FB7CA9635434A15AC344B51486FF11C8C857AC2746D57BF6CD722DB7838EAA5048D786679866A4C4873EEDA01B6C3DBC5E8D9971385F64B4FF675971F37399BAC3D3A78E06051F4A46BA0733D22C4B88BF1331FFDAF6DA706827F0B3E25FDD5447808CF498D6D19E20E8118ABBE0C753B42630C71E1D95DA2A2FAB6191302E86BA53F56B472723A8451A16930243ADA76A2309DA4AB4D257451B237A1407D2B1555BE13DD8519F3DCF4101BE161EE3A4C7820DA60EF2664B4C21B7F83BD5A2C9C73E7BDC5CDA8F7754853200B603C97D0950AEFC147123BAA6139C62EDC56263314BA1640DABE28F7D1AA86C38BC69823E242383B72C1C97F12D78AA6638BCB5E4296E19F2F68D665B36B988718347445F66563FEAFE88639BF7F53C70B3A754C5AA1095660EE40A29D2154031489A207B83976D0AA0117E122A4A879F05D2BF2A3C8629FB845F5C14722954539324F325321B9C46563D5FA5927B9BB0A00921602E77AC6152AA026C421E8B7233077321ABF69FC176E53DB210D802A9DC588F2CAB253BC78041EF75CF0D1479FE381D360BAAA4DCFC1F89F2709FAFAB152141F07617B743463B4CFA112D4E250C0AC07454FBD796C698E042BC3FFD355662C16F55BB5EE265C7DCB016D2F377AF03BB50196B40111AFA8396D20F12136F45B758697303540D6DEEE5A81E0C88502BDE805DE075C73BA21E6939D3FF4957D3C76912F931C84D2E06F8547789A6CD58F8A901AAD3207CCD1143DF7BE3193339A7903DD4178762D2D50DFE3BB57926A1BBD6B7E64F2DE2EA014EB272FAA8B5A911DE3C5E885A5E1568016799641FE5EFF7D592FEDEA1D94B0BEE49F4757556423BBBC1863AAB3085B4BBCF8206A07B56543BF073F0F6873AFBA77DC152EB147EBBD9A46EE0F728B7BD93FD7748549064070D09F05BC50E0CE5927B32959C0AD2DB673CC8B64CBEE624958047A752CAD3D1116777D90AD51276D59DF5944A41FADF3DD4A97C569FB11184F72F0AFC07505EA1BF465F03769CC75841327DD6864C091A2E2C8415EE6B7DADFB1BF8E2DC2C25A019A54084FE2BF01CF2935C548DAF0C4F8A31A5B14A89F37937EC287F3035C46D92DF48039489D3B1293E823417AA8687D2BBE41D14EAAEE2D0742D6F87C534130950F81A04A8A3B42B3B26266B30A7C0276F4739110B9D88FAC9DBC5FE85122E0BFD74653F099F000887373550FC8138F1B6D1369BADAA8861BE8958060BCF2C65788B4BB68AB11DEFBBFC543F2608F0A16D82FD97BD55B06BDE0E17F05C1009607A2734A396BB8CBD718356B3EFBEB1F1586D1606AB3B2701E4B77800C33673C54CF9DCAFE215DFABD53B13879BA663DFB443A717C610671A6F2D65A319BAA06D472472C6F71520888651E33DDB9A72242E23C81933E6CBF951C8FD61942FCA23D7E464D24DB365874AAD627A8CE684FF0B73772A542047C5A8DB9B9B077075707C602384DA8A035092877A27F16774BCF4533B8423CDC7EDDBBE7A27E926031871BD2293CD46109CC9C0CC7E18F06F802BE20FAA35A170D547B864AC931DAE50EA4FDB0C24BFBE2B3E720A66EB5F6EFF5009D69B353FBA489F18835ECC43E3FC2863103513D8986EAC34B31E8BE31CC2BAA2962905988BC0E20BB1D9BF98B82A66544B0FF175B296356BA17217A5D91EC5E38839BB7A3FB575F71290E11D9E42C28B7C63A1E3491C7651D3ECC52539BA21D824FBA6A22A548B91335CA607A630A16F234330F4FF75061B6C9FE4C2E131F4065A0E9BC8BF4967CA4C0238D3CE38291EABC4085198EDE4426AE3FEF38A3A2C70448898C800E726A9BE870263935B6C71998E83801AFA13FA2DDC9760155EF0F960C206E495B78B1411361B98992D7CCAB9623BCF6FCBFA1A5ABB8CAEAB0B25DFC2CF9CE04A0FADC24CFE1EEFB752B287B1DA6BD820C0AEB2CCD414FE618547D3DFDD58E53E6DC4A6E7A1955BD6E451B52616DB150A75EF13808C3BF9D9069FF6DBC76290AE755E97F2B7F3465719495AED6CCEBDBB2B4030010AB1BD9F74C4A216504CDDE4C97B2349822E25C25DE270BBDEF0DEB901F25C8914FBD5919CADCE790537C53749FEE474B6D099CE7AD3B36F748D336892B11AD2F4A9B9173126E805B23D6132D75E9FD4FF9E3913F74FB4C88F8133F9B20E20E239D083F90EA9DF7B599F14DBBF454A5F3A49BEC62149E50772126DBD038D5E6E52AFCF5E11313E33FEBE953500ECB77FBAA17ED2E9F1348A282F7671BC4D285C4099D46DC0CA702A2169102479EB4D291C25C47D997DBBF76DFE7C5C20DD9A4010221579CAC03E837AD9187A0D46D9BF4BF41D2FEE16F49F6F64F428817567A6311F6334A43BE921CD833FE854F901CDBFAD5A5D6908508F6E46C3F65B436A8AD3FF8931390C5BAD82CD274BBB1085064FA1C1F6CDD0EBFCC3E46AE16006A08A48F6BA27794C89B68350A8409F81402237871674695A0512D33BE49A2344B0B2A1B7833775F29E501B88DF27F4ABB2AAF39D114B158DEF012185B4793B3523E839CB24DC605A0F28F21C4C9195722AEA7EE5EADBC41A18C6295E5A3D18F357A3EBC2C5DA8770EADF723DB6166654EFCD0357BF892ED0CA10F8845F6BF8E5EA04AABA6C721187C9E360AFDB868571F9AD5EEB6E50C154EC3399F5CE2E9FF639F08785E39EE7FE92BFCA0E4D4FCEDD46F4CA5FEFD313FAF02DFDE5414E70797553A8CAB1A80FD6572C22C5F133B4FBC172F1E9721BBE70D8667AD968F31D62DBD4B8AC2A49FDA622B1E74B7EA8188093AEDE307F3FEF35507D8D72738152B26C859DD6B0D27A88929AE340471710718D635787E5A67A53AB1C6463E9A8BBA220BDA69D59F25F04A2D670BBBD95B99BB10B393043ED5BF97344E71D31086C75CC3F82F6AE373440FBB56EFFC39E07D9423F003F76BF36F8145A66F4C9FCF79CFDF5930019B26D413BC6ECA59371ED9DFEC86D92C7C364327AC934FABE4A73B361340B423729B2FE5ED24CB5F8B97B55912944FB5BF5B8308FCA7F3077DC61CDD3BDBD603AC14C837F91CFD50F95EE0F25757CB8CCC49F72897A9B90C1B93137D79EA75813440C6591F909B3796EFDDB1AC209675A7028F31404B3C4D57A23BA3C0B71C19DFBFF189083C0CF0ED48EE89DF5BA1F9D9BA39B6C813D4B6CF94835C7B17D9B7031DDF921E9FA2D8CA9D91BED4C0202805993D41DA0102650994D6D818DF2A56E983E903F29BF9423F1190CE0B181808F05A2D2975AB73D49A61A8F7757AFEBD48948766C5EEB176B917342598A5EF51AE3BA1BBB908903A308B6E138249C7C68E788D3AE44A07589D3FE4AA09F1B2166698E4FD1F213DDBE35D38306A5A72A6CE416DBB1888CD0B0C58C3B8878EF04E1B12E0969A7EB01000D51AFF1B962722EC3D0B976ECFBE2E885006622FD6D4A6F28C4DC6D69FDC0B1BA28B285DC1E3D6338F33FC41881E378D9019A894CC6F2AA13D65D4028C988E5D8E76C5A3F390FE8C943043AF1CF59238DE9D24617EA2512A018DDB523428049D63E524E9CEF36D5E57A8F94DB5214C919E70078D8AAA157CB62C571DDB73686480329A20B4A673C9D955AB7A61F376D143316B99221B8DC06F20A8D721508EB2904E45BC69B7D0C93B9923B66B0BD5C785A873901BC1BBDB5EB487381905427A99A9EEDC5627079CCAD1C0F12BE9B73B953A915D82E6962F62C8955203E3CF5B14BD6581716C61ADB4082F876B8B9BD9C8BFF942F0D9CACD9EF57A1E71F6AF24068CCA3D0A36C77AB63A284D7E80231B7E10FEB2DBD37D1B2823767F1D563093A20092AB1E8FF9697CA7564A6F3189B2FC23AF4580EF4673625217BE44668458F4FD0B021D54C6B577A1E55B2B2CABAD55B138536199E6582BF6705CDD7E424E702553E0F72DD3E3EC5D358F75F24CBADF1425BFAEEC8932226E36284E26AAD2A7086B586D19535CC8F8E7D22C2B9FAE71EFB1D6F3795F09C6FAFA3CAFA2D8E4A8621DF65165081C6A1C1544DF2E4AC9629EB9AF15EF28286F49CA95C56150657A286FAAA5CCE15BAD2869D5D0491D36B411F0A38A8D82AF231897EAC0E1B3014C2AF9D1B999F0E49E94E6884AF0030D5CF6656A9B4E7E5CABB602EB4360A1A46E7381EC5F0DE56704FCD15E873C12E67F2B77B149D37031CFEC568939B9FB299D0F1981E6341284F742400E1A936C3558FD9643D7B22121EB06484B92522E0486BCDECBFD52E1FC035413F4449A9FDF339396F80C25D0B5E6874CD8A09335EEB1C826A61DA4FF9E7F13E112B12FE82473B461F41CA8F32E35DCABBD3B5FD164820D271C891500CB8603A6BA0DF34D28422A8CE143D715B5CAECA85CA2A705E517601D577020E98893BB108B656411E14326D917D76D9831046EE8C3CC0C829DA03F3BBD6A5EF2DD66822EA76B018E00E83A8C3298901FE8972AA9850E79E62163E7CCFDFA1DC68114CD15C0F1B2CACFA35895FA2568075D8336DD1465838018D55F64148FDA6517BE0D9C3E9803F940869D7AD84F1B27DF8AE6B718C9E66ABD760A17B54DE2BEF5A25DA993A7AADFA10BD5ED7D5FE7806D8E6F7FF5CFFF226238884A87B7851E2EBE3C454A8D46342BE1CADEA0A3B05E5C07046DF6F7261ED831D673C9BA941E3BD6AC47FA7F05B158291B39C4B1DC782D98738A4D03AF3E4284CCDF904B5A32CFC0381E54F46D6D4E860EDFF1479985D3B2A66843F1BB07CF6F646AC7675E7E2A0D9961562AE99F9251AD66937F18B669871524B72473FA5368770F2AD811485AABADADCD205CF80B526543A82540C3E7570105C49DD130C9B8BB7C4F10949430F1E19FDC957D8205A989249CE3201BC916959DE01D2C27523C64C0886D20FC5A0E97C141DD1A44A76BF8D2FC92AD25C916FD91322610D59F29BFAF8DC8144A984EBA131DF584F149069E5178548631EAE2F4C6643AFB9E21DD0E5E6DF44937CA667EC916037EE358F7D0FD9787D1CA87EA3DB17C883AEA9812BBE7CEE8FD76A6AE14DEDFC608F45FA191701716AEC26432B9C260B3F897275E1BC997D9726AAA24F5337E8BD6864618C02BDAC3A33A90F821F7D360759418D03386697655CD9958BF4173929C0D2A81B656869B374C65703445B0F891BA6446A62D902B4F248FA3A4F3B9155A1F46CD45AB32B3F6FED88B41202EF948CF8B28DB9050E7238519A1A42654E1A9C700CBAA49311DCBD44E11FC23C81615871C7973E083F4BB206C033030813E467A0B7CB309081F32DD1C83E9E078E3A5CF06C7B5253A08E38F9B94B10F79C95BB64A9402BDF21EAAF8624976170B9D0422B55C6FEDA5FC0193F2E94B470035C2C9EC95BB306922FE9ABADFBC3F87A5DB49FFA4384ABAC6530D47CAADA896FED3FBB91402810EE018E62BA1A831986CDE59394BA6BE9EF6A1414B068A7772D5C425FAE3233BB5478FB41505ECA49672E94F25E59E8D3CE16DB2C835D2A8FA3735AA4BE4C018AD1FD63CF161ECD37E0870152CEFA3FD19D81A1E70E86706BAD04F35338DF2C3135B8AA8EE7586DDB11CCABB1CCFAAAD5E89D7B5119A1CEECE29ADEEF89B5B5BE498E6A22B1C22C1B8CF3F8CAC0CE7DFB8A675CE7B529E2BDDDD11632CC0ED6ACEFB82198B64B36B05CE0AD7C2EF3C501C6F2C3C2E41068543F14ACD6577F850EC22ADCFFDB8CAB9130E5A107263798B7B62BF1C1DE66530FB999289E26521F4887EF6A6D0DF560F7371E9E49C24CF7A3001B24856F4259A1D0774C5D202A2EC92F46661FC017B7DC0F8577BC1F417FD8058F78639BAB4DB52E5A9378202FB5748F258D8E0F0C3602E9038A28DABEFB252917C184B9B451B417C30F1639142387886C38799D232BFD1838763E28E996FC1A60319117E2671E50447B280D258C3521CE7C1E0A581D8B346CA2B0886994B8824F044AD1075FDE7BD90E772794BD687C720E7DD52FADC89B322691AB6ECDE3C4B5E57727B9B11BC655D45C8CE945736F0AC132627209BB8BE5CC895E792334CD2B976BAC912FC021203DEE7DDF9922E42E2823BBEF92B1D35BA88CD67558A6E28D348FAE24F698A35FA0FFC382463994D8C74767B93F24DD318C54DE01F7FFAC68F4BD0F6654F75467AA6E737A794AE3EE3FF5E0F1BF328FCAED275CF6AA05AF17C5D7FF0EDA5BB00634416A693C963832714EB4A6DF1277ECCA23C8E988114F31EA166417188BEE48815DE3CD19C9702611A3781F00DBC59D3C9F14467A0F1F24C2D4F3EF8E00F54D4E347CC9D918C392D72075DEF691EEEEE1792A3B047C159D986890E02B8213604FCB558A1EC19C250AB4AF887972B6034DFDD4D80FA97B57B12F5332A19AB7ABBBE245DFDE7B349FBF36BABA0B1E016D5202EB1EF125794A668E6DFDD3DC04D952D5473EC4B7000B584AF71426E1C6CB264DE0DF1E75873A315ECCF94264F56534A567CF15A2A38554A83BAD842ACC735901E15B75B51E851FA6A4B7992084F7790DDD3DEEDB4818DF80C6CEC1DCBAA3AD77E5ED336F5996E881F07B4BD68FD5D027F6A7D62D0D24E7D91796D15590096855F9DD7F3B08278A56416625BF14BF149105CFCD40244B114742F7B24CC15A50423DA48B72B33939F8C39E0B43D566FAE15EE39D1A45BCEE69146ED442F45AE76E4CF0D59A6D167A7646FB8FFE57DAFD0AFBB0DF34F6D8C0D8385F6EAAFBFBB90857D2D231E3131F298162FAAD423A830E2790D15314A529618D3D84BBF3CB35E461D1978053A81247BA5CDBD1A06DBA16E2540E63D83880A2B57D1696A45B95C78BB876688560E0F1E97D9DAF88C25B95808B0E616D605B22AEB7568DEB14B83BB0180D8C4A2DE642A63917A5EE6E08851E732AB538E1A738EC66A271F7188F349743EF6DCA9F2271218C1A08E2C0988BB5AB72DCA7D795B941C4BF1D61F6EB6155FFDC6113900F6AEFFC03A0E800169F8BE687ACCB31510E44172A67EE5A682322429244DAD69BA2920522C54661B59996281F6C6D574CA65CB36623F1AFE834ADDC957519708AE2EEA8D44E761A3320C5EDACF594C122E6E494AB97E964FF4279D23342030DE99BC3E7BA415341855AD09932C00C28F20CA1E2BB9DBCFA107BEE3A6BB7FA374530D673A03FAC6A231CC752526FFFF25282CA8CF439CE627D73655B54702215B0B6190E7F78026A831FD10B79C2712600902055B8D04724E7243EE7DC6FAC0B6E37B7F5BF0FD39C7AFEFAA6C23D2E0FB91D0C92FE49D3421F72E4658CA068AAF60782E4CE6315616E54E899810DBDEBBE970466E99D59B5D7609AB90F5088177964B899F60775149147650D7A4A2D100A8169C3F99955DA760E3414D6424A7BA3ADEF7EA56FE080B8C193840D1C870B943B268046D2DFFDB6F59AB9F9A091B77DC9C645F0B1BD4DEC4044460D964A593F2E369E12CB267E7F6660EE7FD8039014F6376D2B5AF820AD34541E4FA3F31BDA8056ADDF596D67F10CC46FA48DE013079620CEEB6A030A36F23CF845081C00C7D8E40FE13ED870C1A0D39D4946621F3F38F9528732891BB9D2D8ECB2B605FD90AACECBB14135AA83DC04BF76B04183A8B98DDB8D70E48A2C43F7B8C1D34CB8F28C8B473B804A6BF1BD0019A3231A7DA12D4E1541EB582562D943B2C48997D95EB37EF817C8AC336421C1263AA45BB95E18ADA3225B63FEE678963B94C228E283C1F367ACAF4DBF4FDA56515C22DA61D5E9DE620F1B9BC0B2B1F0F94EB7EEF60D1BB3F1BEAB79E638004FBDF21FF77115ECE7EA0DEC68944FCE74A7F7D87B12C5D830F51512102CEEBE336DAD9C730C22A7504E7683CC2A3BAD9F45AC759EAD47A8AF00A7D45222EE6B6713F7B0A6873A4A05ED7F6870B37EC87273A98D9D5332FFBCEE8EEFF5679FA36D2565BA97EA4D85E5692925415CE5C8F230593ED5BF37B79F9FE3482EA411CF272BA3783853576DB6525EEA16951A600C40E972C0C1037023938F8DDC972BE280FE494E0198BA0AB5C779D8147E9FE858B64AC52C6D0C54B9356EA97099CEDDDA0155FEF930BCC7B194C87ACBFBDEE57CBD23379DB73259C8F0106EEE62237510A790C1807CC1A0C6A618A632CCAC931CE696926BA9FD81C52EFDBCC4CB9D4FAC1D607837A52E2F38096473558F5F693A80B54111F611D88A7C754826218F86CB04D2BF3BF207BEDC415AF2A78F5706E42540B134B7353AD08F65A20C498547A3853145045429A06EC7AC65B68E579166020C059612EA973A992A934E6DE672C18B20BC0A49D7A001C1F1A53967A4B264B3B8CB16E42D072317047942DD7BBEB64BD45A2A64E7EF9F6D9CD0814D86A635F80736D4E10C12260C9B9E842666802A5149BDF7E607719A20008F08684EA85529EC640F075CE927E84F2FFA50896E8713BED7835D0C5DCC50D7920447306B827BF654B1FD56BC0B55767971C0F65DDF6E230367FCCFC1DC642162E958B397AC19B93ADD3A87132EB41B5F4713BFB2F076D471E00DB2A877F800AEB27AC9D8693759C27567AE240A856B5A76585CED3019BF8D6E94AC75395E56F27AE1C89C655DF677CED7AA535F6E7C8667221CE040E03CF4BACDD747F83D7E8230C4F0FEF1B726AF300374B00A3C8F8B12984289EC2E68CC007FC8CF6803688315285D80BC4F745E62D3B81D3578D7E55B71696D9F90DA19039BE662A5D7ACC0779BFC1B0EA561A79BBBD90A8BA8FF3059440259EB781C75471E653AA3987E1D75FB80EDEC67911563C37A853CBEF039071538D7ED74F643F4B4268E71BA37456D98041F0557268000CB82192FD046CE4316941A5FF7444A5E58AF67B2F088AC113AC66B5BE09A7E7D2387624BEA28CC77F30003B1A24CD27B44A7E8C8031BC579A83CDC485AAEACF71DEB536ADC388C03F4B443D6828CB9D26E5C1ECDA81F6B505F6791A594522EB9A6CE457846965CD8CBA309CE1F45A229CCAFFB67D2B0AAA948404B18703E1ED8E56E9B61102667ED53FDAD4CB75566D874E8AD7B2A7B1D5B701551DB717589CA0A16749E9674214F84BA9E2CFEBCA2570F5B558B7239EC22B6C5763C4E074A8F46E00A3341700C79538F6E2695E1610E2452DE07F9F6D49CB34167B069675CA30B92DB6C3C576FCED30245D271CF6DDA75F2A69B5D1BECC4AB1607B6779B08B4A5C8E0355C93FB28E9980B4EC5730CBE152CAFB5A098156D616E9F4A051E1E84FCA4794D0B85E760F6E146C1383CBA715BA3888BAF0FB542AAA54165D9CF9D0A40E22185962C533A4B0617DD2C4801C790EF46BD9F739E36D83EB1501566DD7467AB23CA0B9A031B6AD48611084166393BAB44071EC74CE3F6124B3895210178FEA852D499570D024B7AA28C319B3835F208F83AC1951748544DAF7E2D801F5878B323AE3EECFBCBCDAF73370959E17F0C8A728D8AC900C6835B72F524652F558B95A19226618711A39925B33FA2E23ABFF9B691B0BCACFE86B75613084A1A96CE6D8927C9919242DEDEA970DD74595D709C3FA504CF8A3A8BF6A2594CC261A68C06CA084480EC20D9771C273A4F8F1949031AFFAB22FBE12818ADDF8EBB57F452D710D8D8DDD441193ADFB9C6E9298617D227F7235AB6FB80FC74C436E63AD715195B68B716C058E0F7F59F2AFB4F7E0B195D49895A2E0D311EB83D40E199EFC8C895B5A439C9C5A019F1ED1F37E1DA9C3CCE7611B7DDACA5BCCC2413B51DF94FC251E7AD3D9A74696142B7889BB1F14D10006A8B291E36483856AF8A80252FF1B5BED5479BC8AA7A658AD60D7F4643EC651232AFEC7A7CE94259EC513A1CEE9538BE7E1280867D8BEB61B34DB8930475ED47F39B9638906BECDB2E82553A048AFF1DEAA5E4D955D6D0D40FEDCC9FFF580842B00FB823B82F15E57409011610814AF2BF4CF69D5527F99AC1435CA28EFB79D1A1039396E45B46EB507690D889A42F165121CFB9457BAA175D7DA853DF6032596279BB92DAAD07E97241A514FBE1382756727AA99C648C77E4089231B3EA36CD8C469BD35DB4914466408CE9F21BDE34EC23E6768F36572370CDE29F86740BD45B9233703732986ABA686156610B1D539E1A28FC42F894A2075925481DC8971000C53C4A7DECB79FA27DB85820AF9D27FC50BEA10E7261B828567B325872B961CA940BC8A9577718B17846137385F5451BB151E06FBED139A5AEDC94A6E39E6AEC4554C10473DCA75FE5DACB31FA75D750AF5D316798120DF7C122ED357FD51F6956BE7FE14323B1AC5F993C98C2D67002B472B393A73CFF29673B4A8507E145A4F25276B71E4EE252D76FFE428580F03FB4E8C6FCD9EE0D59C6B2A1D0A033EFC19300EDA5E86A34666A25A3BBC5CE09C11A15008BBC402620EE69FD6B6185BB3923CDEFA79B5EE839BD3A303C89F69078BF9B375E9B29585F7E9E93B28DE53D066335DE12E4F9549FEF6212110F88B5D97544090A7F2A673EA22AC6DBDACA589DC00916780838790EE91FBCE17A2D25649E39E15FE5F31FFFDF75B6C477EE133DB575146E610777331179A9F65D7844BEBE30286C3550DE93857A9E45D57789B92307197E361DF3F8C532856E24B2EDFFDE552E78CF80FD5FE0C431D9BF22EB531137C390A374742E9CC701986FFAA29CB291D03F631F813C6A68176FF315FFD80CFF0C399D1B441FEC8950FF3A11BDEE0BE28B7C2367FB4CC768B4BDC74ACFB23441B7F0680A292A73B8DABF69733EC9BD9BE7DF25B7E55BAECE406467A55E3F57533D1BEE093CE4717E4D6094DA4190A2AC2C19B45F7FFB081A61BEFCCEBF0B22C0BC50D42C92D87A9B1EDA17A943AE811DDEFA4E74EB1A21DE73E90A75B53F1BFE8A4B1F2BAC73F60DF799A9265D6AFE35EB8E12C34DC5FDFA0C441FD9AAB610E57C1815DDE15A9493AB76160C29579D69A72D85FC3DA3FA1E48A60E6B33035BE27C73C190B000EC953C56DD9BD173E3939AC84ED17F1264B7E25AF5BDB42B25926F3D196197A6225E924A32B282E7DC2CA89B3774774D9DC4F2A4EE138D1E1281FACCAB63DA5BB8C034D0B96FC7F4CD640303EB7963DA464449A7489E2672EF64359C40FF1A6FA897CE72CFEA37DB0B178E0675CE034460269E9CEA69D2660C41125AC19DFC76CA1E607B5130782A860A4662E0D3748A2AA02B9210FCC91EB74FD55574193B9F270C52F6B5360BBC2AE48DC0631972938ADC0580B2612129E61E00FF7CB325CFE4C3D704FB93DAD7F21CD40841E01CCFF9D26255286479E6E98E93944AE002240D4D33635B7234ACC13AA2C5DDC30676328D16774DA5DFF2A0BE49F3B1E4BA69610E1BD7ED1E1A49E91B06F7063A7D349F2F76A8363DAE51BC3FA1BE9AAADD0BEE83307333FCE09033FFE7FFEA542005AD7229C0EBB1BE5557CCAA19CA548640CCC350C2806B8C6924FF9FA398A5BC7C66396635B7D89165ECCD5238271574F0C9E0BFFC623B6B7B67D53AEB934037F08C1B38345062B48ACE53A97D55E50E9D0A617559477629AE09F510C20F11E0932D1989F2C7E06394988042CD7EA01C0F7749A509C3C370741677CCEAFC6EDE68814BE4E0301AF3C8383CAB65DA3DC17E6794ABC4EA67DD481EAC0D320375D2087B18417078A9DA184FA960E6E38A6FE6EFB11A4516EF33EF2A5260F5EF2CBEB171AF902F6648560ACF32A038F03C4D6D1DE235630B606614E0A1320F35A1D30CCE6EAF7AAA21CAD4FA5FA381CC7CE290DE695EC38B1F8EA9240CDA10F4EB1BCFCAF7F268626718D905896104D16415758E3B33085F02E20CEF9DAF1DB697473E6AA56C3E93683C287F00FE6A4806F20554547611CD54CDF96AF702565E4856BC7923FF9036C836CC07876793F707BF51847BFDD22D46E5AD5F7854E37B0994F7981150468008A078C25173BF35ACFE5D89BF11657C15FCA03D53C56CF35BB49B9FACD39AD4012E06E9EA9C02F5F5D9B215BC29A1F66001F2093B3C2180C0F5A44BB8FC1E0D96C5F6C0B10BFDCB7115F19ED233B5C4828D9294F6FEA1A507237C5B153198E3139A9CD0F6B7851A366C1BBC7C070D1A449803D0418A0D86752A1FD25D79A6FF0B2D6A7CEC6E92143322B64FF442E5F1B49FEB2B257EA406BD06AC33AAD89ACF4DA8A76E3B29D1D9D16B9F571524FB7CCE608170B07B2C641B3DD17B6FE3104840D8E6057A4E6E4F0503593880E284BDB02C808681B347F91EC14AE075768F917AEBB5BBFED5AEF7F3B2027447C831F0D839C6B7598E9C38E951C95C90588F31C18807B07D3298D66549EFA3E555A89CC1558F0EEFC065211834B11CDBB9F8894AF15BCC041190F3992819BE74BD02CA9C6A4E5F40E3DF7D74B4A3CEE3FF86538F754A24B962E368AE492437419E37944B422280048AEE750E70311708426001F9288D0BD70C36EF2B14A28C6FA701E6410A7C20D5FDD65ED1B18EE26A5E2C3317E0A47D1B4FC47006B7449C58510D7EBAEF16733D501AB86645BCBEA5BB2D966519503CAFEF9C1E40F91BBF1B39F78AE0FCA8D73CF78E94764F759122B4DD04C5FE9DA3D6E049D76D67145F60D6D845ACA2EFC8D25166C69D6C6CDA61D8020D3C2E66A6BD31EAC0F51212566705D66FBB3116AE6AE19B5247FF41D33D3027EB29B86E3A201951BFC3E61D501BF6C4FCE727E20FCF8A378060961DCD18587E566A315633A52580A3556129CC801F07FE7AF06E5B2FD0D4894F2F316BFF0408F48A255C08CCB42C7D569433E0029112D8551338522EB6AA5AE970C73E258F31D79CEDA8706121C2AA7264F57C026F624EF6A5C983195017793D7E71B4C7A9A714CE863E5D766F0C81AB3446A4CAC3D534958B5208F84B2F8B683B472043A217942DA2989B89F54BD11B5967CE7014A8943BA20D7796B6BF1CD18660978ADB50B563AB9472735045BCC477E015F85C0230A4635C974A58BEEA799B82518575AED6B20EA35D0F56B55BFFB908E099C37B037EF4732963B861DFA2DFB83CAC54C744777A450C13B65F14EDBD3AA54D01857C68CB8F01EBF0EAE09382CD42E4E4040031156A873C341DB204D24294957673E05762463D87E293FFBC35E624FA1E0347DFE2C1C4F2EC0C8E975FB1347794E59E6CF2DC3E7B25D6A62D5FA6C53854684241B5DBF6EDCC10833ADBEFAC1276B0887D79C4CF0097BAE990A7698C8AA4DE4DFC6F00574E3811D8F358A34E8DE83EC474C6E801DA61FA5DA180FEFA7739FB3408DFDBE71FEC39FD13E002878FDBC60200FB5EA3AFEDDD58CF4DFBDC7B35C4B5FF527D5466E7CDD6D81C8A72B7C628D5480832616A87877205C6C24A82FE6D7580C9F52DE72676035A6675BC20C04381E100C3347871A70CA2938B7D027B8D4A7614985A6964A99D631EF0228E89FCEBE0188108BC6D6DA67CED038E8F658009F185E5F63D0F8AE7F15B34A93858F03485DDE2EA8D31A339F215E830CDB136CD6DE3DCE726C31AFDEBDD7BB6D0BDF6F858E8AF0724C252C06639346C7999E12301573233C361CF4E590EB947AF8AC195D79C0AE8F2DF3A4CA806DBD18FD33277FFA920111E42D1D3F5EE0568306D0D7A7DB01D49C8F723EAB74A2E58D0475F7B110B24E0831914A2DD5E0B521A015368B86294995B9EE9CA772817C5839DF23B16042D04336B0168101CB4F3F9B36F8CC99AD74A4ED5114DA481DE51720C7E35A1DE51AE125C4BBC8A13EBB98A28306C5D1B0D3DFDF1A7696C0DCF5D4A9FB556A9C8EC618E74224DF6AF5C36AA1B9E4429923091735AE68D19794C1154252CF06C2A437C5BBB54DB7CCFEA3BAD44B49054B87539AC005CFDAFB762BC74DAB1CAA7244AAF920B6C6BB42860DC7CA68F590C37C2A678FC65B40496DDCDA61CB49DD636DC338509028E6DA60A530C3E24EEE8F09D34A517CA6E15522F8A885E68888C4312E0E7B0E17046AF2527432882CB30B6DD537550586A0B168164C3B8F241D7333BC6FF29E235AAC7C505EC1DEAE24C3823BA2BF07B8BE5CD67730F4FC98443E32FE6B205850953BA59231FBC9408271DB3CF47857196FEDD3336A975FD094E1C6D2D51ABE5F0E5783807E01B1D32F004CAB4BEBEEF2EA35D3FB772452EC01E6C5BD8A684A17B33BA00D47BB36949F13EC822CCFCE167CF99848ABE1760187D3838BFFEC835901ECDFC905E8EC3427FE9A24513E0BCD2560FDB7C32412CD97EF65A667329A50B0011A2CF0AB5FAD5E2679B28231999D2E29F57197B6D32FC74DEBAD09E365B3A2CE78A9E3A9BEBF9044C29D5DE4E727D0190E83208AB1D9ADAAE0815D2194FDC08EB39788BB0A8E7EA5F778C5391FD368B7CC0AF554704025CDD59764D7622E4C8356AE477E0088488A5C44D1B5075662BB1F85A2684B49808A3099F457313CD03344FBF3B92861A22CC52C5073BB13A12D4E0740C60BB941B738E977EABEBF94C30AD8552833037926EC9662D4CFAB0256B9F7893B0E898D3513967200656EA6688B772031DC86C9CC4FA3B3627226AFD4130C8FFF98CA52E617155A4B93D4E860DEEEF416522D08B2F789906F4DD317B570A83EDF10C4B74B03393409476A29B2FD38DB9203F6FCF2CA2F8B3DD6795D57F7EFFC6B3FF7B4A9CF3576524EACAF951C53B518B2BF1357286C22A88FE6CA47DB4612B29D937515FD2B408A4236E9CC7F393F85070E28C4D9DF4D75313C1BF8D598A562D521E771ABEAEBAEAB29106B2FACA90DA05CACE59A13771B8F25D8D6633C28B5688A622E7149AEB7F84F3553AB45901E6033E005120468E981D1517491EE8FD4505B96A6160BE6827B960AF32E2351FC2DF5B013F2829768AA68538D51201ABDE34539D5B260131121F91EB2B98ABD9FF17BBEA0695AFB6AB1A8F52B51BC0173AEAF9E5770D40443852C737587B8673829EB2196BCC304984B66417AE0567C16250D7BD4214B42221CD11EE9ABDF6BFA7F67F2BAEE9FB8F662347D7EB3917E7C8A0FF1069F0190914E4208907CEC2706A6543ACF77D23AFC529115D46302CB313C44E1E5AE27197E988B2E3E291DE0210F55B60A9ECD6A1587386FA257B94346AF7D718A8A63F684B7B1BAA34BE3DF4D5486DE7099238584EF31056B765607A6C1152E688B16D9591D8107ECF25DAE071E83753DB4106E2D39DE3E3BABD3831CB71705218D67FF8F34932D64A55FD4C73490C57F295744502EB1B318D9104BBEBA34269395D86013953F03ABD89A0094C32B68720649671BF470465DA5EE56A4407DDEB23391EFC395FE5DBD5D759ECEC505834F57FF93F2664458354487EBEBA662E3EF485C28AED2D12AF75659E1926E6F31527E5DDEFCB3DAF78907229295F3F0855ACA0EFA88758317B883C2BBDE247461557BE2DF5C56A91F8AC34FE21FA17A4D6B22ECEE501DCE522681D4143AD4A86D916F9FDA8156A560EC1AB61974FF38C8D46DEC1DCCA4861E6E8BAAE92B0AC27F96765223C2A32AFEAA0BD073011166D44C5FFC7AD04F2D50890786877A19B88748086180FE1633C2D2E95CC12EB665B73C1639EB261818B3F0C06A76B5E51B18DAC5A5CE656120F2DF88F47D47C426ABC4746F70ABAE9597D0A504EAB12BADD7FF65DF01F3936C26448EE6457A66A6E73872973CC139CF673DD2A8A60EF4821724A9F6C91AB2504DC096AC368326D1DE07602153A00515C9D3052FE1AD5D91850B952969E16E9575A134F83C2B52B652E614D7F77765EB6B8E903D50DABE22FF223E4F0605639589E9C1D796FA94E39CE8D53AD1CB2356D9D1A1391371DCE1F6F80636B41A4256755730702337D018AB268C2C9F8AB5E864676954753E833325B5529E95ED016EE2A05DDC128A9B5030DAF373C7DCDE5E1538BA6C6D236AE59CD59D31B3534AA6DBFFDE21AF8B9602FD3F2FEBA31550EA9F4BFFE98DC1AC2D120830C88CB2F893005DD7E446CFF7B5EAC8B696366A94D50D8190C4EDD44AC94B5AA5ABCF4E8F6FB21D24D7611664C42D92988405C99D1D553115C2746BEAE71896D1E2625CEF840DEE64DB3A5B0D199569B0A3841CC8BBB7F3478FFB4C6683483C9EDEAD2A250066571DCE46446C6B1C53385A92D473EDD3D8C8938087EF6D07FDB7340AC3B6C9E45CDED17A882896E8E42D12E1E9324E90CC801E197391FE6AA7921DF62A1D74B7A00EF09BFCF7E1DA607EFDAE3297F0F9DDA22D618177636F2E61CE11C206577B5E97AA301EF3E9188FD24C83A5EBF0D774BC2DE770FE4A1BF00AD17B4498B4B53F754CFB4D78DCAE942AD92FA84D36036EA089E10CED758A4C48447B3773FE1077E18D302C44C9502B7A61817BE55AEA1043BF230A357F4FA3B9C0D9A8B13670F4020EBCA387EB77E3DBB42352F061BC05E218E34FC49F64710C88378441F8FC63BF2F62EEB9F28F5994370F54B2D4835583237A32AE477CFD2459A6CD2440F3000E84E8434878E9F580880FDBECDBFB1F75794B187F0B3D5832851CE012CA2024E34F69E5F320056D935EBF5F0C5597A9B621E3FD7B57EAA88C15051EFD6687D45D0762B067DE8F359270321774A9521C55DAC74C1057D010DA9C2298832257132343953D1527A8722253967668D2F6D3D2D6E0467588152042207C791FCF314AFA09E656B51CD5DEA72E2AE92837875C148822026F9A9050616DFD47C768C029C5FD4AC84B55F7CF1EBDE770DB234BD72EF8C81087D3CF560EEED9D4D4AE14AA9EA3757DA5932B5913C51EC3229B22A9A4E76D4F14968E3A2640433928C5A8B771B89666AF0D370AEEBEDA470CBF3F1A3D90573AB576728058F91BD1C0719A3CEC3B8CC1C230489CAC6737B4B26CA70080A1D5D58F56FE72D364E716D2DD129A624C8F9708BB987F25BCAA8AAAA37389BE1BCCCF5C238C677023C2717E3979B94FBCCF2387598B4AE4759D0917FA8BD1D024F50D93446C8EE8321EDA7AA22DECD6C0E435CBA7BEA00B12B2FF933535C06566D1A77436BF73B8D4E541B0C16526F8480FEFB36421E6E8166CDD329051AE2B17687BB0282003971B3A6ED6F25E36795473DAA4D2F5436942889AA25C9F78914F79279F6F7DAE2E23186A9403E44A19D55540A2852BCF0A4D8B3892530903D5FA0C7D02F70C0FC101162BA01636C629A9C7EA6D019846D71E9C7BE2901109BEC9182F6C5FDAA15AF0F9D7248FF4C93B8E3B7B26C22DC3952AEBF5E9A6445C9278E9D6133CDAB5F73D68681B9464AF05CE1127E0731668666F494C7E42D17724E6FA78217B4C54CE3D37B0062350D714F712D4D300695AD3361A1BE14AC753F131B6F35ED60C341DBCE731F6BD57730FE9D6AF6FD47AC614647BE9201903F35FDE5D674831C263B0DEC59A5545316EC5C4BF0659389B3DD6588B559B3A864B591BB4C4A82C5E4870EF72D6BC767D8273244069ED047B479A51BDA24D1E64886D232CA6130680040E4591FBE4150A2225C6F7BD5FB4E17F18339ACABDF30201C9FA2E59BD095CBA000CEF206520B0303F713EC944FA952E4DB3E30A399A41FD16061772100CCCEF357237B2BC034EBE4FD7E25A2E09F210BB3BF82CEC16A567AEF61789CC64B10D266AEAD04B2A67E59EC5C3BDC176E3B702E69C852AE6CDB3362D0D040024E99A471446DC81039515231F2BCED51F092EC3A5013E02A8B50C4B2B82C86EB3EC8B5C980E88FB83E1F1DDCB3DD2EEF2198E2D391A665187CE882F1DCA248F1AD2EC7D62D4F930D12E798E10C998EC5769532E7A13EB56CC13327C9C4981C165D8420545B932585548617998BFB16D3EB1D9F760871709641778409A6CFC4D7DDA8F92414B49DED04C6E0E6EC91904454C51BD89EEDD05A4B545316EBAC7DEA61930563D1ECCF40586A2F1AE797FCE8BDFF21AC373E88965E181391F005D0CC1A77EA15603891C6792C498D8D1ABA5E0F9B081CB7E024163669E03678BCB60B492BB8E5C8580696D7A8FF9803B1F341FA6DD93A7187731079FFDE8D032D0853D1EBB39B43AB5859F713FDB863FAFE3138C901F6BCCCAC2A2E6100CB3DBFB03FB5DE6FFC5C631029D4E2B991C7CBA2876A5597384C23090E5B2158F83C484A11F33F8086194FA93F81D744BD50DDF9AED457FEDC312180CBA061ED8040AD5A6AB82B6EB97688CDD85E4364034C22DB1DB9C21FD59CEB24F5EA6950BEC272040432178DEFCA3B1C48BBCBEC0B8B18E3F73175B5CCD58E4928C0698C846AA6D5FCFD7492B10064C234C88E1CDBB060D06BC3D130BD1107D19F3DC44DABD19F6AC31378E349806666CE2E1E44B74C5409A6E48112CA45AD6827F11E94D7A1BCC53878D91BA753487FCBC21E01A65E5FC50CC7A94C0A1EB038F04FFCE765A5EF15510318223D1D6C826F8ABCAAF074B4A0D61846212CE16AFB3E6464F862632FA65B39F0F41043335C1B80D7201E17591E37F4EFF2198072E1FD03F6273B7322F8C660B6418851C2909BAA401346A7DE3DC2EA144C9511FC380330547CBE95AB577BA92E6179FD3AD1A59C5014C0FE0CB7E8CD25EE288B6FEEB20C09EA99B37F03FAD4529F650A010CD46B97C0F29F99B0127B15FD673088CA1FB8FF491552D226F9BD2A3510482F36E6B6C4123F2891E387DD9537D69EF2711368F2C654C0F785F5DEE2CC95EC412CDEE48A413D4E384055A17808806FEFFC6528260E9C40B1916E3D7BEBF8A22209421D7FD961731FD71BC1E3ED56A4E4E81F0DF9123A309C8D7942AD43FA126E64764F16484BA56812EB49A8B912664027BDB8DDB9679380090039A07704A25C49F7D6B9962069D811FCBBF16E759DD30BC4CDD426999342E12EA2E81FEE51E56E67D696A4EAD4478B14ADF1CDECC83649B28B22C954B094EAC6ABA9DA36654DCE233F4BDE09AEA129D78CF695028661E9ABEEB5944FF01C40BE945D811EB73C6BF00693228F23159D3A2BC907143BB5DB2FB2F5A9BEAAEAFB513B61184B16F0D58EF6F77E122AB9F16C2E0487D01FBC998745575895FE11C408099A312B406720C34F266B1C7A47A28C5D6EB3A288B99C40726146C5917FCB80CB37BD9AFE5AB16B2A23BB64C17305A864CCA34E75803284F59869F98758A4189F12110293D7CDA5E126A04C4F4827BB7F0DD9E4F35C5E1590E44CD3731AF98BD5121140974662CC9A3D39AB74336B79F5F22513106DD970DA639F4771E5291432D58F2C6A37FE3EE2BAECDF392E863FE163BD187C696A8D75DAEDF10220A4F74E0071FFA5C4BEE5C9DECA65622B9FD16E48E0FF86521B084D3E3BB55A4429CC3B7D739E51A155DAE571D7A0DC66FCEF85AD1AFDEDA41CD94A213EC2FF246310D2A0A150AA9C0A15D00748EFE30240596426DE5C973978B6C50F43FF5082B57849DEB861489E82083B0441CC7689C6E7779E9F2189DE6B1BFA30A6D6F918986F3716E98923970783F2ED75ED47EDF3C9AFF771D0237E22E3F9002A9BABAA4CC360084185FBB9F710B2ED3B7AAE929FAB1734B7654B096BC2E64DCB3C4D3346B25F84702D457F076A2F30EAB33C286D912FB4D12620E11CA7A35D83922E3980BBD97FB3A5619E6682E6E301151CAC072CF08E04ED990C843ACF8B0FB489B6795338356122AEF2CA069EE781938A5057D518A8A248087F85E5533E6882FA3452F35561324CDBD7D78A17057654B7A35189A66E96423346EF2E19141BCE7449C6D60FE52CBA1E4BD201945A7D122908429129AD6796941BA4A12A5F3B857AE47C78B0B1D0808ED6DBDD749D54291680163299F61DA4BF5B91B3015C01713124BA63250A86AD30BC3FF19C75B37D8102837BD369FC1CFBA2D80AD3E0C0E3048C3935B6840F0A0B41461ECA988DA184DF9C680DCDDD0F0346A685B188B2ED943EDE6CFAE53BAB364A1C1A2D1E778CC8C7C981E297D47D6302005BAD51F7450D3DF18912C9D6937C6C26A739C805C63FCCAD72B78448019D8AB866C531046251B6702CE87CBD65CDD5F03AFB18656E36F63E32AE9CB67C2DBF66E42A9AA15C3E861640FCDB3B9BE82961D2CCE3359892F8313A36043A1B00B538801D648CEDB02F43D3CE684A75C4A188AF1348BD5F4443306B249705A16352683E44EA5EE41B1D95E2ADC7189B6D1F2CE2BA77ACA3B6C4465AFEE1D05935B145DCF8E13DCAE92B99CBB76F4CB7FDB838D4019FC411CA21C512DE6D85D9527FE39CBC154BE8D600D06C11A26B142F07761D89CB84C9B86F378B1437E34FB71B7E06A656833EC31195ED8C65C287875C67B286C35DD8D2CFDAAFDE5DB3719ADF4E5081E45172F2E422A8D6D222EEE2782D8C684FF92086B13A1A5239ACCA77E1FB162DD0C9236AE84821F8CEC30C32C0A153CC6590D779833CDFA20A8135AFF4474CF751EC18401BC69264E3CE04F22DCEDC4C0F8A060B89503D5A4187A1E97CC7CA7661840CCAD24B1A0C506D5F43A4EA81F17ED3EA791AE8CB50909D1EC03DEFAE424DA32424E5C7C15C11A628205EBC78A66621553F2CED67028456BDACE57D86A189870398434700C12A1926A3A40825A332E0F7A0EB469CE95FE3650FD1FE31C85ECCC62190DFE894FD47C4D352DAD00DB0639C4BA16E9F93CDB2B6AC156E44C5E747F7C4B356CE938332A6F5ABBA787E2A84EC607638C24BF19D8F06FFC245C81D826A615485E2E07F7004B25F4243FDB391EDDDC11DD0B63E0DFCE6703D1BFC33CA6BC074797FC39A620BD9B1998BA3FCC148E1F2C29C33C992737DAB783ECD23413CD86DE41E78213C17C3EA93AFAC2873EC00B81FBACFEF521997A823C9E2F7933FD7151CB709C31D181F6AB9C589C3FE0392DBAF2FC663AE4534F65D4894AF9F1A7E6CDA2F0EA1761136D5E6BF6B78AD6E6BBB78519292B81029FEB6637E3CE6D2555AF4DB9CA5C94BB0E64A54B781EF2D43BA5D4AD2F938F63B8E2D0DC64FA1C96B224163E30A134B4C66C6428CB6C7EEF525D381A823A555FB4C75ABBC140C465C2B1AEE1DF8411729C57CDB3CB200BBCEE5A19A7379C42CF5D127154FE4653FD04E1EBC4C22229D6E2F05200E941ACB013D94BF899D32408B24E33FB936B4A1FE98B2C2A2944FDB9C4033C8AA35A9B77DFA89DE336F1C4038790CADE3C63B7F146DEA3D72205E55F0D3E1065353D876FDEC569C8BA18509C89C9DE6A6C14EC5C0EED7BE8409C0F92E5963F982AD45739CF5DB8C0CE11CE888888918AF02FB76382EF6E95987FA4376F01AC134A3A542D03B2A82AE0F54DCE296547A1A78F43AACEBA891F7AB51459C998F811DD5CB50D00CD9579EA414C5E4DB37242518818E328AC8B5EE409D9F19789016B23C44EE123E2F0CDE7B6F9B20B9F583D0BFFF9DA8FD3ACCE9064BDC2F370F830AA5061E335F9FE39510304F5C16196B32066913288C4F6FEBA940065AE918CACD2BB23BB36770439804E08DFDD9AC89CC91B10FF77067CC52EB40D48379C476573707C0698D0D0FBED05D68396318E4069E384F3F44CCF295EDD9729798398AD0B3B22F68F935985267A0EDE208CCEB3EDF70ED75875234B6F5560054E1E101A266625667F4EA17E715D003E7F7DA35B7E05B184EF87BFC4119557011F32B98911C602E4DE156EDB0868CA33845BC759A084A11A8C6028E1A9A114958F7347091D223F3A4F40E11429C9F582EF9B84A884CB7EAB6BED5603C26FEA19E9F133A37EF295CA9BBE1A0901C23033908A5ECAB12F449EB3F2E6E753C30B2B19F015E048271FFC9E58D1C7F47D523AD35B8CD793065DF7D04A40FC50E06F938B45D2BD85AE6ECBE15394D4645D3730B9BA590EF90025535EDB0D20939F45EB10A9F2F35279E529712790B09CDFAB681ED25BBE609E1261F8203F88CC37C4897DE56729C67DCD98318DB0C5236FC75C8EC1B171461FF27EA74C8613E669FFE1C144D169D96C14826C8018BF0599038321911CAA7DF4F354F1789CA6178D958C44644EF8266E541A457CE32736294E6E95B7C3E5FF2F713CA6A4F814B77D6EC89D1B0390C9DF49C05BE2A9F322F1D375E58EE9E4B120662E885FCAD8053BBE8DFAE914568FD48C30478F709BA4D6E62E9C5E332F61EB81807DD6B2C07AAFD5E5BD98C27B3300561769ABCF993768E8261CBD7EBC2F0A377CB619D1DBFAD64E24E4D890169FE88CA118E391B310CE892A296271DFBACF6E93940C980D6ADB4228267B9E515F69844C9F72608BB40DFB20A2D67A7ED848DBDFCD30A61ED2CC6FED10BE97F23C217D3A7B55CCF5052C62C9F5AB59D68921D603C7B71EB0B7E071D64B67D89F096DE05D6A241502989F4713FC03C09B509E4D7DF8B24E8B059BA81558371BBACA268D44A7BFC06C0320A7715C61CD8F2D7618AD721E28BD4A6914B709D2427267F18AF672741303FE988390D5DC009D876134F026ED256A8FB82BB8333206BA6C7B3D39296DCEC07ABE34CF665D93F9970171E86743397690964D61E752615341CDDCC72D3F27EA12FAB2C1CFAE77903FAFB6A87A8C5C956ABCD76851E249D522D554D06DC3C1A023493A9B12ADED48A7872D9A33A7E548783CC43C31A4798A520862F4BD2D0274CD0F907BA4F77FD500AF8FFDFA4235EB56D5CA9A3E96F5D4E6BE7D967012B59C972783CD8023FA06099EF7E9CBF04BF92925A5A1D52712D23EA93388CC6A0FDE17E34A4F130AA5128557685349AE91FCDEF7356739C67E8406055B44F6409B6F86C070A76DE40B1CB4BF6E34F9D2C0B1AC6EA91B0EB8A6C5F87872D3DEF7CF1566904550366B3622C72172B3D9D4577324AFDA08F68F0307227707BEDEA4C05D00AAAE3127C84F9233CC47B144F0329F9B3E9BDDBCAD6F2A37C9B7B0AE83E114FECDACF6C8307A072B3C5534761C3AD5330B9D275DBF629177F856802CDD430CAC4A06260B8EAB6A3762169AE18535862C72AA281067AEAF16A82407DD62B52A0FBACCA1D5852B000BA6236CB8C90C4C7E9000E2641C0D52766ABAE9312F03252FD3401A9B78066D1F9D9017A94DBFE6CD3B2C4114D03B6D3D11CCE167151E408CE5BEF02771938AE121A13E0BAF9DD13EFCE8540B90F3A54F6585FD2F5885659DD78A27830F11C21243BE1575CA1D939E3DEAC90BFD33766A1209122C70854D6D255D4A7DD789EE5710DEF2E23063F157A3892F6B292B5977F0AC39E77F8C94B3514AEA20BE3F89EBB942502E91753FA87B5C922142721E7027C0D0AC6977EEAB4128D4C074504CBD6C9F380F0139529352E37C6198601A2A0B0E83978C41162626406108255A9207EACC1719080782341DB5319A73B52D27F18EE15694FAF16666B66D7FA75980173F0DC01DA3E8D5E173D829103E40B81452235594D68359B7DAA30B7F325E191CCF489FF9E38A5399BADF634A0B8E3BCEEC60FD55CBB5D59CA5D8BB15B0AF68934B00E518BE526FC78E1739F029B8A4CC9BB2F7F5A9645AB4CDA28081572F76E02F8A55923A4B59E0773CE7574FFFC4370E90224F774BCC615F2405D78D572B77E996AA6CC37B0E1B9A2BF27C67880404D8B285D45FADDA102F2808F770E0424FEC81F5455DA9A446C8BC1597233F7CEF8E71246E6DAE5BA5289EBB49693FC5DB014531F3CD0A76A2A292DD0A6F83A1CD4F8092785CCF571F6864D041F1CBFA915F12D5F3E0C84C5317E9E19F2E9EFA2D0E2B6940E5269C724F50A9F5DA73985636037C1E3B4530884FDB466B4724AB45310E8CEE89D1A8C5F3A52B6619B8CA4060AE6C109766EE95019F96B8E7575F98DFC10880C07AFBE6B549A919B5717C50C38BA558BF92AC3A6EC3CA106AAB3D91AC6036E93A71B15D43F7F9C25C9161103AC4235615B12CCD9FD84508F19886478EFD67E53AFACBDAAB3AD09ED0E4A48A0B81C11EBD7E92EC7F2368F7F3235E6DFE1251D6761D75E9FD305184AF9559B3FFF63923024EAC69AF83345D1B631B65F486968CD67DBA901C69DFA730B15CBC84FEED119AEFB4F5CBF4F5D4F93A6FA37B61184E5B4E7576E73095B2BE520C16023204072B504ABD98FB095A58010F013213110CDB7ED6342376B1CB22381F92DE99F533249CE430BBDF481BDED8639BFF7FED4A37D9038A6797786D2CF13BE9C2E4B81F2F1DD340E8D7B610A7F3EEEF21A34AA9CF685FDD371A902CFCB4E8B367356A297399473E2D477F44640D588726E7F08D0F7BCB4E9766F182382B33F4B9F0E090D4426E503286CDF416FB9BA92B6A0BD081BD4C9CFEE843176219FF113BDD0BCA1F2515D91956F3FFF043D619ABF4595A6B2A5324F794E7B01D1E901816A412722E7C814BC67584F59DFBF599A7C90E332A1B185ACC8C7C6BD14EC68420B144F01696F816FF5B8CA7E833860404B712ACF90ABCC454FF417EBBB4AD407E5E847F98D3953F6C32829DD90516F07FCDA09A34B4A4D72F7144F5A6AF3FEE284AA13FBF2CCDEC7D12904EAEF3B60DC1EBA0F34BCAEAF643B9DD017EDA1D4E07557A9194275C2A2A4A269AA923E7E6689CF349779D548A1C469567F1E5CB0E2F13EC3F9FEBA13ABA88EC5EC9633FC65993CD9ADD01418EF9CFFC6A8145EA86164B0A3787298C667142625EEA140D5E74A404F5B9B6F277EA7F7B679F2B14549DDF9EABBEB44C5234DDBD7A08505461EB825D51A688902565D2476E3D571262DEA4163EB275D6905EC42025A7FF8A562FB1E57B47EBC4132C6E78D830D53011A6DA61678FDD55B5EC63EA41298107BB9CBDC2C2B85FD18AEAA95807D8DE259FB85431F79279B96FD7F9926BDD8C7E0B3BCD64D71A94D274A80C350C3F54A552AC9A4C352656ACAF549C4714C077AA759523BF55F9A9E8F6A6CD4E6A4B9B188E8219195A1AEA584F361CCD939C21C9D4BDC3BBC849CAF6B47D7181F16A2A0DC3D05A57500DDE753668B029FB1A8DEFD3F5DE0274FD417AC3B0F0B1716C341E4C99A0402BE5CF3AE32898A986A91EB9D24B39A37E4692D7A604BE818AE3B4BF45EF3FE8DB8F57532B0DFF382AD64182F1838692C04AE6DDBD6D37623DC0135FBDA07879E0F1D907085C30EE99E9C0391672623964C57FD12AE76858E529B8A9C67D944CCDE2D048A15A5E6E9C933DF938133DAEBBB03DAC7FF0850AE5842CEF8604EFA9B4053AE17C2F62437A10DEBE65B5FC496232FA56ABEBA287AE703EBB763BC980978327327D4D5396C03DC638562DE7043C35F86F750EA65CF17B7FE7FF7D5280FF941438BB35021269CB4478CABA9233DEF282A070C858A2436803B5918251B79041AA8D09CF635BFF0030CE2D0F30D868F13D8A9989F3EE0BCC25D648392F33F7103EDBF28B89A8D22F1099CBD0CDE3C109A90481E0A9E0C15B8919F63A0888647F70BE9AACD56DAE38FAAC38975251DAC3D5BE4158C9851DDDB740D787772770F0F5E3D7F519C4CD8035559170AD11881C201B29E33CB9DDC20C9EC534263F552A1B0220A6A33E0C6BEBF25A647D9BEB1A172797549208ECBBC36FB19D22E9F52FEB641D3FB6A7B9BA77ACF0D04740EA849518D9B71EFECCFE34E563F98A8FB58E57A0D3E6EA0A00B154C8883E908089FAC6BBAA7C28FE6CBA5CD6E8A61774BE0E30617C257E7EAE32A00E2C06E95F91FCD1FE79DC125457D7EF3CB3FD194BA4BF82DF788676C377763FE5E5C49B817E7A264A032BFDBD58850F28F6EF35D602D2511FE3699AAFF105838BB9DC0B78719C12ECB6ADC61A54DB2E31E86B04C1A8BB95CD2D387A2518A8F82BCA16699BB6341B4BC117D7020741B4C6EF2D602124B1297A7441BF4F18582F4327262E4A2716991376A11BC6CDE1ABAEF80C90CDD2C850803811C906AA6ABEF3333EC3628AAAEA218D727DB46AEF22491063BF7D8514B22EEA2253554B8BF2A5000935742ADA369DB1542789E4357CE92344D5C7F3DEE61F312AD1735DD4C1C8081798D50E911A9FED7EA86596C2A671CB5499382F625310CE25874854B43478944E098D991F156053101F1672083A8387817982100F982067B54F7939E30D57C99066AE8C93B60DE8FD22851C91D97CAB74F82C0FA816014B338CAF511DE95268C4ED057B6E1227B846638BDDAA5119073444AD401276250D72852C6531D2F20DC53497AD6B18C004CFE37F6607F7D07955B4C46AA991ABED048C80C09050A8D65D892D0C84E6DA5E8F5DD10D329C4416CFF1B3DAD94C38F7B54885842D13ED6A4F1102BB8CAA9238A392780E9B76308860E1221EFC4A53BFD29745985AD635B3FC525EE7BBA489AA9B7A5208D2332FF3A9AE9A85203CB36099171A0FC42381A169BDD3005D8F46A851C7B5CA5915548B69087484AC13EB5F93592248C0138BF9D7415AB5ED020F09E9ADEEFF8AD59AB29E4DD4096821EF6223B9268F477B7A14C7BA5EBB1F3FB436A9C2F0394BC3CA95EC2C037CE06618BC6815EFE46FD363CAFE0B0E4EDA793D9AD903BB8943045DEF09A49D8D179B78B0FD75B4CFD3C389D2F774E720203257A5FEF44DDF6BE142257D95F7F90AF77F65789E015E78252B31A103E98193AC6BC56CBBBF7F46E99650AEE2407A82268162DD931A7F933471F946898351EF29A4792097A22B66A5ED571FABBCB2FC9ADF033F69020997D3C9A4D7E49D7CCA0F4AF33D9D8DA651AC7A5FB4075B45B9FA517EA95DBFA402A6058F806FA9A48568F0C7A1223C89CF54F93A8D412987D6344611E460A70FB06CADBB005C3B6FC28D1203C4745352EF527EBAC405007FCC33484E6CE871B1C25638F9C336A5C0CA24B01D88D1E103FBD232EFDE4FD2E7A164680F1D3F528C2EFAD90DAEC6E3D6DF5A236BE1FA8F2669F92D7111726979C000764A0F7906D35D394BC2F21C6CDB3918CDC7C93E52EC76DB3E92D2AD6ABB6AF77EE01EE18A64AA45DCF430FB84D500F8811CC32ABAF767CCB0EF22B6F62E3FC903771520E51E82FEE219125537FF8316ACD2F300FC94512CA54CE1C68061B8277E1BB4508E003DA7F8274B9C2148EA4719B2884923C2082203ED22A463F9A07C166CEFFE4625D15A2E690C3D8EBFBDFE5BB8B32B85B1DE582DF00638FBA93EB700F2B19818521EA8EEE0481739515D22298B94EFB870B6A92190146A98F5657A25724AFFAA52BEE9AF8E0CEFFA1404DB27805CCF47B9A1F8817E830ED46405E7DC7D1BE3EF3B080697E2340E47507634E561A77E9F18665729B84666BFB31D7452DD25DB98724C66497C0C3F57034827EB85F1FAA34814E787D2ED76D4CB7A04228EA0313ADDDE400B377FCB16C716BDC71E08A33635D2C0A4A2BEC0F7C8013B5849D8014C2231E020866722CAEDDDFF4228EBBE0D68E72F200CD83610A4E3CE15983B6AAE3E41BFE92632438EE2D2358358CB1CCB69C960DF09873CC9CC1C766A81CDD51ED9724FC06B6DCD708B5A4688C19976328FB762EF74027786694F08B2DDF3EF688A605E3EB41A9E59F7748C5A9B53323289DDEB888569C94DBCE7012BB97D93956C2B86844136C146AB9F983B905BE8E70DB991AE43B689AC95A7D425DC3F1BBDD456A224032895E12CF7037DC878B07A9686BF77A35D5A5C222F29D413D64F4E71F583ADF46BB6FCE0DDCA51922E1D220EEB41E2F09A0662D5C8E97E1D81FABC5AFA0CE9844AD4D4BDCE7C6016D8A1C452A1B407FFBC58D5D9E7C701BDBC8C666CF0F09E69FC345A497C822C956C235A1E43D987C630C540FFB4494CEED53159689F74D2131924487B3FF08AF6C8E14E2BA15C48D16591DBC27D1F774D8AF379E7C7319EA2323ADE2CA17B2EC53AE2D6B3F80E80937179FFFE04EB048E21D01E4DBB5F860EECE71780D706D93526285B65429A60FB8C34D9B62F9F9CB7A9EAD204375F8D8E2EC1262593D3F8812F4A3BBD15C444094378045D3EFE89A1FECF91B72A0F6FD1EE971A06F79B6B2C4F9824F7B6643221D0054F543A430CC2F18DB81BE4741D82CB97584D743FE3B7BD248350EFBB901BA4BD6BDF0185065931F20209B710F9DADBE65DB3D736963323D22A6C8874F1CA67AFCD3FB3F7AA7E2EEA71FC4BC3A3CF9107773C75F5E5D86B2F2FA331854FD4724AF4871309625D7E11BDCD2E8E3EAFCA85E98FBD6A7F44B9B85875EC4265A15A0CEFA1CD54E67C3CCDBA0BF7109D98297D8DA5A8041FF3B154ED586042AE2424CB4A9D070E8F485325F2F83EAEAE2A6A38FF3B708C7ED052F1BC1E28FF505031216816D856360542B3C38547F903EDF10133BB79E0719D1483F28670B2D51EB9411A562C7D28587CD5AB16227AA6A4429CF53BDA226E55B1F12F243BBA1837BC2C6582EF38780FE34FA331BDC1F565DE8963F087B8A46C90B2C205BDF622EF7844EDAAE6CE61771E996F2A16A5C801DFA84206599CFE5AFADE60891477C11465ADD7588C92836E1DB3987FCDACB59AFB412C3D81802F4D5A2F421CFF056264E0AF2D9697DC89CBC0DCA71DDC591FD29887F2C8141C1B6BB513E5D7E4680C90E76AC9912F01ABE511ABFE7713F336C559C00C477617F6D81B32B04C1E1A0847320DC452CD7D51FFF1E8273E0E5A64CB19D42BE409069F569A429A112A3A820EB7CE3B8A5BF47F13B624033D287F4B714745166C74BA2990127A0F975FD091248C9223EFF7680879BA6067C0765F95402EFF9547815111A25CBF4AA1D94797FCC631F06ADC1A1E35AF06F4490AA3797DA65FA6ADE3D0CE758434E5DEBC826F5413F9745CA1893FE2419BA32922BF8041971D5AFE081E2B489E5D259BD2523B9FBDCB0C6E15B0830B80608EE303F2B5476EE7D41DFE7ABFA6E5E38BC718F2519AE977BEBA9D61AEA11D7BBA6CD1B78B811291C1FB4DD9C1B434A051278B27D7D6E9AA046EAC53D2AC47B4EEB47AE72D72B84E647DA99365138C8A1E316F4C7DA1B791545E01B64AD3836FC82D5F6494AF1BAC1808218FBDFDD3B8F633F26E71AED2CF976A36D734FAC6B5E49F10F10B39EC57E92667079C9889A723AD078AD7F6990946BB478584C3E86A69889C281EC9440E43BDAABBCCA1DE1D9D3DA8D0FDA54422CD37EEC80DD17115C8635E618F65E819F9CB84E28630DAE5E53FBEA375E036FC5160F9F3E3045298C242AD57661968D7038A7D5DF3AF2D294CD3812AD747BA41A33F83FA77B098C939007565CA09F061FBD87D1D09CB5BBB1F42AA3FF08C9987EAB350A56DB13901FCCD67B8CAC4C517C2DB03FA6286C855D8AD41F487CEB5507DD2338BF94FE742558F6CF1AAF8DEB1B6EE3E9C85EFB0F515D92670F2B1C46E1DD49831D79DF8B87B30F27D78D630473D695A913AFC6C7446AA93171598D19F6DC29B10BD11484226A33C9E0912BBB1D0A297FFAC54C6F1D5EAA5B8A28F9E0810C46663A885DB70FEDF0D67E38ABBBC26B109062CB1E194B9EF09E27CFBDDA03BEF099D813DC7E79FD20E96319E5C3879D9CC8629E2A272B6FEF7BB29AB590DF2AB1FB87273314117061448965A338C95F218AC02F404F9D8FF56DA62F2D78E696B46A7120F28839022665F4092238B4B7F8AFBF8CE58C9F4477567AFBB63BA8D10B85CDD3262FD47CEA90B3779E6AFDC37A6643D499BC2562E9A98F8ACADE147B22EDBBAF687176DBA845953CE477575FD2CA7F0628EA103977F9C456D2C6E3E1286F36BCE3CBA6092E5A238B4BD46CCCB27078020974D4FBC773A206700FFBDB25623A9D12BD8DB5C7638452B73D6CC30B44F9C73FA7CCE8E26511A7A5FC4A8C17CC0BC899C6B58A7EB4F00F3E64AB33574D75A0E4C563B541B5FD6DF598B45384840F583CBF629479E8FA47F4E5773207D093D0E7588786F2485D569063AF6AECB3B019ADC525F096E05D6829E09CE351AD872D80A361A0800280AA3D965F6590F93FAC003B4672F5BA55805D8F9D91DBB9F8CADA9DC3FA2C114A42F9AE617C4DA2B7C4B759B33EDD464BD7BBD0315B671A435960F6057FA3734FA6825357F392D3D31FE20F0FFA5336D5CFB57FDC6E03E873FB3E4A3307D862FA7828C1DBA0E0532EEDFBE1A61B588C8809BD105A0E810CB48E86A0880846FFFCE56ADA16817229FCAD2FD34072D28895DFA60A729CBC76D1DBFA10D57C3084E2027C657735A9EEF88126A44D2BF10F6863B5310C43BB856E812CE1B97939129C3D3218448776568E73FE9BFC4587AC2953C093357DB013AD90A033E6A472D6383507F67F9D6273B60564D7196735F3882618B0783A9A3A3E281898D34C08AC0FA7AB489CA3FBE1A7FA3148884ADBE50E54CDA7ADED820FC27B68AEB11C80DC3DD6FB9D79942538EB590979F427BAD5DA7C7B035B907B99E86B6C31969F34E116E79EF1D5DCAD272A5E3488494BAADFE62BF366EDFFFEA0DE9CFE2F14850F1168BAFE7DC03E0346E1DD0538E361BBA9D6C3227789BE4FB354992D923C50B7B19123F907B66DB827D54F47ABB448700AE27EE906DA638E9EC205865C4924276EA8DD984CDBE073C5D05BB4A9A242ED555C1D9EFDC0627F2370E499F2C51764F98220B287649094EC45FE7A5B2766AE6E90E6E8695B3325FD7BB8AAFCF2E15D38D1D106121BBEBEE7B8EF492EFFD2D6430F5DCE5864D429326E37EA86B15463A5B9C88133ECEC158B0FFB67ED563C085821EA1210120E0DD441DB572A88D00CBD50E80980FE675E136133CA4E1370668126D2AEA98D36273F652FCFD67722B87E6AEB281B1D9BEADA4BED94145FC719A45277D8B8AC19A60E08457869F75D6BEEFFAD1CD8A2998B5F7AC049D3DB75AAEF2FFAA69AF8905EBEAB8B86E23FE0AB52017853388F4330EA6DA78DC90783E6EEF2FF86B0583BE802B30846773AF7BE59480BCB0D1526B0E631CF4B0CA5CB742E8A8B4C5999EE88E44BDA1FC6971BF7CB3206A867EF9CDEE83F3BEC5783E8877DD4CEA10A816F14D96AC5C8AD88A92334B27DD8B8A5243DFAEC9F0E2DBBBB04E1ED4568A70374E419FFB3519215C018094355F91B3E499C463C1621A9C158AAF31922C959F959EBF6E6D60351F616057C67E76B954261214897EC05A07C56CDF0CE65AA2FF04101380317F90005601C0E0C7A8561A582F6899FE65341F0CA79DF868C49BFC9B95B3B808DBF4B327F35C1263EC15C6EBA3926B142C7A7E929DBDC206971C273DDB28FA58653144EB98CCBD75A21B972F0FE3C76A1C2CA21D009E635C4D0FD3FCE14FAD4264C3D6D00E43028385FCB1E731971B9897E12552624D0C8EAC7E1ED8A16D9B65C12DFDC0480D9B2A6E4E5B53F79E6FC4E75066D75D03CAF6F699FA2669B2309879F2AD32F2611B98F9D268CA3D55235CC3A87DB93DDE8DFC6374B25EF75F0D1123B3CD3A12327860BC5B882152D367E19AA461F850866BE58488E57730BA9179BEA68F263736DA6BAF5B770D6E55BCB8A83CE905B6EBCECC74EA2B8D04BFCE4549C6C497709D2D936EE5BDE2EDCBAD7DBEF69DB131D7673459FC4D9D31BD603A7D36BA246F4F6E8F329177C1FFC4C323BD00A780F9CE5F058C9A062700A6A23CE5BBEAB679F5BEBAC10EB27664B38C10B807032D8D546DB160E11066D93A37753D114B60C6470FC15970E561E3CC48A0C0B8F60DAA375E162A65E574AF2B9D6B7C9622A757395D2C48FB371ACEF0334583EFC001B84AEC1FE2643840F9454B93598167F7391166A9476F1A17E02F830365DFCAF0D7B426DE5978440C338F58B1E05839A71CAF3E78B77AA65BA1FD46BF3457E619BDAE5D19E1DA801D33343A6DDF3727666BCFE397A4250F1C491B1A3521664C80186E4997FA51F90E690729B40A96DF2F5C50D0BC73900691BCC8B20FB14A45862DB9267AD7FF52320CEA5546D31461EBB732431DC5FC429672A5A5A21E0FEB56ED1B6287CB9BB0FA60FB5CF505686DD72F54081DEEB6CD2FD2009BD21A4B7485BA43356A38820E35453F38B3E0F1C89E5D2AC60A944709A0B3F1C337A176A2755BD8C629BF57C1803638758341D5D0DE54B9C18AB13E052E16C6268DF5451ECEA094AC2BD7DFD2D8B5E1D2AA971854E5753CCAE43F40CC8FBFB6AFA826FC515B83B879C7EF758422A3B018D221431D4F033F426CA8A2E017241B1877FA084DB473CA217FBB3D69C2A1B2CF3EE7E63854BA2FF4ACF4BFF828B8EC47D71506A39C5C6C724DC12CAFCF3C7AB4C095EBEC2ED04D53251A47368941F897B656E3B6989E2377BD75B1B2A1905D7A274176D1BAA2677158934FB9AA0F5D97A440128E2311B966E98B23D91E7E0299193D4DB743DD917A185A6132F7D5BF8D44FA8ED48DF7F7A0F90D1086371E6330B3B81D105368EA77807AB4E0689285238DE9E7ED4460CE00F81A880A3848E05E642E1F4531BEDB4FC2ED4A52AC394E4234F6E05611602EB1BE537134ED9F24D9F47BE500C1C73EF551DC2CF7E0BF8C725B17ECEAF0DAB8B3F15112D180CA0355A0DE7AABE35123544955473140C1A211D2225BB6C115A43120EA3F89306D3B3EAE706C695EDADB0380CFFA1EE27D48B594E05076CDA16F51A7FC183AD9A99DE67AE18A5FE0DB7C2AAAE2839302037BA71CD18F7675CAA14D8D6519874F2A333D7C7963FF633DA201FD58551AF7F7214D1C2BD612ABB7712AB62605629E8070A743D323EA4844C1EB7347B3693D155FC08CC274639CE68B726319D2FF4289C4926A2BC88C32EA11C95885BE99632A9261632B23429CB6240FDDF1972D7A999A480633034ED1A88F3B4C3E01A5C49950FAB6CFD52219E7AA78CBC8F0DCEBBCC25701FB1B2CE4C23C24D7C6BA48A37D08A87F99C2F3121ECA194BA105482C18CB30AE691E6F87B71C8A07143C475887880B19056755FE8B74010080D48C4A6ACC4270A903D4F08AC80E6A6340DDA4931751B4E95839DF30B16F028A201BA29BDDD21DA69E5889B625B8171C66540C9D7661582D59408A3839340B03EBF93CFFEAACB9A462CDA1285DB900088503AB969222CEB5E61366C352D2781CEFC9E3D00CDBBDD820F5FD9F5F25006D6BFDE5A16063F1302071A7E6F574E7F56C3EBDAA9E2BFED115B4CFA155A00B7CBA65777BFC546327D294EE9215852905394CB8A5CD7ECC9BC656C3B6DB01730497F662548E8776CDFD90AB002ADDB8D2767895FAA6DD571C7E7936ADA00CF6D1B4A2D49FE918DBB292C094517A8E11B1D9B821A9D9086EAEA72EEDF8F4152C26F80CEE9461EBCC33B0986897601D1A5B222A3B5A8F493D98630C0426D49C93130EB4D05D3D8CFB7ABE419B43D58E2A874780FCD256E6BF6CC8435D75F255AC798A389457725979C8EF289CE664402FC0FABA37A24E3B40BDD806B23CEF43797B4D58DC614BAE859A362D15A19B192283F4A3930730E70E6AC82A1BA316E1DA9586BF8AC1B94390D9AACFCB2063C5D161A8D8538051061E646B642B51E26C35F7E49B40CB608B88C64B6FF7C16A29A197C7D9453E7E7B3629BD8FE4C67703DED74BED46DCF23E3B6F28B2DF2FA82D4C5ADA18394E07A79E9B4ED5564F63EED83826B9B493770231CA56B988ED31621B45F6B9FD5D451C189CC5D5104F35DE4EA32FD6C623EC01344A949621851007941C92A981EE1798838F5B4CEB6578C560B05CAD78260545B2181A0AA1752768BEDA09D4C3FBDB3638DFCBFBCDE6187CFADD8EE621471E68ABC48A138EB2AFEFF5EF38350317589EB23B46D8034746E997EC77D7884DA9DD2027BCE1997AFEF32C6D4A2A1DE068F11D3B3835D28DB243CD4F2120BFDCBECF926E89C965E39B698DB2998A3443DC6E3723DCC653BD9F33E2CE09632FD05E1BD6A624ECF88C85B95C120C96C2058A39345498EB6726FD14808C48393F179EBC09F0000FA65778F7F1B70224725311EF19725A8BE50C489B7CAE26312CE24BE4600DA70A21016B65A8BFD4A6F0CD3EC73A409D48C2F697D5C42D6CA798B5EAAAB6727AD53959ABEC3562711E9661DA8B64410686761A161464BA141B2C21CA1A5BCC2D213633F2372D6B0E5F66A57720D624B3DC628938B1335E3FB10AAF889B1909E215F6CA836BC9653E924EB5556795738C38E399047FE24FB36FC2A13A79300BCF50FFA488806A54B4CCF780E2D008C688C6615041BDAAC153B06D2EDB999C07628BD7E1A418B261FB7B2CAB234F0F5682D9AF401C6120C1254C87C2E511D04A914C8BEF676B2258F8DE95B6252332E1BFC997674376F3BAA90EBCC528C6B81D992376E739D2225ED3AE78510F58BCC7E21D157ECB68B8540A818140D3DE1318504F85ED23177D9CB7459C6D8FAE0ADB4B626122C66B1D860A2EF753E0BDD9634E120590B2D4B0718E83B6F06171812F82C9DB2A4A0D981D70B347A545B87CD8DBD35AAB271D3B0723A4F237BA223395C3DCF2BCAA97282CE963312CAFB65F78C7E1151DE6101E7998DF4D58383973361F54ADD2CC8579996E66DCBAE5F00202B157C17894E1E7961691B543BC8E92BD7EC383D73218471E8A7D2B794021A5FF3A552BE689A79EBCCEE2A7DD4A9E7702A57D0408D6D8B4A92081B5A789948138D9602C5A8324B013C772CD381596635C512AC7A4EC19EBDBF48FB1F7F563410B0F52C6D716DD4020A076826246A819E830CB268DD745964D0B6036B8275E1F1344A27988D0BDD8EABED3645D5364C4B6B448AE60CCA0135FF08DB589058E0B71F99AA2DD0C5CAA82966E96FB98BBDCBE315C2799C03F94C9AB55558FD12581C292AEBD7473E28B5EC51F635B73AE6A556325F2650B59DEB44A25AAA61A33C5D94CBC1B82AB44F53BEE323D7A7A359DD8BE85B434F3A40F32AD344F7A60F0056E77DB4C5009704580358BA95435686C4926DB9699036767A957E545A49BD1AA3F7CDDE1639BA993613AF66794BAE3D07709FE6C4A7BD2D2CF978D060DEE9D8A4D48F5997A1EF5BEAF9220C8FEE5C846CDB354918A092E75AB8385BF088717DEA9881A37373074C0CB74D2D8097D219DB4EA2BE6FC6471D617F31AB92AAD18BFD48A46BF96064F434EDB418263C7EB1743D557AF78F4DF4EBEC858E0E0B06C5CED5C6A54D186E75B3BDD6EC7D564170D51002BEAE838F9F2B7D68784F3E10DC75C1D71092F0B221844F0A358104AE46AC75B24752F5141CD6782ACF121CD799A0804A316463985216BDA98B5BA3C7134AA25E5F46180A288DD3E52AD68E1EB7ABD666AB88EDACDEF3050B263A470CA7A805A3E120701E61ACE38CFB20410A7C414ACCB79D1FF72299B42F2B412AC058AD33F0743A063DC267E4317CCE6B65FD00BC06A16F23C143013CA1F09EA6D0D9BE4989E7F1421A732876B6978F119CCD7B51F7261D414964933EE23EFEC7EDB0AE7D03B513FA89291E499B49158DE5E29357EC92B55EAE2E3EF634B0919D2CEB7CD6430994ACAE132032372D987CB052D4F7A13B8D51B97B2345D9EEB8E74420EA506508C3D6815AD3EB480F589AE9449F5D2400FC39F56809951041D0C4CA1C07D68CECE46E1727B39EEDF1B5EFD6E9F1C28A10C708DED3ED63D635B0DAC75C705363FD52636D0D33DCC2606C358F11BE175D34A1A41A08E964956C48DF27DA2C3F51EEE7787CD8FA10DA26FD87B206D90486722FDB053C3E2C0F08FD90BB6CA63704BAC4615DB9314A624F5D5D16D0F2D7A7306D4C1DB969C39B2DABCD6DE41247625917BBB56D1BED6390310C20793314352CE3633EE7756F81DA1877C5D292DCD8F90F813934596377301592DC46A6F012B978A9687FACD9A255816DDE941D8FFA5FCEB63C0BC6F676BDA609779FD65DBD78F2A6AC763D846C3B63B7F40FE7FEA09703D3676527E062DE4FD692CD9CDA8901462A3C6DC315447A89099E121B97332E35594FD13E6062D93E34A0626E8957502C61ED8A78AC87978A94DB6A87024DF4A662564F1EC441653EC706541F32E5A9E502188981C51A3544FD2B6C0D9383C2DA3E9EBDC45D4739B22EFE1125BEDED6159C4BD37866EB06463D57C2119DEAA281CDE3725218D133CDF7817FE32408554CC5F48126215A4A3EAB3C58FE8E2888E73C70D0C4E8881C9DA95F06E30C37B64E10BD7E4F4BF8BFA7700E5AF03D4B8B0151971AD461DBE22D1290B3B05EC1A48FD244D1CA4E510B8E8E8A7E93C1DCCD2612779C8FE13BB28303FF6370D9DD8479EAE88649A90CD242F531D85DEB07DD627D1F8A8FE42FB2FD95716CC884641624EDB8B7284C7747E0B58657393917F898974C487C397B9F10A0B7895C7AE3A02CFA76C9368EC2BE9C0943F1A653D7305EF004916C7F69F4AF4EF948C77BC885550E8B4AC20D2947BA9E7018F643B655891DFAC68A81047F3C542F8C70A59A1127A1613DB7438E03F31255A92577EEE9A23DA045BC96421C1785BF604D2B4AA1251A8EEDBFCA1558DAD9C4803CCA63E2E4D88DC59A96F41B6D3D2E6B15FCE35731565027CA0F738FAD0AEE7035F44D5FF68DEB92D9DAD8BFAC611CD5B86A301EC5B717550DFCC6DA590945CD5B23A45F4BCF4CD5461BD8CD17601AAE2F14E3DB5E366D86295DB75A9B07A580F41BB017CA440269C34A07207145B51AECB8A4B557A40199F9BC355F913CD59809622D517CD6797818F3D603D1B1EBF2BCBBB1D3C117242FDB77237FBA06E719BFA63C2FEFF537DA469B282893CF0A37A1614B32B455282BEE47A10151C5DA32DBABCFBB1888C5A181389F2FC367DB215C7EE7AFC0DCE36A210CB008E726F962ABE80CC01C3D157EB9F045FE3EEFAED7297C797796394F536D52DE4BEEE55167B88737CAC6656570D442C4B0D9244CD869D65035B55D0B70EF5483A8D51C4C9E21B1AE5BEEF838436AF9DBD23799E9AD3D8E21D801B4AF4A1A0556A2800FD7B31940D745D5E0F13B888F4C1E707D9305A08EE2CBDAE862FE7BC3043737C718049B701A94517D37AFECAED3DCBD0D4692B1D6CF6B3B9A5322A5F39293540E7C61A627191368EE0AD5B74612CDF83EDF2E763181082937D8100672B3FF5947EB4E59217A941FD637E63F9FB7FF4D5D63CDA3B55D9D504991C4635C12EEEECEA8BB7FCE5C1A13E07DFF6D2DE0D4B8FFCF3E982C26F180F88725CCFAE0576F3C934F6E75DF9846B69EA62A947121F6AB1D066FF551C49CA7F8BBCF1AC17F7376926A9BCD12D817E7CD14859771F4E3F7E8E5A16041F68D84173FE04A5EAF490584F5E0DBB62FE1D679FCF6A6BAF3B4923A13043EAAB5EC8ED599782C4C3B9C128370B124582A609FD85093EF88247E213575BDC4707E7773FFE0410821FE06CD8CA533084CB09EC1752D7223E7505085C7A55BF1A27E4D0000B15AC6D264FC72B45D25FD3CB24FE75EB945FBB69970AC6731DB8841D16E844F4F8FCF1D7ADAB02F89603B32899ED83979B5B72BA763B22C26D7B5390732EE3EAF15B3AC23E62F573521AF8010AB45BD9F1F2B289F4BD0367176A7B7CF79CC0274AED59D1B46D32343555DD5E5CB9770633703F38A83379210D4FF663C8CEA99F9674567C4AC14F371E4CB8F19A57A1770D848751C1AD9A609E5119657317416DE54C1835FCD29830F49AD6F719FB772F6252B13912AB4579B35A3812F7BCC1B7C54708281A89F30DF491209256B03E0DB62BFE281E982ABD2224BF3C62810FDEF059FCD65483693FEB0D8845A29765728A59BE0083C576E68DFBB2D947C9987E1ECCB937229A790C862EB60A375A8F7B760FD592CB51C1996F93B1DD592A3E80BEC28ED6E0E0B20575177C18177D506CC80F9489E41A24815995F60E83695B93C64F0B831B72F7D2F798F4561C27C912316A7952CCCC3698D6E41C0B98A5318FB01EAC97F3080721B4168F5D5DABE13B3C7E14A914694353964545417EAF20272FF0A6AF87372E38F7E22222013938F566E4FD637F5D10D2303314014ACE33EF1B9C26CBEFA6931B90F7E735F21778C80C9A9A6515C2576BA220167B43023B1B7689125D80CCA51771C7A2FAD2266F091AC82B65441823065536C3B5879F08FAD8FAC3C6CBBCD43E244A22F9B5C3CD8FA4AF079A743189C12BCE489A64391F6CB6A556AB9B44D51FE72C11C936CA288C6AAB268B8DE45680A0989553C542413DE958B3DBED41E668A4A85FBF81A5C03CF05C8CCDAC7096C18F45E97EB293CEF30C9E0D673BC40614D24EB17E9BAA2758BB2EE29CE430E74EED071C6F73004817B4B0EAA20E1DCB64C846BBCDFD118DAB21F8202558678A00B80895CF91111100B35720C8385FC28791D764D77CEF71AB2C43F8268116F120881C17010A55AA3814600E7C4B84FCE4952B2E80FFDE1794D18B9209311841A4D4EA4B8C6643CFC98F75F7D03C370AF4A07FAF44C7C25BEABB484C0E42321251D61DB06838AC3FF1C9784B836AF78F9E2B352BE7AD1D0D54FCC73E154148FEE964AD9F57B10F89ACB9607B678C9B1F189F92E0D3B4C3E44487D760F7AFF49266A71D3E493271F9AE1A68935458EE611D765A977D05D415649187439829557526304F853694B9F0A299FFCFD6A1B74F2D6A99BBAA0B8F9C1C3D3125ACC63D790108E7BA24239F9C4B362507DB1DFD74BDB6ED00DD9D01D335F1AB34193851A3BCE7FE803C5483646897F8270049665685E2EC70DDB353FE1866462DFC373C8D23D0A1024008E5022356D492E1DA21E3C0ABEB9652CB63916C3219EF2B5AF7F2398F277A5F7A53F8857073BA635C19E90D0F000C3D84E2E6033D6A50561BDD493116FED165A35CA58BD7B1E40CF0660F0D351BA37DDD960780288006F25C64F688FF6C513BD2BA9105EA9FDE3CFA94243BCBB4CE8D54DE2F021D2DFE5C84016A70A980028CDDC67E2A455A8BBCE20A2B1B540FBC05FF3C989798631E7FC2056540D4C8F068BC527ED89723002AFF997AAD7B75F37C00AF45CF39D1FB5ECA8AACB13B290C0F9A587FCB39FF556244AD03E778D9076C97E439DB2C6B7607C2865FD8165C592CA5CBF6A1273B7D732987FF09D0EB1D428404C601A7774016F3AF844664563E781AD3C179507C9B3DCB535E9BA4C14B807D0DC52D0F8DCF609E89932F588F14275C2C47BEF4BB69FE0409850D1CC681E4968CDAED75DB80B0CE58E1B111F687B5B5A4731F873605D37535A48700F2668B61A4AEBA20783D1DBD14D88D7B0F27F9DE6D030135F1E50EF428F24D3374AFCF3371BE01A1039C2412D37E58A52EBD0DBC78848A17D144ED7DA7C8848C535C4335A2EF5574727E17A344332700EAC71DD64C8518DAD3F959B1174219C5EB04ABA05E0A1604AFFD2ACCA0135680BE86D07A4236E09F4897B6B93E953B3790A345FEE8D66EE49D483BE48FE4B2D3E2D99B0516417338EBE25427ACDB2A92F0F01FB54C156CF7163BB4966658C5CD6DA580D54FD4E7D40A8B498CCB2D1FCB3EF71402CF9C2679F77B10DF07C7A996CD3D2F9E4905D1C541883EBDC38C102CBC7371032087114CC9DBB73E5A59E6EC7FCEF92F5CD05F846DE503709123085C7D853573465AE258044320F52C97738C7812BF73A701DD6CF8814695FF187A674D26DB12F990C7A56D6CFB38BA475EB20E9BDEFFD44054BF13DFDF7816141C89E897C7340FB9675E3D6721D8472BB62DF3E206AF59E6B64F8F4C9B3AED72424D86D6FE808C4065AA79D00E1716E85D5205B64EED36610D61F66F76BBC1A9111968194196459C7A3769018EE34EF5DC03EB0BC9257ECE005993DB5010036CAD711C6C9C09E9465A3A1ACFA9A85E08878FD838A820BAC280FBAB50826CB69F735D0565762E0C6FFD154358105B1C1DDA0A1E4303811E4E3FF5A235B49836720E5E8323E0DF783058135CA9599C4511FB1E965782EA23159E72F6FF333923B51946417DE28C1D7B044F18707178E6C0A3151329C9A9A7AB8E4735D61294C08A859EF72F9AEEF2E6B98097E72A890AAA21281329F8D4F1208219A6C3584B6A0F86361AC6AC0C77D4092D104E0CF7053DC41298F2501AB3ABEB20F77850D4F9A5F685613E43F191B07FB10C03DFDC0D7582D8B57B1BF773D2CD8F3B3AFCA7CBBB7AD359C9B2D74D8E7883E1D9888A82EC10E24FE29E25ED7E51650DE7523729059200ED10D49C98102E1D5CC5C22D20C12C4A2D827D684D6A7EB90A37843D8E06DBA90B328108130CF1824A083F770B9F5C3B8A1A60F51382B56A6BD836AAC0467E9CF2D3567E86BCAF917E98C016F01A14CDDA3315D9B50CA02A25FDB361DB34E0F47F187CA9CE0D4F96409F431DAC363FE330E4B5F936113E6CCBAA9150661840ED6FACF11FDDA8C5C4A7E07724D40EE267E53428638C952B7FC777AA13B79DF695BBF491496B543E989934A7350C25594473A4D694008D024BA9788D0CF5C6D590BE5DEE99FFFE6FB7B1950D502BB99176FEF1A5585AA94CA228251AE1EC0DD6A561E26708272F19A97C412F8744B4F2D5C9BE742FA310374A4C6C501D35920920EA9D25F568AFD1C8975BCD80219B4C3014E936C74D5562A37899084D5095867F86FB5AAD9153D0D61CC0EBD35FE1C1CB48FAED442126677E914D0B916972293CDD034472EFBFE29F6096F0CA844DAE27F974B49A38DDA4F60D938160736017AB05975E9E34C367A142CC6F8FAB6E1FD6C35D412501806460BA34ECB98780BB9EBC5E95DF9B7ED3A80C80A7967D2AEA13929D332907FE2DE21F1EDF1EECE3249380F98D5753849EC9C8B55B4944C73D0BF7934D9B709EAB5007384C3B5759D6C16169FE4BCB0D1D99AB0BB7C31D90B1B08A767A5704608F254E131197CA3441EA53B09082B6CF62515A5DC2EDC44D0528488351F371AE159A1469DC8F11959D98AC9DCFA09C94B110B5EED08CA4BB133E79EAA62F51061DFB7C0F201060D6179F1484AE298299B8326E899F93D2A014588422020B2ADEA0DD1FEF37FEB311707555C8AE0778D9520267CB6B65A0D63C96639B0A0EE2692CF82D8175774B779BB1ABC0BCFDEC88AC7DB21F7B0AE7F536ECC36D0CA5A6BA31A22970D23FFBF4088D13BB5C700B1652E89366F4765F1AB6CF546CEEE20B900D840D0699DEDA8729DE06F4B753BFD3BD151938F3AFC5CE7CBA52B5DD802756C2468545821B946E70879D73B504395C0CA92C727F7F129CE984F6A24BAB246B606042E68E9681E63E9C07B614F86DBA76D6870D3E6DFD6EA14C81E5020BF5AF5629A5B8486579C603409B37E177004D48522D6209E183002A9A90330DEEDE7FBA5222A5C96845CE435F7770290FC62F639753FC109DDAC53D1728686507C1B55B6C397D2F82D8DC6A7DCFA0EBAD3EA1A2BA8EFF1404698467FFC37F0AD07F4FC56160EE298C31C80FB782A50C7DDB083AA807947855DBF4992F2B76FE4CB1AF04FCBF062DFB4293FA7D6AC19B1A3B8124788982CABD885DCE6215F5C3C74B706509C36A239FB42970CA7F1F7F1DA5DBF532DF36D81EDFA7CE3BAF1B8BEDD7F35065D7F303CCC7CAA80D3EFF30876D56C1B3E62188CF95EB3FAE0B1A39B2B68A9AE602E211B3414134649CF98F10FA777FB6B3B6E03814DF383E2742D3B5CEB00E70A1962710989E09D85549BE7CBFC1521FD2C559D6A10620BFF3D238B5C67BC6527EC7510C6FCEB39CD9D080C80C6968C81416BA630E035A55C5615C53A64EF04A9EEFA745044CADAEE9DF42956573F73303DF567128FBB3B405008053571E8963A067BF59F896B77F4D7DB4317FFB5997E04CEB0E07793EA06AE306F74317DC9D09EF2C47F25FD8618D3036B81E5C9F12D5E3E5F6278C163180A4CF40F559CB48A3260348EE0CE0DD5FE1A81F6CE3599665493466C0B19251659C186F1F2630C314D6EA2075612D09E820BAE06E027EB7AB361AC987E3CDCCA01365621FEE66F24BDB84F295CD7381CF15CAA767C37F722F44B8CB5BB879AC538130D1E7930636B176B395010726DA4D192BFB86F6FB0DCC2B384BC6B601682F2AB435D0DF35E8D14DA20B0979B822235E7BB2E9479FCCFD338A443F5DD52E4A317A954A76BB080482801F93182E6890E226392BD8A8872260681AA4FA1AD64DDB5977586F0570B51C052732CA743B4E3FC10DF04D5F99B4FEB21964AE907CAA914243EC817ECBF2606389ADD6E4B89D3AA42BE4FDD97E54CF88A2C940995397E49F2167A8D229232D8E40AAC99D6B2CFD898E09A245E8CFAB837CDC48196B40F746DB4E3609A10D1E3BAB1D505DBFFF81DFC1343600F6AC67C47CFB86644F4E942C540F6605A2A8533B592BE658B03B0E77B71B7CA47C615B1B8991C43DB2FBBF5868F53CE0C15DDEDA9E4A387F179C8FF71025465A7F56D88CD742439A83724F5111CD5332DB50BF9C014EE0C46351B13411E141C1D87B8428F2211B91741BE5287CFFFB17045CC73DBD1ED7ABC5B89053A6360B8860468D38685D98ADC3FCB5DBF79EC54D79F082A7C5A0F14599CA2A8A6CE7C60F3683514F7B5C7947500E51A54BAD3FC94CB591040121DED134FA77E01C32CDDE54EFDCFE189E481C96AED427485B869C381819BE6CC48D29D91163BC10D679DBC7F8FEFB12FB2187FC26B4F2E0AD995FFC29DA395E3532CB30D7E474F2CE3BFEC83B23CB784FCE7EEC427E90BAFB231037E7FFBE0569154A19175A37AC0DA60720E9D19C249B6E6BF4CA44C1B7453D09ED37E73A6BB69B4EFAD6BAEB938531470FFE7ACF07DA382BDF797D773CF23D6C40E5A4AA5F778DADBF674177419879285AF618C130025819B672E10DC6FF16638782DD80DFC00E4A1684FE3DA79C08C4DD0A267B1525414EEE6CDB64816DB56F080799993E5C8E02DDEB8AAE9A1274E457C6129C44B6641FD6D7C6617C6DECC279C02444D0ADDEC856454674F47FE3218535A674FCFBCE801DC5C94CBC8971CDD2375CA39278A5009B3965F60F22F0ADB244774B067088087BEDCC062CE62DAC57B6DA19EBC928DE33CB75D81117CABF26589D0E47E0AB42BEC26F5ED3F449879F9F4077FD67F5547106A8D4C03198A2A5EE53B5DB056AB9C9F1E2A9D5E649CFE9CBEE585188DB4E8BAE2C492B313273FECED665ABEC061C77A52297D353C718B4B104CC845AA24828E3EC939B80A5C1B14AA1B51441641C79C3427CC9D75285E36BBFD4CC7B028AB7726DF7583B7EC1969F3F961164331BC718760DACDCF5A7123DB3C2462AC611B773E60F3D9131826589B72A18F3E9A19BA7DEBA5D06BBCD4EDFB6BE918479ED6497CE84E2309E13886FC02A966F0293B8379B47A4BF01F11EDF76BE8161925550CD2F4F53C4A4A67A8D4F76DBA13C3F1A27E91DB392666FF93D3AE88AC5FE6786228BCAAE200EA1FD329297449A1C768F9D28D36BB1C79DA60DD696A3ACB65A83820C96BC61612A7CB1D85739BBB33486DB56D20FBA4A16C42AEDAAB01400AEB78EC92C148121B5ED813B12FF5997C6833259C5B1481402972DA98A3D91419BA7BC9CB2DB3FF10FBA266B9C836C7C8E215E30EBEC76D33D6715E1F79E1DCF8A5F49352934556D134EF7F4875FF19A2F01AD90735660E9D703CCD3DF9C263EEDC712390C10DA73E492C95282ADABC3992EBC112C33013F3CB25690ECBA1685D64E84B28348340FFCB1E20DBFFB671467EFE8D98BE3C3E2B97A063BCA499ABBC3AACDE57B8BCEB08F0027718A98A21F3A07EF99B41A698E723384B6AD54967754D587E3DAD55434C68C93E85C5D0E2A0D239C1B2D7E72EEB138E44E8D629D87C0BF67889331164FEB513BAA3DC2904955B4E0FE365482BE932F3540B3BDBB1DA3F50306B611DDAFBED08890999D945D179267490881F3AF3D0EF6699B62C4465B207A141DD9FBEC633066FBA60771BCD432356F2451D0ACEBCF2445E5BB3989EC54EA26A45AB692C9B646533EA3E9ED2989E268A8BAC53823A1A565A5CC1E996F20C1B27B2DCAB0A79B31CF9EC969A8DA2861C81FB20365CA3FF80E9CC7449CC36D6FDC197B6A227F4F8061AEB270624C61ED87AF17F64DFC4F54885F68203B373C10BDBC3C85FE42397B8DEC63B0C1B991B8BBEB5560B1583A6BC3DC07212A974E4C669B28A0B753889D25F5AE4A5664DE93F7DAB5C641C3621695CD47CD9B68438DCCE1ADA11BCB4695C1D50D3D7A2808D16991BFF51CF478C7A9A20E27CC4350FD2AC56DC6EAD6A60DD58417F5816D15BFDC8B4E7CD25F072C0D13CA5B968EA671582A766BB7D1E1E465BF6D9176D0E9224A6C94426663B409749B0B0BD8C1F1DFDE4BE4825810B6D2FF41384D9BE98DC7E8862E9BC2D53FA0FDEE99DEA4A25D52F2FA1D26B96571153373A9F0F900C9F185456B94EE8391572EC0D618DEA0B734E970BEDF11DB2EDE57A92E4D97B4B4DC020117527934DAF20852380C5059D8F044FAE4B445F7688FE2AE44E027364E28EC62AE6B6DF3938942B5ACA94923954FC44CA63B930703B95B61EFCA38AA521905EB954083B7DC328851F30FF734AA364EB7F4DB3A3653BD1FD5305ED041C4B94C3366D53BCD4C613250EBD99384E7E7DF2CAD649B7095A5DE27F34FF6A4F0917BEEAD403FA5F1BE8A651F562E5022D3D5100012F8F1FCAACD88224DE33661B0BBBB0A5AB19FCDFA111152C869944EEC0A8678402570E7D65CC20CA71572B9B57F88E4BCEFED603BE237E185313EA5E114F39380234E0CF0E4C49B3A81D59F31117233FFA92D45051BC04C92FA3CE23E2D37B4804BE2BA001748BFCFDD1E943F27648CE81252231433D705172B8B22AACF6BD3BEA3256585CC84289C79A1CF7AF2FE03A97AA39547F757771D6CC0388ACFE03D7E9590786335BCD0FEC1890D5712A3A62E33D887DBF23C80D47B0014FC9487D39A3324CFA92CA212BC29E9393E6FD5E6933BA2A6DB7934741BCF0F506DBC2B7F2194E386378137E0CCD8B3124B29BF47EBF89220787D778D6C2DC232B5A4C39CE9DC5743A1D80ECE67911BC6886C3F756BF7F4A59A27A3593D10D06F60AD71C8D69A69FF1CC1F17860F92877C5E0C75B9227FA13CCC86A9862B7D0BB849E0FB566E2430ACC639B8D5DD932D367A54E0101ED890C6AFB120419B8A04A4F1DE11C4030A398CF1A818F5433C8CCA0A67D52B1CFDC0B9E3643DD3D9E62147675345EDF1B9151CFDB52FD558AD99E4C3102BDDCFDB3B2FDDC7211F7827AAB7427DA19DFE86718F235D0280D3FF41AADD63F8E2628550293483E9835150ABEF10C6C98FA6EBBACEBA31BFA24A9DEF6B65F03CF1D462941DAB2F71FE09BC70C1566088C94DEBFEEE37483E76F3F5490A2CE86AA4C2D72ACA1CF7CDC2345309F1BDAB668E18DF7CA2FDCFB70E3476C086C48FB81B853894E2D238BA34540DCA2754BCF613B32B66AE60B715662648FF265341E10317A1423B7D195807476370D0527FF15CA1A255AB117357A8F6B18A502A27D154E1C84D0126026BD15F236A87C8F024DBFEC09DE837696A38FB55347AE877F46FF6F157EC6FC8D1846B7F55B1FB23DF3C97E42F48E63ABF64A992B4F77EC9DCCA1A329D84316155102E7F2F874AD369B64B3221A0BC852ABB69E1898D7364EABDFFBC94617448E257AD83112F87521857E2872E9895F2DEF3C5402DEB8F7F5450FADAFD47342907EC9642CC670FB1282BE2E1B31156F843F68BB77C29430708E91BF3988F9F4B9CE27F707828A67C2EDBF3B395500CCF71F31299C54601858C442EBD59185439C18F7EFDB83252BFBE193D65BEE7D150501832CF3E20AFAE4E936EBF635057670CE9FE5601A50BF518457DB36125ECF3FB77588E509A8A7D7A6F438AFC9AA7D103E2F2AF575EED551B1739A57CBE5AF4FD286AA870AA50B4E7457C11B2FA39F6F18BFBCD99188D0D06117197578DD2B7BE13016165B4CD7FA26D72CD6BF1B9C48D2BAD48802F26FBBE8AEE0F9E25E5D3309E03F72BD07E40C5F5788D46E62F29A4013104265BC855AD7809A2C800350FB140935EF3059B1B2AD54DD5FDB92DA429BA8AEB1D9A806D67DC7B6ED187DDD2B3F1084422D75B2C02BC242EDF4ACE0D478FCADCEC64523AC277E88F3823E050915190FC48EF6FE0897BD087B6BB2757A16AE27BCEE562A3C3955B88F82117428C73DF31862E9EDD8C8183F22DBA5A74A904AF45EDAB4AC057B8A470E5D48E277FC433B8E28851B51276728D6B0F06BC6C9E32BF06EAFC45704D7395A1F70AE27F160C7C7626047D030F8CB252D8B848CEA0D22E765B85A9431CAB3FA41C2BF939B56AC8E48D04AACBB6A62E2303E09A05AA6791F8E723B4BA8B021397C9918127E65EDC2A4EEC6B7CC5679B1BB08414FC4F2E49C2AA0F82750D07E3440A633F36BB107737DE269064725B5563DD7E49FF26508B14F29B1695F9E918B893B5D4FA04602A1688CA6BEADEE3F6BE2C0EA512624AE585396C930CDCF9E1D24F961241A421E035AE0034D4711641536F80BA8D8DBD1846216E8CE8702B794BBE1681A01C3AC79ACECE24B82DE63D60D48FBE9455359D397F0A6FEA1762920C6B976A83D4062CC19545201CD0D5A2F58312C01CAB6633521395358FA1044B6B5874DC913DC9A1CE930CE9B5EB39A87BD0DA73F5D7B237472C50C0979FD8E349752E1093CB658CFFD84592F90E0DC2CB3B957D81D80AE4C31A4906FB8DCA58835FCE16F6B3E3B6307FE4EA88BDCC466508E40F0439A3D84D1879281D460C35FA38C44D8856F684E5CFA5BACD411BF50DDBCB0F92D6133BA190627426B61694F3CC296C752E8CF0A916A1DAA336AF6DBF20BE34745DE3405AE15B2AF7D05A13DB27AB0549E3765DB2002DBB2432CA69DDCF90901B42C563DD33FBDB85D483EDF2A98931FB51274258323F5EE623B7E98954BC9AD4198CF3EEA950B2F3670A518B6C14404D9BC608B22C51F20E71FF22A13B870F11BB5FF80A9A32DD497565FFDDECBC45785EE65A14239E02A9C85D2AC0C41005BC932E137DE905FFD841268FC6E9093F911E5802EC1DF5EC68AF9277D85F90BBFDD470561AFBCF11552B52CE1ED64D281F073ACD51564367FE624870CB51B45066E98C305EA7BC6F9814F6487C3EA0C6EBB2912023E14D0C0D6223AB57F724135FBF553E2086E512CCDF095A0981F73BDAC5B27E68528758B15E5DC7F0B9C87946C1849D9861DA175FFEB27BB9080E6BDDD0820BF7077FA44E737D446E00F9645F82AB87625312D9BA244C15C9951DED33836182C892A54458DD090652613A3E1F53EB718E27EA344AA5930A4219EA1746D69E3BBE936652CFB0B94F5336B887E401A16496EB2312E5616FAB9CACA5B409FC5F41828FE2ADF32D6EBF6BCE8ABC1A3057B8E3EFA886C97630102587EF316D740A9D55E7BE8ECD4890D7F1B66A421DA4004A42EBFB9B98BE0FE01D409F319CE066EE2521063D9AD0136906B2D3039418F2334D10A85E217EB07CB5F6CFAEE42F7D59E7896DB6476A9F250279F5F7AAAB0A92198D795172B0541BBCB6F6EC8CB7E70D130F43BB2596E7CC50A9CF06FAEFD08DB1D8443D0C9918C17F3A577063EAC3A628C48FFE6CE48E484056187B6B7275FE62AB168BC60AA8AAA39CB47DA5E8E489083B5C90CF63005093B7E4C822E4AAEB03D8BD477C02876FBBA9C5CDF8F0805AFC962F43F342EEF53D531E964C4E9AAF08A0917FC8E2D2E896345583A48B556D3586877F3B7241E5F28648744BE752A029E4868B3D0BE4149C0E9A9C59B469664813513F99B1FA552B271B5251F1F91FC53B5C5982586C41D8F201C8FB187ED60332797D2BBAF27003E09EFB2A3A6053094F29175E709D4B445E3D6A65F1DE85789D1DA9E84DA5548A678D37A9C48C85F9E2B1C652ABA789B9BA004D7AF8D59BC61CE996F48227DE35914D7A44348C2F33EE039FFD855BE89FC08298CD77B77A35BEFB81AFEBCEF5BFC136263AD34027F679AC2CB2973EADE129CD5151C082944D9B795C107773248751231574E34E48976F7DE2736D11571D7A6BBFC263DABF8F9C230B26602F7489A920E12149ADE320E48E2961E9925708DD638FEC9B3EED0102188F608136E266863AECD63792732B1921B635C322BC26E2B779239D9583BEA245F62314299791E162A54751FC319FEFC2D96CD514A9472B4BE5828ED1C054126A3119EF75AA3ED1AD3F7A43E9C0920F82D1AE7344C8F31989EA355330BF8DD6C494962FE48635C2A8E8B94BD6CF5EC260E24BC838090A1DDCF33CC6DCE23D6F4075FD9607A59ABEF12FDE27818E19D91347F3A07C825B64D9FE609E1D5E4CABF5CBF59EF536C9DFE23766688572ABB728308A81AF112EDE97D1BDDBA446CBB5F66D503250E9579CE0CCE7B8F81BBD3C4A517F20DA10B4CCD8767DBEE2D7329904EEEAA8B885B012BDEB288584C41ECC9643EC2DEB7BE58D99BA093862A3CA973275264C5FA7E9FCCE66E34A87C9687CD398256BE95001C8BF18748CD64094DFB89317CC1750098E84AACB23AEA6EF8FA882296EEFD6982DD86C37E5707356FE0E6264EBA15480D15245EBA707684A47124D8837BB998B04341183B126222D4BFD23BF8BF1154C74BD9AE9AC4F1A2F6349EDDDE331043F2D8E524AB7A31C72BC5358215274AD529134901FE1FE105981E5ECA8009106DADFB35F7B7283FB9D9B43053E7030B04E31AF4AC1AC3289FC38905F3667A2E088E0558B08FD0D35688308C8DBEBC604B1D91EF8FC30333E21EB32AD3C0B8F159D4999535F117A0C77E9A8E15111F40CA9BC36B87725C18DEB78672F022C9C7D1589BD1392B39210B899F9435DF28B354380C9716C4E78938C99DE079625E39416776556C957109E89C81BE8439C37B2A33032F89DC505C7451F6865896F61CEAD50E64B7493131CA63E2AA4D3AC4BA1A7DFAB900C8EB7AAFC8D192D35CAD83A8E0A00322A0496BC1AC609FC030286CD20BBF1B2B62E7A98A10BB49A7AF2B98825F2B2A30C4361010CFC342E99E905ACF9E23D51275AC5655CFF53372D386ACBE4D43001B6BB46729663D6ADF641B00BEB312A85F0EFDBF4C2C86967FBEA0518CCC9CE9C063312E183BEABFD35497346297F5CDD8E289EA2859D0FB1AB4E54F41C38F1BE95E8177FF8D9276C00AD3CFD6BBC587B1EDB59FEA80EB5F513CFC315459E953B7DFF7F0424C86D29A6108CE0836216E15BB8659FD6D84FE2B55F01A4966F7119379A29110BDE2BC880DD70DF26B4270944C0FFACD1A048FB4E4516AA8129E049A745B6B34619794606F7555DDA876B5BAD91457D4694FC3CEBC3AE24945A52346EDF39C4D3126C652B819F6E85973B3C77ACD1D0AF1C61124556601F16E6A989136843D5C914FCC6EE481EE33ED2D79F7C5625309DED0A6A6C615EA4DC2A01F6E2039BE88361913EB0DD1E2CFFFBE3BC4ED6DDA93D1AD89D82232B314B144C2014B6C689816AB1511445AC0F50EE7D445F3054E35A8120536E86E5E130E85772D98012B69861A5BF739077383F5B7AA6A1AC7563C2C47E7833837C3449B0B6E6FCC0BAB2CBADB6EE8673591FE7343DF1974B174A9839036F9568F5F99F7B86965AE4B81A2DF277BB0598D5CE459C0727A23A4271F0EB83A7D4F6C055CA85C3D1F78F4D692C3688F5B618F779A24C03C6869BD2D5B9611526B12E1CF202325DCF316EC225B48A3353AB0D3DE412C4C486C1E3816BAE2AC9BBEF4206C3C3F976B8E10AFC72ABB6EE6591F3EED911AFC4275C3789486D67E46E33145574AAC0FD789E16EF7D88D385950309A8387973F608B6D948ADEB51B46281AFABEA8B8301281C6B0AA3653F7374380AA6984D77231F0D34B43158BA581109858E4344EA36ED73D16DD01E1B4FFECE15ADF96AC0C67EA8A2FAE36E57979C0C6A32923A5DD067618817E5A160DA7D5BB3C039D7775E060181176B73895065B051727F32E86AFE951EAB4B4949DA5B2E417D8DF2B8084564AE2C236A6E1DE5664BB1112A0CC9F6AF10F553F31B7C034E142B1E8C185DBD11038B79340926F4BA8D19C8F06F4D03232660DC978B2332EB45C1D17C89B7AF821CFE5462F4E7231354C0B0D6D64BD58D1837A31C8CF720CBE563CA12FC58925CEE387B06BED84E0BB062CF1DB2C87A37AA8F48B9D930AE4F7593BA1AFAF7F12C9A395B75170CE54979E0E19C89704D501D11F93911A8BDFD54A0ECF81402A0419FDDDED13D509537A59E02AF373A26AD0D3A0E110D0DEEA1B86DFBB9B545FDA6459798277949F17AD3E2A6509A78C778853828ED7B31EA6A0BE20AB3034879AE6CC8305DEA9E8B67796089A33E3B19806DCFCF7B8ACB76513D4FD38F3F6AFF4DB07E2701F6E5624C91C32CCFD626A6BA31DC166EE6D755FE699373EC68B19AB6F285F12FAB4C4F1CE2F8C7A2DBAC4E4D723185A4F64E18DC9B2651C52B843B4D96DFE8CF822A95820EA5CA271E2D427B70FB599167B9D8CBBFB5BF1162B4610E916EDD792B31314C7A777E4E7089F29E506B9A22988929D272F289D1CFBEEDEEDFEC28FEB379A67F43EC0BBD3BAE4EE2F8399B8147FC58AAF42A80F760B5105871AD5B941393BB5E71EB5333B8A7A708263F0D9A6042C5975E8C94A9DEB587A5343DCFCBBE36F7DF70E14D1F04C5124CD40B7B20BB0ACAF008626EC65F8F473D61EA2B336B512343C52941A6F98DAC0A543697E6122D09D833D8E3C5F2D7690BF7587166759579D5F3B0C26EBF4608CC846BCEF2B7366ABE3C1BFE28610FA94949D4F5512175180AEE782045C9BEE2C168A5CE23BE2FBA0AA47156F21F77FD11C135141DB40BE87028CACC12FCA3BC19CF83D17DF6E14DF931ADE786AB70137BD60F9A12CECA9F009115D3D429084500B5B1A82B31FADA1648557BAFF81FA4AB322C554D4EC38422917D31AE5225BAAB5D0A8053587E1A2C4778BEEF9178248BFA3E6DAC8E4748D9EB9A448D8ACC4979C77B5FAC477150DD8835A6E7D882BCDA0BB10095E0F1747439354B5C17476F6F7156F85981BE703529A3AE55881A2E99831A4379FC3F1CAB5AB00DB3B340722C5128021EFFD76C9CA7480384AFE80E720F8B0B53B8A127791B39E195F8427E8576182F67F794AEA65FA16F61F86E3C493A45FCE18DF03F8286CF1487CD9C4D792A2EE4AE9BDBB834B943CA042212289F59221340C2D85AAD6C71FC0F66FF2B6C1B60957D8410007657F085C9E442342B8A25B9E7F608085FAA744C9B37B4799BBB5892A3CFA40AC8B63A89E0CDA120BE8D9DF40E1F074A3053D8448514DD4C71C58A8FAF66B2A576E3A3EDA77DB4271B3ABBCE7B8B4BE12EB58EE9FBE6F676DFFA640EE40D01551348A412DBE0506935345347B471794B549361953550C70CC5373E3249D6D6D7BD8758D80ABEA6DAD9662DA44B09BA1326057CB2099330320725A8BA690906546609C6998469E122797E35399EA2CC1936D467D30FC55E6E24DAC353AE2F461C928B1D7EBDE9B489BFF98EC3E13136693586448A554DED33F3E9BC9AE091534C634659A97E5ABDB8B49E9E23BBBFD75E577910350F33C7901C67FC19E6ADC30C02104C17234369D3EC5A4021BDBFE331E19C2C1B6E9F2DA334FF06EFBD9E382352FF0822814AAA437D75BAD4C9E83E50BCA3053DFDAD299D13B0383BD80448189E909F30D95B3D9783DE643C4D4829B40C52234915B36DEC34E369FCCFB9AE6F6DFD2B8FB846BF82F6CD624CEA7F0CBC95B10D8FA91B9E288F635D3AE874C2D664B167E9D06AED4D618DEFE7A3F9902BBFCA86992A1ED9BCC408085704F039026405C29EC9371578F09DEDAEE3ECE92A5ADEBEE2A895BA7989F0D2E075AE9765C81E21B7FBDC8300B6D50A934D313448ECFA0AD73470038E6C1EC0D80A7A15C21096A1BC1F08A6ACE3B7200C3E8F8846B28848ABC36E8C0D03CB2E3F791C4FFA311EAD9809F1BB3B4D0894E3F4E446EAD18659DFFE69FC7F0C7DE9CC5DCE2C7D41E4A7BBA529B325E8F5857130AD8717C4DFA86279E959B0916D4E66A70DD98FC23F5DF15CB7DD6B8B550B060BFB23E0822D33FBFCB10B35EFE07C104D8A2D5C19D5D55A036761C83C78E509A4758A567FDB0720FF17CDDCB07BB607D726701418C0C8E6753EA8407A03E4E1DFBE0FBCDA3E06DFF57F1308019CC73BE4225B17A245782A93E029A8552E88CAF83FF45FC15F62DBF001E444F37500416229815BE02A9D069FD91DAC3
|
|
923 |
exponent:-352674
|
|
924 |
) < (LongFloat readFrom:'1q-500')
|
|
925 |
|
22041
|
926 |
4.0 asLargeFloat < 4.5 asLargeFloat
|
|
927 |
4.1 asLargeFloat < 4.2 asLargeFloat
|
|
928 |
4.1 asLargeFloat < 4.0 asLargeFloat
|
|
929 |
|
|
930 |
4.0 asLargeFloat < 8.0 asLargeFloat
|
|
931 |
|
|
932 |
1.0 asLargeFloat < 2.0 asLargeFloat
|
23739
|
933 |
1.0 asLargeFloat < 1.0 asLargeFloat
|
|
934 |
1.0 asLargeFloat > 1.0 asLargeFloat
|
|
935 |
1.0 asLargeFloat = 1.0 asLargeFloat
|
|
936 |
2.0 asLargeFloat < 1.0 asLargeFloatfalse
|
22041
|
937 |
3.0 asLargeFloat < 1.0 asLargeFloat
|
|
938 |
3.0 asLargeFloat < 2.0 asLargeFloat
|
|
939 |
|
|
940 |
5.0 asLargeFloat < 500.0 asLargeFloat
|
|
941 |
499.0 asLargeFloat < 500.0 asLargeFloat
|
|
942 |
|
|
943 |
5.0 asLargeFloat < 7.0 asLargeFloat
|
|
944 |
5.0 asLargeFloat < 17.0 asLargeFloat
|
|
945 |
|
|
946 |
"
|
|
947 |
|
22049
|
948 |
"Modified (comment): / 17-07-2017 / 16:38:59 / cg"
|
24202
|
949 |
"Modified: / 27-05-2019 / 16:39:49 / Claus Gittinger"
|
7445
|
950 |
!
|
|
951 |
|
|
952 |
productFromLargeFloat:aLargeFloat
|
|
953 |
|otherMantissa otherExponent|
|
|
954 |
|
|
955 |
otherMantissa := aLargeFloat mantissa.
|
24202
|
956 |
otherExponent := aLargeFloat biasedExponent.
|
7445
|
957 |
|
|
958 |
otherMantissa == 0 ifTrue:[
|
|
959 |
otherExponent ~= 0 ifTrue:[
|
|
960 |
"/ INF or NaN
|
|
961 |
aLargeFloat isNaN ifTrue:[^ NaN].
|
|
962 |
self negative ifTrue:[^ aLargeFloat negated].
|
|
963 |
^ aLargeFloat
|
|
964 |
].
|
|
965 |
].
|
|
966 |
mantissa == 0 ifTrue:[
|
24202
|
967 |
biasedExponent = 0 ifTrue:[^ self].
|
7445
|
968 |
"/ INF or NaN
|
|
969 |
self isNaN ifTrue:[^ NaN].
|
|
970 |
aLargeFloat negative ifTrue:[^ self negated].
|
|
971 |
^ self
|
|
972 |
].
|
|
973 |
|
|
974 |
^ self class
|
|
975 |
mantissa:(mantissa * otherMantissa)
|
24202
|
976 |
exponent:(biasedExponent + otherExponent)
|
7550
|
977 |
precision:(self precision min:aLargeFloat precision)
|
22041
|
978 |
|
|
979 |
"
|
|
980 |
5.0 asLargeFloat * 4
|
|
981 |
(5.0 asLargeFloat precision:20) * 4
|
|
982 |
"
|
|
983 |
|
|
984 |
"Modified (comment): / 17-07-2017 / 14:50:42 / cg"
|
24202
|
985 |
"Modified: / 27-05-2019 / 16:48:58 / Claus Gittinger"
|
7445
|
986 |
!
|
|
987 |
|
|
988 |
quotientFromLargeFloat:aLargeFloat
|
|
989 |
"Return the quotient of the argument, aLargeFloat and the receiver.
|
22299
|
990 |
(i.e. divide aLargeFloat by self)
|
7445
|
991 |
Sent when aLargeFloat does not know how to divide by the receiver."
|
|
992 |
|
22299
|
993 |
|otherMantissa otherExponent otherPrecision q e pMin limit prec n|
|
7445
|
994 |
|
|
995 |
otherMantissa := aLargeFloat mantissa.
|
24202
|
996 |
otherExponent := aLargeFloat biasedExponent.
|
22299
|
997 |
otherPrecision := aLargeFloat precision.
|
|
998 |
|
7445
|
999 |
otherMantissa == 0 ifTrue:[
|
|
1000 |
otherExponent = 0 ifTrue:[^ aLargeFloat].
|
|
1001 |
"/ INF or NaN
|
|
1002 |
aLargeFloat isNaN ifTrue:[^ NaN].
|
|
1003 |
self negative ifTrue:[^ aLargeFloat negated].
|
|
1004 |
^ aLargeFloat
|
|
1005 |
].
|
|
1006 |
mantissa == 0 ifTrue:[
|
24202
|
1007 |
biasedExponent = 0 ifTrue:[^ self].
|
7445
|
1008 |
"/ INF or NaN
|
|
1009 |
self isNaN ifTrue:[^ NaN].
|
|
1010 |
aLargeFloat negative ifTrue:[^ self negated].
|
|
1011 |
^ self
|
|
1012 |
].
|
22299
|
1013 |
|
|
1014 |
pMin := (otherPrecision min:precision).
|
|
1015 |
pMin isFinite ifFalse:[
|
|
1016 |
pMin := DefaultPrecision.
|
|
1017 |
].
|
|
1018 |
|
|
1019 |
"/ (m1 * (2^e1))
|
|
1020 |
"/ -------------
|
|
1021 |
"/ (m2 * (2^e2))
|
|
1022 |
|
|
1023 |
"/ (m1/m2) * (2^(e1-e2))
|
|
1024 |
|
24202
|
1025 |
e := (otherExponent - biasedExponent).
|
7445
|
1026 |
q := (otherMantissa / mantissa).
|
22299
|
1027 |
|
7445
|
1028 |
q isInteger ifFalse:[
|
22299
|
1029 |
"/ now q must be made an integer with at least pMin bits
|
|
1030 |
q := (otherMantissa bitShift:pMin) / mantissa.
|
|
1031 |
e := e - pMin.
|
22042
|
1032 |
|
22299
|
1033 |
q := q asInteger.
|
|
1034 |
(n := q lowBit - 1) > 0 ifTrue:[
|
|
1035 |
e > 0 ifTrue:[
|
|
1036 |
q := q rightShift:n.
|
|
1037 |
e := e - n.
|
|
1038 |
] ifFalse:[
|
|
1039 |
q := q rightShift:n.
|
|
1040 |
e := e + n.
|
|
1041 |
].
|
22042
|
1042 |
].
|
22299
|
1043 |
|
|
1044 |
"/ limit := pMin.
|
|
1045 |
"/ prec := 0.
|
|
1046 |
"/ [ q isInteger or:[ limit >= 0 ]] whileTrue:[
|
|
1047 |
"/ q := q * 2. e := e - 1.
|
|
1048 |
"/ prec := prec + 1.
|
|
1049 |
"/ limit := limit - 1.
|
|
1050 |
"/ ].
|
|
1051 |
"/ q isInteger ifFalse:[
|
|
1052 |
"/ pMin := prec.
|
|
1053 |
"/ q := q asInteger.
|
|
1054 |
"/ ].
|
7445
|
1055 |
].
|
|
1056 |
^ self class
|
|
1057 |
mantissa:q
|
22042
|
1058 |
exponent:e
|
22299
|
1059 |
precision:pMin
|
22042
|
1060 |
|
22299
|
1061 |
"Modified: / 10-10-2017 / 15:57:06 / cg"
|
24202
|
1062 |
"Modified: / 27-05-2019 / 16:40:09 / Claus Gittinger"
|
7445
|
1063 |
!
|
|
1064 |
|
|
1065 |
sumFromLargeFloat:aLargeFloat
|
|
1066 |
|otherExponent otherMantissa e m|
|
|
1067 |
|
24202
|
1068 |
otherExponent := aLargeFloat biasedExponent.
|
7445
|
1069 |
otherMantissa := aLargeFloat mantissa.
|
|
1070 |
|
|
1071 |
otherMantissa == 0 ifTrue:[
|
|
1072 |
otherExponent = 0 ifTrue:[^ self].
|
|
1073 |
"/ INF or NaN
|
|
1074 |
aLargeFloat isNaN ifTrue:[^ NaN].
|
|
1075 |
self isFinite ifTrue:[^ aLargeFloat].
|
|
1076 |
aLargeFloat sign == self sign ifTrue:[^ aLargeFloat].
|
|
1077 |
^ NaN
|
|
1078 |
].
|
|
1079 |
mantissa == 0 ifTrue:[
|
24202
|
1080 |
biasedExponent = 0 ifTrue:[^ aLargeFloat].
|
7445
|
1081 |
"/ INF or NaN
|
|
1082 |
self isNaN ifTrue:[^ NaN].
|
|
1083 |
^ self
|
|
1084 |
].
|
|
1085 |
|
24202
|
1086 |
otherExponent = biasedExponent ifTrue:[
|
7445
|
1087 |
m := otherMantissa + mantissa.
|
24202
|
1088 |
e := biasedExponent
|
7445
|
1089 |
] ifFalse:[
|
24202
|
1090 |
otherExponent> biasedExponent ifTrue:[
|
|
1091 |
m := (otherMantissa bitShift:(otherExponent-biasedExponent)) + mantissa.
|
|
1092 |
e := biasedExponent
|
7445
|
1093 |
] ifFalse:[
|
24202
|
1094 |
m := otherMantissa + (mantissa bitShift:(biasedExponent-otherExponent)).
|
7445
|
1095 |
e := otherExponent
|
|
1096 |
]
|
|
1097 |
].
|
|
1098 |
^ self class
|
|
1099 |
mantissa:m
|
|
1100 |
exponent:e
|
7550
|
1101 |
precision:(self precision min:aLargeFloat precision)
|
24202
|
1102 |
|
|
1103 |
"Modified: / 27-05-2019 / 16:40:13 / Claus Gittinger"
|
|
1104 |
! !
|
|
1105 |
|
24217
|
1106 |
!LargeFloat methodsFor:'initialization'!
|
|
1107 |
|
|
1108 |
setPrecisionTo: n
|
24220
|
1109 |
precision := n.
|
24217
|
1110 |
self roundToPrecision
|
|
1111 |
|
|
1112 |
"Modified: / 28-05-2019 / 11:22:21 / Claus Gittinger"
|
24220
|
1113 |
"Modified (format): / 28-05-2019 / 17:45:16 / Claus Gittinger"
|
24217
|
1114 |
! !
|
|
1115 |
|
24202
|
1116 |
!LargeFloat methodsFor:'mathematical functions'!
|
|
1117 |
|
24217
|
1118 |
agm: aNumber
|
24220
|
1119 |
"Answer the arithmetic geometric mean of self and aNumber"
|
|
1120 |
|
|
1121 |
| a b am gm |
|
|
1122 |
a := self.
|
|
1123 |
b := aNumber.
|
|
1124 |
|
|
1125 |
[am := a + b timesTwoPower: -1. "am is arithmetic mean"
|
|
1126 |
gm := (a * b) sqrt. "gm is geometric mean"
|
|
1127 |
a = am or: [b = gm]]
|
|
1128 |
whileFalse:
|
|
1129 |
[a := am.
|
|
1130 |
b := gm].
|
|
1131 |
^am
|
|
1132 |
|
|
1133 |
"Modified (format): / 28-05-2019 / 17:42:34 / Claus Gittinger"
|
24217
|
1134 |
!
|
|
1135 |
|
|
1136 |
arCosh
|
24220
|
1137 |
"Evaluate the area hyperbolic cosine of the receiver."
|
|
1138 |
|
|
1139 |
| arCosh x one y two |
|
|
1140 |
x := self asLargeFloatPrecision: 16 + precision.
|
|
1141 |
one := x one.
|
|
1142 |
x < one ifTrue: [DomainError signal: 'cannot compute arCosh of a number less than 1'].
|
|
1143 |
x = one ifTrue: [^self zero].
|
|
1144 |
y := x - one.
|
|
1145 |
y < one
|
|
1146 |
ifTrue:
|
|
1147 |
[y exponent * -4 >= precision
|
|
1148 |
ifTrue: [arCosh := (y powerExpansionArCoshp1Precision: y precision) * (y timesTwoPower: 1) sqrt]
|
|
1149 |
ifFalse:
|
|
1150 |
[two := one timesTwoPower: 1.
|
|
1151 |
arCosh := ((y * (y + two)) sqrt + y + one) ln]]
|
|
1152 |
ifFalse: [arCosh := ((x squared - one) sqrt + x) ln].
|
|
1153 |
^arCosh asLargeFloatPrecision: precision
|
|
1154 |
|
|
1155 |
"Modified (format): / 28-05-2019 / 17:42:40 / Claus Gittinger"
|
24217
|
1156 |
!
|
|
1157 |
|
|
1158 |
arSinh
|
24220
|
1159 |
"Evaluate the area hyperbolic sine of the receiver."
|
|
1160 |
|
|
1161 |
| arSinh x one |
|
|
1162 |
self isZero ifTrue: [^self].
|
|
1163 |
self exponent negated > precision ifTrue: [^self].
|
|
1164 |
x := self asLargeFloatPrecision: 16 + precision.
|
|
1165 |
x inPlaceAbs.
|
|
1166 |
self exponent * -4 >= precision
|
|
1167 |
ifTrue: [arSinh := x powerExpansionArSinhPrecision: x precision]
|
|
1168 |
ifFalse:
|
|
1169 |
[one := x one.
|
|
1170 |
arSinh := ((x squared + one) sqrt + x) ln].
|
|
1171 |
self negative ifTrue: [arSinh inPlaceNegated].
|
|
1172 |
^arSinh asLargeFloatPrecision: precision
|
|
1173 |
|
|
1174 |
"Modified (format): / 28-05-2019 / 17:42:45 / Claus Gittinger"
|
24217
|
1175 |
!
|
|
1176 |
|
|
1177 |
arTanh
|
24220
|
1178 |
"Evaluate the area hyperbolic tangent of the receiver."
|
|
1179 |
|
|
1180 |
| arTanh x one |
|
|
1181 |
self isZero ifTrue: [^self].
|
|
1182 |
x := self asLargeFloatPrecision: 16 + precision.
|
|
1183 |
x inPlaceAbs.
|
|
1184 |
one := x one.
|
|
1185 |
x >= one ifTrue: [DomainError signal: 'cannot evaluate arTanh of number of magnitude >= 1'].
|
|
1186 |
self exponent * -4 >= precision
|
|
1187 |
ifTrue: [arTanh := x powerExpansionArTanhPrecision: x precision]
|
|
1188 |
ifFalse:
|
|
1189 |
[arTanh := ((one + x) / (one - x)) ln.
|
|
1190 |
arTanh inPlaceTimesTwoPower: -1].
|
|
1191 |
self negative ifTrue: [arTanh inPlaceNegated].
|
|
1192 |
^arTanh asLargeFloatPrecision: precision
|
|
1193 |
|
|
1194 |
"Modified (format): / 28-05-2019 / 17:42:49 / Claus Gittinger"
|
24217
|
1195 |
!
|
|
1196 |
|
|
1197 |
arcCos
|
24218
|
1198 |
"Evaluate the arc cosine of the receiver."
|
|
1199 |
|
|
1200 |
| arcCos x one |
|
|
1201 |
self isZero ifTrue: [^(self pi timesTwoPower: -1)].
|
|
1202 |
x := self asLargeFloatPrecision: 16 + precision.
|
|
1203 |
x inPlaceAbs.
|
|
1204 |
one := x one.
|
|
1205 |
x > one ifTrue: [DomainError signal: 'cannot compute arcCos of a number greater than 1'].
|
|
1206 |
arcCos := x = one
|
|
1207 |
ifTrue: [self zero]
|
|
1208 |
ifFalse: [((one - x squared) sqrt / x) arcTan].
|
|
1209 |
self negative ifTrue: [arcCos := x pi - arcCos].
|
|
1210 |
^arcCos asLargeFloatPrecision: precision
|
|
1211 |
|
|
1212 |
"Modified (format): / 28-05-2019 / 16:15:15 / Claus Gittinger"
|
24217
|
1213 |
!
|
|
1214 |
|
|
1215 |
arcSin
|
24218
|
1216 |
"Evaluate the arc sine of the receiver."
|
|
1217 |
|
|
1218 |
| arcSin x one |
|
|
1219 |
self isZero ifTrue: [^self].
|
|
1220 |
x := self asLargeFloatPrecision: 16 + precision.
|
|
1221 |
x inPlaceAbs.
|
|
1222 |
one := x one.
|
|
1223 |
x > one ifTrue: [DomainError signal: 'cannot compute arcSin of a number greater than 1'].
|
|
1224 |
arcSin := x = one
|
|
1225 |
ifTrue: [self pi timesTwoPower: -1]
|
|
1226 |
ifFalse: [self exponent * -4 >= precision
|
|
1227 |
ifTrue: [x powerExpansionArcSinPrecision: x precision]
|
|
1228 |
ifFalse: [(x / (one - x squared) sqrt) arcTan]].
|
|
1229 |
self negative ifTrue: [arcSin inPlaceNegated].
|
|
1230 |
^arcSin asLargeFloatPrecision: precision
|
|
1231 |
|
|
1232 |
"Modified (format): / 28-05-2019 / 16:15:21 / Claus Gittinger"
|
24217
|
1233 |
!
|
|
1234 |
|
|
1235 |
arcTan
|
24218
|
1236 |
"Evaluate the arc tangent of the receiver."
|
|
1237 |
|
|
1238 |
| x arcTan one power |
|
|
1239 |
self isZero ifTrue: [^self].
|
|
1240 |
self > 1
|
|
1241 |
ifTrue:
|
|
1242 |
[x := self asLargeFloatPrecision: precision * 2 + 2.
|
|
1243 |
x inPlaceAbs.
|
|
1244 |
arcTan := (x pi timesTwoPower: -1) - x reciprocal arcTan]
|
|
1245 |
ifFalse:
|
|
1246 |
[power := ((precision bitShift: -1) + self exponent max: 4) highBit.
|
|
1247 |
x := self asLargeFloatPrecision: precision + (1 bitShift: 1 + power).
|
|
1248 |
x inPlaceAbs.
|
|
1249 |
one := x one.
|
|
1250 |
power timesRepeat: [x := x / (one + (one + x squared) sqrt)].
|
|
1251 |
arcTan := x powerExpansionArcTanPrecision: x precision + 6.
|
|
1252 |
arcTan inPlaceTimesTwoPower: power].
|
|
1253 |
self negative ifTrue: [arcTan inPlaceNegated].
|
|
1254 |
^arcTan asLargeFloatPrecision: precision
|
|
1255 |
|
|
1256 |
"Modified (format): / 28-05-2019 / 16:15:28 / Claus Gittinger"
|
24217
|
1257 |
!
|
|
1258 |
|
|
1259 |
arcTan: denominator
|
24218
|
1260 |
"Evaluate the four quadrant arc tangent of the argument denominator (x) and the receiver (y)."
|
|
1261 |
|
|
1262 |
self isZero
|
|
1263 |
ifTrue: [denominator sign positive
|
|
1264 |
ifTrue: [ ^(self + denominator) zero ]
|
|
1265 |
ifFalse: [ self positive
|
|
1266 |
ifTrue: [ ^(self + denominator) pi ]
|
|
1267 |
ifFalse: [ ^(self + denominator) pi negated ]]]
|
|
1268 |
ifFalse: [denominator isZero
|
|
1269 |
ifTrue: [self positive
|
|
1270 |
ifTrue: [ ^(self + denominator) pi timesTwoPower: -1 ]
|
|
1271 |
ifFalse: [ ^(self + denominator) pi negated timesTwoPower: -1 ]]
|
|
1272 |
ifFalse:
|
|
1273 |
[ | precision arcTan |
|
|
1274 |
precision := (self + denominator) precision.
|
|
1275 |
arcTan := ((self asLargeFloatPrecision: precision * 2) / (denominator asLargeFloatPrecision: precision * 2)) arcTan.
|
|
1276 |
(denominator > 0
|
|
1277 |
ifTrue: [ ^arcTan ]
|
|
1278 |
ifFalse: [ self > 0
|
|
1279 |
ifTrue: [ ^arcTan + arcTan pi ]
|
|
1280 |
ifFalse: [ ^arcTan - arcTan pi ]]) asLargeFloatPrecision: precision]]
|
|
1281 |
|
|
1282 |
"Modified: / 28-05-2019 / 16:16:32 / Claus Gittinger"
|
24217
|
1283 |
!
|
|
1284 |
|
|
1285 |
cos
|
24218
|
1286 |
"Evaluate the cosine of the receiver"
|
|
1287 |
|
|
1288 |
| pi halfPi quarterPi x neg |
|
|
1289 |
x := self moduloNegPiToPi.
|
|
1290 |
x inPlaceAbs.
|
|
1291 |
pi := self piDoublePrecision.
|
|
1292 |
halfPi := pi timesTwoPower: -1.
|
|
1293 |
(neg := x > halfPi) ifTrue: [x inPlaceSubtract: pi; inPlaceNegated].
|
|
1294 |
quarterPi := halfPi timesTwoPower: -1.
|
|
1295 |
x > quarterPi
|
|
1296 |
ifTrue:
|
|
1297 |
[x inPlaceSubtract: halfPi; inPlaceNegated.
|
|
1298 |
x := self sin: x]
|
|
1299 |
ifFalse: [x := self cos: x].
|
|
1300 |
neg ifTrue: [x inPlaceNegated].
|
|
1301 |
^x asLargeFloatPrecision: precision
|
|
1302 |
|
|
1303 |
"Modified (format): / 28-05-2019 / 16:17:03 / Claus Gittinger"
|
24217
|
1304 |
!
|
|
1305 |
|
|
1306 |
cosh
|
24218
|
1307 |
| e x |
|
|
1308 |
self isZero ifTrue: [^self one].
|
|
1309 |
self exponent negated > precision ifTrue: [^self one].
|
|
1310 |
x := self asLargeFloatPrecision: precision + 16.
|
|
1311 |
self exponent * -4 >= precision
|
|
1312 |
ifTrue: [^(x powerExpansionCoshPrecision: x precision) asLargeFloatPrecision: precision].
|
|
1313 |
e := x exp.
|
|
1314 |
^e
|
|
1315 |
inPlaceAdd: e reciprocal;
|
|
1316 |
inPlaceTimesTwoPower: -1;
|
|
1317 |
asLargeFloatPrecision: precision
|
|
1318 |
|
|
1319 |
"Modified (format): / 28-05-2019 / 16:17:10 / Claus Gittinger"
|
24217
|
1320 |
!
|
|
1321 |
|
|
1322 |
exp
|
24220
|
1323 |
"Answer the exponential of the receiver."
|
|
1324 |
|
|
1325 |
| ln2 x q r ri res n maxIter p one two |
|
|
1326 |
one := self one.
|
|
1327 |
two := one timesTwoPower: 1.
|
|
1328 |
"Use following decomposition:
|
|
1329 |
x exp = (2 ln * q + r) exp.
|
|
1330 |
x exp = (2**q * r exp)"
|
|
1331 |
ln2 := two ln.
|
|
1332 |
x := self / ln2.
|
|
1333 |
q := x truncated.
|
|
1334 |
r := (x - q) * ln2.
|
|
1335 |
|
|
1336 |
"now compute r exp by power series expansion
|
|
1337 |
we compute (r/(2**p)) exp ** (2**p) in order to have faster convergence"
|
|
1338 |
p := 10 min: precision // 2.
|
|
1339 |
r := r timesTwoPower: p negated.
|
|
1340 |
ri := one asLargeFloatPrecision: precision + 16.
|
|
1341 |
res := ri copy.
|
|
1342 |
n := 0.
|
|
1343 |
maxIter := 1 + ((precision + 16) / p) ceiling.
|
|
1344 |
[n <= maxIter] whileTrue:
|
|
1345 |
[n := n + 1.
|
|
1346 |
ri inPlaceMultiplyBy: r / n.
|
|
1347 |
res inPlaceAdd: ri].
|
|
1348 |
p timesRepeat: [res inPlaceMultiplyBy: res].
|
|
1349 |
res inPlaceTimesTwoPower: q.
|
|
1350 |
|
|
1351 |
"now use a Newton iteration to refine the result
|
|
1352 |
res = res * (self - res ln + 1)"
|
|
1353 |
[| oldres delta |
|
|
1354 |
oldres := res.
|
|
1355 |
res := res asLargeFloatPrecision: res precision + 32.
|
|
1356 |
res inPlaceMultiplyBy: self - res ln + 1.
|
|
1357 |
delta := (res - oldres) exponent.
|
|
1358 |
delta = 0 or: [delta <= (res exponent - precision - 8)]]
|
|
1359 |
whileFalse.
|
|
1360 |
|
|
1361 |
^res asLargeFloatPrecision: precision
|
|
1362 |
|
|
1363 |
"Modified (comment): / 28-05-2019 / 17:43:06 / Claus Gittinger"
|
24217
|
1364 |
!
|
|
1365 |
|
24202
|
1366 |
ln
|
24220
|
1367 |
"Answer the neperian logarithm of the receiver."
|
|
1368 |
|
|
1369 |
| x4 one two p res selfHighRes prec e |
|
|
1370 |
self <= self zero ifTrue: [DomainError signal: 'ln is only defined for x > 0.0'].
|
|
1371 |
|
|
1372 |
one := self one.
|
|
1373 |
self = one ifTrue: [^self zero].
|
|
1374 |
two := one timesTwoPower: 1.
|
|
1375 |
|
|
1376 |
"Use Salamin algorithm (approximation is good if x is big enough)
|
|
1377 |
x ln = Pi / (2 * (1 agm: 4/x) ).
|
|
1378 |
If x not big enough, compute (x timesTwoPower: p) ln - (2 ln * p)
|
|
1379 |
if x is close to 1, better use a power expansion"
|
|
1380 |
prec := precision + 16.
|
|
1381 |
e := self exponent.
|
|
1382 |
e < 0 ifTrue: [e := -1 - e].
|
|
1383 |
e > prec
|
|
1384 |
ifTrue: [p := 0]
|
|
1385 |
ifFalse:
|
|
1386 |
[p := prec - e.
|
|
1387 |
prec := prec + p highBit].
|
|
1388 |
selfHighRes := self asLargeFloatPrecision: prec.
|
|
1389 |
(selfHighRes - one) exponent * -4 >= precision ifTrue: [^(selfHighRes powerExpansionLnPrecision: prec) asLargeFloatPrecision: precision].
|
|
1390 |
self < one ifTrue: [selfHighRes inPlaceReciprocal]. "Use ln(1/x) => - ln(x)"
|
|
1391 |
x4 := (4 asLargeFloatPrecision: prec)
|
|
1392 |
inPlaceDivideBy: selfHighRes;
|
|
1393 |
inPlaceTimesTwoPower: p negated.
|
|
1394 |
res := selfHighRes pi / (one agm: x4) timesTwoPower: -1.
|
|
1395 |
res := selfHighRes = two
|
|
1396 |
ifTrue: [res / (p + 1)]
|
|
1397 |
ifFalse: [p = 0 ifTrue: [res] ifFalse: [res - ((two asLargeFloatPrecision: prec) ln * p)]].
|
|
1398 |
self < one ifTrue: [res inPlaceNegated].
|
|
1399 |
^res asLargeFloatPrecision: precision
|
|
1400 |
|
|
1401 |
"Modified (comment): / 28-05-2019 / 17:43:30 / Claus Gittinger"
|
24217
|
1402 |
!
|
|
1403 |
|
|
1404 |
sin
|
24218
|
1405 |
"Evaluate the sine of the receiver"
|
|
1406 |
|
|
1407 |
| pi halfPi quarterPi x neg |
|
|
1408 |
x := self moduloNegPiToPi.
|
|
1409 |
neg := x negative.
|
|
1410 |
x inPlaceAbs.
|
|
1411 |
pi := self piDoublePrecision.
|
|
1412 |
halfPi := pi timesTwoPower: -1.
|
|
1413 |
x > halfPi ifTrue: [x inPlaceSubtract: pi; inPlaceNegated].
|
|
1414 |
quarterPi := halfPi timesTwoPower: -1.
|
|
1415 |
x > quarterPi
|
|
1416 |
ifTrue:
|
|
1417 |
[x inPlaceSubtract: halfPi; inPlaceNegated.
|
|
1418 |
x := self cos: x]
|
|
1419 |
ifFalse: [x := self sin: x].
|
|
1420 |
neg ifTrue: [x inPlaceNegated].
|
|
1421 |
^x asLargeFloatPrecision: precision
|
|
1422 |
|
|
1423 |
"Modified (format): / 28-05-2019 / 16:18:20 / Claus Gittinger"
|
24217
|
1424 |
!
|
|
1425 |
|
|
1426 |
sincos
|
24220
|
1427 |
"Evaluate the sine and cosine of the receiver"
|
|
1428 |
|
|
1429 |
| pi halfPi quarterPi x sincos sinneg cosneg |
|
|
1430 |
x := self moduloNegPiToPi.
|
|
1431 |
sinneg := x negative.
|
|
1432 |
x inPlaceAbs.
|
|
1433 |
pi := self piDoublePrecision.
|
|
1434 |
halfPi := pi timesTwoPower: -1.
|
|
1435 |
(cosneg := x > halfPi) ifTrue: [x inPlaceSubtract: pi; inPlaceNegated].
|
|
1436 |
quarterPi := halfPi timesTwoPower: -1.
|
|
1437 |
x > quarterPi
|
|
1438 |
ifTrue:
|
|
1439 |
[x inPlaceSubtract: halfPi; inPlaceNegated.
|
|
1440 |
sincos := (self sincos: x) reversed]
|
|
1441 |
ifFalse:
|
|
1442 |
[sincos := self sincos: x].
|
|
1443 |
sinneg ifTrue: [sincos first inPlaceNegated].
|
|
1444 |
cosneg ifTrue: [sincos last inPlaceNegated].
|
|
1445 |
^sincos collect: [:e| e asLargeFloatPrecision: precision]
|
|
1446 |
|
|
1447 |
"Modified (format): / 28-05-2019 / 17:45:28 / Claus Gittinger"
|
24217
|
1448 |
!
|
|
1449 |
|
|
1450 |
sinh
|
24218
|
1451 |
| e x |
|
|
1452 |
self isZero ifTrue: [^self].
|
|
1453 |
self exponent negated > precision ifTrue: [^self].
|
|
1454 |
x := self asLargeFloatPrecision: precision + 16.
|
|
1455 |
self exponent * -4 >= precision
|
|
1456 |
ifTrue: [^(x powerExpansionSinhPrecision: x precision) asLargeFloatPrecision: precision].
|
|
1457 |
e := x exp.
|
|
1458 |
^e
|
|
1459 |
inPlaceSubtract: e reciprocal;
|
|
1460 |
inPlaceTimesTwoPower: -1;
|
|
1461 |
asLargeFloatPrecision: precision
|
|
1462 |
|
|
1463 |
"Modified (format): / 28-05-2019 / 16:18:25 / Claus Gittinger"
|
24217
|
1464 |
!
|
|
1465 |
|
|
1466 |
sqrt
|
|
1467 |
"Answer the square root of the receiver."
|
|
1468 |
|
|
1469 |
| decimalPlaces n norm guess previousGuess one stopIteration |
|
|
1470 |
self negative
|
|
1471 |
ifTrue:
|
|
1472 |
[^ DomainError signal: 'sqrt undefined for number less than zero.'].
|
|
1473 |
self isZero ifTrue: [^self].
|
|
1474 |
|
|
1475 |
"use additional bits"
|
24220
|
1476 |
decimalPlaces := precision + 16.
|
|
1477 |
n := self asLargeFloatPrecision: decimalPlaces.
|
24202
|
1478 |
|
24217
|
1479 |
"constants"
|
24220
|
1480 |
one := n one.
|
24217
|
1481 |
|
|
1482 |
"normalize n"
|
24220
|
1483 |
norm := n exponent quo: 2.
|
|
1484 |
n := n timesTwoPower: norm * -2.
|
24217
|
1485 |
|
|
1486 |
"Initial guess for sqrt(1/n)"
|
24220
|
1487 |
previousGuess := self class
|
24217
|
1488 |
mantissa: 3
|
|
1489 |
exponent: -2 - (n exponent quo: 2)
|
|
1490 |
precision: decimalPlaces.
|
24220
|
1491 |
guess := previousGuess copy.
|
|
1492 |
|
|
1493 |
"use iterations x(k+1) := x*( 1 + (1-x*x*n)/2) to guess sqrt(1/n)"
|
24217
|
1494 |
|
|
1495 |
[guess inPlaceMultiplyNoRoundBy: guess.
|
|
1496 |
guess inPlaceMultiplyBy: n.
|
|
1497 |
guess inPlaceNegated.
|
|
1498 |
guess inPlaceAddNoRound: one.
|
|
1499 |
|
|
1500 |
"stop when no evolution of precision + 12 first bits"
|
24220
|
1501 |
stopIteration := guess isZero or: [guess exponent < (decimalPlaces - 4) negated].
|
24217
|
1502 |
guess inPlaceTimesTwoPower: -1.
|
|
1503 |
guess inPlaceAddNoRound: one.
|
|
1504 |
guess inPlaceMultiplyNoRoundBy: previousGuess.
|
|
1505 |
guess negative ifTrue: [guess inPlaceNegated].
|
|
1506 |
|
|
1507 |
guess isZero or: [stopIteration]]
|
|
1508 |
whileFalse:
|
|
1509 |
[guess roundToPrecision.
|
|
1510 |
previousGuess inPlaceCopy: guess].
|
|
1511 |
|
|
1512 |
"multiply by n and un-normalize"
|
|
1513 |
guess inPlaceMultiplyBy: n.
|
|
1514 |
guess inPlaceTimesTwoPower: norm.
|
|
1515 |
^guess asLargeFloatPrecision: precision
|
|
1516 |
|
|
1517 |
"Modified: / 28-05-2019 / 11:22:33 / Claus Gittinger"
|
24220
|
1518 |
"Modified (comment): / 28-05-2019 / 17:45:39 / Claus Gittinger"
|
24217
|
1519 |
!
|
|
1520 |
|
|
1521 |
tan
|
24218
|
1522 |
"Evaluate the tangent of the receiver"
|
|
1523 |
|
|
1524 |
| pi halfPi quarterPi x sincos neg tan |
|
|
1525 |
x := self moduloNegPiToPi.
|
|
1526 |
neg := x negative.
|
|
1527 |
x inPlaceAbs.
|
|
1528 |
pi := self piDoublePrecision.
|
|
1529 |
halfPi := pi timesTwoPower: -1.
|
|
1530 |
(x > halfPi)
|
|
1531 |
ifTrue:
|
|
1532 |
[x inPlaceSubtract: pi; inPlaceNegated.
|
|
1533 |
neg := neg not].
|
|
1534 |
x exponent * -4 >= precision
|
|
1535 |
ifTrue: [tan := x powerExpansionTanPrecision: x precision]
|
|
1536 |
ifFalse:
|
|
1537 |
[quarterPi := halfPi timesTwoPower: -1.
|
|
1538 |
x > quarterPi
|
|
1539 |
ifTrue:
|
|
1540 |
[x inPlaceSubtract: halfPi; inPlaceNegated.
|
|
1541 |
sincos := (self sincos: x) reversed]
|
|
1542 |
ifFalse:
|
|
1543 |
[sincos := self sincos: x].
|
|
1544 |
sincos first inPlaceDivideBy: sincos last.
|
|
1545 |
tan := sincos first].
|
|
1546 |
neg ifTrue: [tan inPlaceNegated].
|
|
1547 |
^tan asLargeFloatPrecision: precision
|
|
1548 |
|
|
1549 |
"Modified (format): / 28-05-2019 / 16:18:37 / Claus Gittinger"
|
24217
|
1550 |
!
|
|
1551 |
|
|
1552 |
tanh
|
24218
|
1553 |
| e x ep one |
|
|
1554 |
self isZero ifTrue: [^self].
|
|
1555 |
self exponent negated > precision ifTrue: [^self].
|
|
1556 |
x := self asLargeFloatPrecision: precision + 16.
|
|
1557 |
self exponent * -4 >= precision
|
|
1558 |
ifTrue: [^(x powerExpansionTanhPrecision: x precision) asLargeFloatPrecision: precision].
|
|
1559 |
e := x exp.
|
|
1560 |
one :=x one.
|
|
1561 |
e inPlaceMultiplyBy: e.
|
|
1562 |
ep := e + one.
|
|
1563 |
^e
|
|
1564 |
inPlaceSubtract: one;
|
|
1565 |
inPlaceDivideBy: ep;
|
|
1566 |
asLargeFloatPrecision: precision
|
|
1567 |
|
|
1568 |
"Modified (format): / 28-05-2019 / 16:18:42 / Claus Gittinger"
|
7445
|
1569 |
! !
|
|
1570 |
|
|
1571 |
!LargeFloat methodsFor:'printing'!
|
|
1572 |
|
24217
|
1573 |
absPrintExactlyOn: aStream base: base
|
24218
|
1574 |
"Print my value on a stream in the given base.
|
|
1575 |
Based upon the algorithm outlined in:
|
|
1576 |
Robert G. Burger and R. Kent Dybvig
|
|
1577 |
Printing Floating Point Numbers Quickly and Accurately
|
|
1578 |
ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation
|
|
1579 |
June 1996.
|
|
1580 |
This version guarantees that the printed representation exactly represents my value
|
|
1581 |
by using exact integer arithmetic."
|
|
1582 |
|
|
1583 |
| fBase significand exp baseExpEstimate r s mPlus mMinus scale roundingIncludesLimits d tc1 tc2 fixedFormat decPointCount shead slowbit |
|
|
1584 |
fBase := base asFloat.
|
|
1585 |
self normalize.
|
|
1586 |
significand := mantissa abs.
|
|
1587 |
roundingIncludesLimits := significand even.
|
|
1588 |
exp := biasedExponent.
|
|
1589 |
baseExpEstimate := (self exponent * fBase reciprocalLogBase2 - 1.0e-10) ceiling.
|
|
1590 |
exp >= 0
|
|
1591 |
ifTrue:
|
|
1592 |
[significand isPowerOfTwo
|
|
1593 |
ifTrue:
|
|
1594 |
[r := significand bitShift: 2 + exp.
|
|
1595 |
s := 4.
|
|
1596 |
mPlus := 2 * (mMinus := 1 bitShift: exp)]
|
|
1597 |
ifFalse:
|
|
1598 |
[r := significand bitShift: 1 + exp.
|
|
1599 |
s := 2.
|
|
1600 |
mPlus := mMinus := 1 bitShift: exp]]
|
|
1601 |
ifFalse:
|
|
1602 |
[significand isPowerOfTwo
|
|
1603 |
ifTrue:
|
|
1604 |
[r := significand bitShift: 2.
|
|
1605 |
s := 1 bitShift: 2 - exp.
|
|
1606 |
mPlus := 2.
|
|
1607 |
mMinus := 1]
|
|
1608 |
ifFalse:
|
|
1609 |
[r := significand bitShift: 1.
|
|
1610 |
s := 1 bitShift: 1 - exp.
|
|
1611 |
mPlus := mMinus := 1]].
|
|
1612 |
baseExpEstimate >= 0
|
|
1613 |
ifTrue: [s := s * (base raisedToInteger: baseExpEstimate)]
|
|
1614 |
ifFalse:
|
|
1615 |
[scale := base raisedToInteger: baseExpEstimate negated.
|
|
1616 |
r := r * scale.
|
|
1617 |
mPlus := mPlus * scale.
|
|
1618 |
mMinus := mMinus * scale].
|
|
1619 |
((r + mPlus >= s) and: [roundingIncludesLimits or: [r + mPlus > s]])
|
|
1620 |
ifTrue: [baseExpEstimate := baseExpEstimate + 1]
|
|
1621 |
ifFalse:
|
|
1622 |
[r := r * base.
|
|
1623 |
mPlus := mPlus * base.
|
|
1624 |
mMinus := mMinus * base].
|
|
1625 |
(fixedFormat := baseExpEstimate between: -3 and: 6)
|
|
1626 |
ifTrue:
|
|
1627 |
[decPointCount := baseExpEstimate.
|
|
1628 |
baseExpEstimate <= 0
|
|
1629 |
ifTrue: [aStream nextPutAll: ('0.000000' truncateTo: 2 - baseExpEstimate)]]
|
|
1630 |
ifFalse:
|
|
1631 |
[decPointCount := 1].
|
|
1632 |
slowbit := 1 - s lowBit .
|
|
1633 |
shead := s bitShift: slowbit.
|
|
1634 |
[d := (r bitShift: slowbit) // shead.
|
|
1635 |
r := r - (d * s).
|
|
1636 |
(tc1 := (r <= mMinus) and: [roundingIncludesLimits or: [r < mMinus]]) |
|
|
1637 |
(tc2 := (r + mPlus >= s) and: [roundingIncludesLimits or: [r + mPlus > s]])] whileFalse:
|
|
1638 |
[aStream nextPut: (Character digitValue: d).
|
|
1639 |
r := r * base.
|
|
1640 |
mPlus := mPlus * base.
|
|
1641 |
mMinus := mMinus * base.
|
|
1642 |
decPointCount := decPointCount - 1.
|
|
1643 |
decPointCount = 0 ifTrue: [aStream nextPut: $.]].
|
|
1644 |
tc2 ifTrue:
|
|
1645 |
[(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]].
|
|
1646 |
aStream nextPut: (Character digitValue: d).
|
|
1647 |
decPointCount > 0
|
|
1648 |
ifTrue:
|
|
1649 |
[decPointCount - 1 to: 1 by: -1 do: [:i | aStream nextPut: $0].
|
|
1650 |
aStream nextPutAll: '.0'].
|
|
1651 |
fixedFormat ifFalse:
|
|
1652 |
[aStream nextPut: $e.
|
|
1653 |
aStream nextPutAll: (baseExpEstimate - 1) printString]
|
|
1654 |
|
|
1655 |
"Modified (comment): / 28-05-2019 / 16:15:05 / Claus Gittinger"
|
24217
|
1656 |
!
|
|
1657 |
|
|
1658 |
asMinimalDecimalFraction
|
24218
|
1659 |
"Answer the shortest decimal Fraction that will equal self when converted back asFloat.
|
|
1660 |
A decimal Fraction has only powers of 2 and 5 as decnominator.
|
|
1661 |
For example, 0.1 asMinimalDecimalFraction = (1/10)."
|
|
1662 |
|
|
1663 |
| significand exp baseExpEstimate r s mPlus mMinus scale roundingIncludesLimits d tc1 tc2 fixedFormat decPointCount shead slowbit numerator denominator |
|
|
1664 |
self isZero ifTrue: [^0].
|
|
1665 |
self negative ifTrue: [^self negated asMinimalDecimalFraction negated].
|
|
1666 |
self normalize.
|
|
1667 |
significand := mantissa abs.
|
|
1668 |
roundingIncludesLimits := significand even.
|
|
1669 |
exp := biasedExponent.
|
|
1670 |
baseExpEstimate := (self exponent * 10.0 reciprocalLogBase2 - 1.0e-10) ceiling.
|
|
1671 |
numerator := 0.
|
|
1672 |
denominator := 0.
|
|
1673 |
exp >= 0
|
|
1674 |
ifTrue:
|
|
1675 |
[significand isPowerOfTwo
|
|
1676 |
ifTrue:
|
|
1677 |
[r := significand bitShift: 2 + exp.
|
|
1678 |
s := 4.
|
|
1679 |
mPlus := 2 * (mMinus := 1 bitShift: exp)]
|
|
1680 |
ifFalse:
|
|
1681 |
[r := significand bitShift: 1 + exp.
|
|
1682 |
s := 2.
|
|
1683 |
mPlus := mMinus := 1 bitShift: exp]]
|
|
1684 |
ifFalse:
|
|
1685 |
[significand isPowerOfTwo
|
|
1686 |
ifTrue:
|
|
1687 |
[r := significand bitShift: 2.
|
|
1688 |
s := 1 bitShift: 2 - exp.
|
|
1689 |
mPlus := 2.
|
|
1690 |
mMinus := 1]
|
|
1691 |
ifFalse:
|
|
1692 |
[r := significand bitShift: 1.
|
|
1693 |
s := 1 bitShift: 1 - exp.
|
|
1694 |
mPlus := mMinus := 1]].
|
|
1695 |
baseExpEstimate >= 0
|
|
1696 |
ifTrue: [s := s * (10 raisedToInteger: baseExpEstimate)]
|
|
1697 |
ifFalse:
|
|
1698 |
[scale := 10 raisedToInteger: baseExpEstimate negated.
|
|
1699 |
r := r * scale.
|
|
1700 |
mPlus := mPlus * scale.
|
|
1701 |
mMinus := mMinus * scale].
|
|
1702 |
((r + mPlus >= s) and: [roundingIncludesLimits or: [r + mPlus > s]])
|
|
1703 |
ifTrue: [baseExpEstimate := baseExpEstimate + 1]
|
|
1704 |
ifFalse:
|
|
1705 |
[r := r * 10.
|
|
1706 |
mPlus := mPlus * 10.
|
|
1707 |
mMinus := mMinus * 10].
|
|
1708 |
(fixedFormat := baseExpEstimate between: -3 and: 6)
|
|
1709 |
ifTrue:
|
|
1710 |
[decPointCount := baseExpEstimate.
|
|
1711 |
baseExpEstimate <= 0
|
|
1712 |
ifTrue: [denominator := 10 raisedTo: baseExpEstimate negated]]
|
|
1713 |
ifFalse:
|
|
1714 |
[decPointCount := 1].
|
|
1715 |
slowbit := 1 - s lowBit .
|
|
1716 |
shead := s bitShift: slowbit.
|
|
1717 |
[d := (r bitShift: slowbit) // shead.
|
|
1718 |
r := r - (d * s).
|
|
1719 |
(tc1 := (r <= mMinus) and: [roundingIncludesLimits or: [r < mMinus]]) |
|
|
1720 |
(tc2 := (r + mPlus >= s) and: [roundingIncludesLimits or: [r + mPlus > s]])] whileFalse:
|
|
1721 |
[numerator := 10 * numerator + d.
|
|
1722 |
denominator := 10 * denominator.
|
|
1723 |
r := r * 10.
|
|
1724 |
mPlus := mPlus * 10.
|
|
1725 |
mMinus := mMinus * 10.
|
|
1726 |
decPointCount := decPointCount - 1.
|
|
1727 |
decPointCount = 0 ifTrue: [denominator := 1]].
|
|
1728 |
tc2 ifTrue:
|
|
1729 |
[(tc1 not or: [r * 2 >= s]) ifTrue: [d := d + 1]].
|
|
1730 |
numerator := 10 * numerator + d.
|
|
1731 |
denominator := 10 * denominator.
|
|
1732 |
decPointCount > 0
|
|
1733 |
ifTrue:
|
|
1734 |
[numerator := (10 raisedTo: decPointCount - 1) * numerator].
|
|
1735 |
fixedFormat ifFalse:
|
|
1736 |
[(baseExpEstimate - 1) > 0
|
|
1737 |
ifTrue: [numerator := (10 raisedTo: baseExpEstimate - 1) * numerator]
|
|
1738 |
ifFalse: [denominator := (10 raisedTo: 1 - baseExpEstimate) * (denominator max: 1)]].
|
|
1739 |
denominator < 2 ifTrue: [^numerator].
|
|
1740 |
^numerator / denominator
|
|
1741 |
|
|
1742 |
"Modified (comment): / 28-05-2019 / 16:16:57 / Claus Gittinger"
|
24217
|
1743 |
!
|
|
1744 |
|
7445
|
1745 |
printOn:aStream
|
24202
|
1746 |
biasedExponent == 0 ifTrue:[
|
7445
|
1747 |
mantissa printOn:aStream.
|
|
1748 |
aStream nextPutAll:'.0'.
|
|
1749 |
^ self
|
|
1750 |
].
|
|
1751 |
mantissa == 0 ifTrue:[
|
22299
|
1752 |
"/ a zero mantissa is impossible - except for zero and a few others
|
24202
|
1753 |
biasedExponent == 0 ifTrue:[ aStream nextPutAll:'0.0'. ^ self].
|
7445
|
1754 |
self == NaN ifTrue:[ aStream nextPutAll:'NAN'. ^ self ].
|
|
1755 |
self == NegativeInfinity ifTrue:[ aStream nextPutAll:'-INF'. ^ self].
|
|
1756 |
self == PositiveInfinity ifTrue:[ aStream nextPutAll:'INF'. ^ self].
|
22299
|
1757 |
|
7550
|
1758 |
self error:'invalid largeFloat' mayProceed:true.
|
|
1759 |
aStream nextPutAll:'Invalid'. ^ self.
|
7445
|
1760 |
].
|
|
1761 |
|
24202
|
1762 |
biasedExponent >= 0 ifTrue:[
|
|
1763 |
(mantissa bitShift:biasedExponent) printOn:aStream.
|
7445
|
1764 |
aStream nextPutAll:'.0'.
|
|
1765 |
^ self
|
|
1766 |
].
|
24202
|
1767 |
((mantissa / (1 bitShift:biasedExponent negated)) asFixedPoint:6) printOn:aStream.
|
7550
|
1768 |
|
24217
|
1769 |
"Modified: / 28-05-2019 / 11:23:22 / Claus Gittinger"
|
|
1770 |
!
|
|
1771 |
|
|
1772 |
printOn: aStream base: base
|
|
1773 |
self negative ifTrue: [aStream nextPut: $-].
|
|
1774 |
self absPrintExactlyOn: aStream base: base
|
|
1775 |
!
|
|
1776 |
|
|
1777 |
storeOn: aStream
|
|
1778 |
aStream nextPut: $(; nextPutAll: self class name.
|
|
1779 |
aStream space; nextPutAll: 'mantissa:'; space; print: mantissa.
|
|
1780 |
aStream space; nextPutAll: 'exponent:'; space; print: biasedExponent.
|
|
1781 |
aStream space; nextPutAll: 'precision:'; space; print: precision.
|
|
1782 |
aStream nextPut: $)
|
|
1783 |
!
|
|
1784 |
|
|
1785 |
xxprintOn: aStream
|
|
1786 |
^self printOn: aStream base: 10
|
|
1787 |
|
|
1788 |
"Created: / 28-05-2019 / 11:23:17 / Claus Gittinger"
|
7445
|
1789 |
! !
|
|
1790 |
|
|
1791 |
!LargeFloat methodsFor:'private'!
|
|
1792 |
|
24217
|
1793 |
cos: x
|
24220
|
1794 |
"Evaluate the cosine of x by recursive cos(2x) formula and power series expansion.
|
|
1795 |
Note that it is better to use this method with x <= pi/4."
|
|
1796 |
|
|
1797 |
| one cos fraction power |
|
|
1798 |
x isZero ifTrue: [^x one].
|
|
1799 |
power := ((precision bitShift: -1) + x exponent max: 0) highBit.
|
|
1800 |
fraction := x timesTwoPower: power negated.
|
|
1801 |
cos := fraction powerExpansionCosPrecision: precision + (1 bitShift: 1 + power).
|
|
1802 |
one := x one.
|
|
1803 |
power timesRepeat:
|
|
1804 |
["Evaluate cos(2x)=2 cos(x)^2-1"
|
|
1805 |
cos inPlaceMultiplyBy: cos; inPlaceTimesTwoPower: 1; inPlaceSubtract: one].
|
|
1806 |
^cos
|
|
1807 |
|
|
1808 |
"Modified (comment): / 28-05-2019 / 17:42:54 / Claus Gittinger"
|
24217
|
1809 |
!
|
|
1810 |
|
|
1811 |
digitCompare: b
|
24220
|
1812 |
"both are positive or negative.
|
|
1813 |
answer +1 if i am of greater magnitude, -1 if i am of smaller magnitude, 0 if equal magnitude"
|
|
1814 |
|
|
1815 |
| compare |
|
|
1816 |
self isZero
|
|
1817 |
ifTrue: [b isZero
|
|
1818 |
ifTrue: [^ 0]
|
|
1819 |
ifFalse: [^ -1]].
|
|
1820 |
b isZero
|
|
1821 |
ifTrue: [^ 1].
|
|
1822 |
compare := (self exponent - b exponent) sign.
|
|
1823 |
^ compare = 0
|
|
1824 |
ifTrue: [(self abs - b abs) sign]
|
|
1825 |
ifFalse: [compare]
|
|
1826 |
|
|
1827 |
"Modified (comment): / 28-05-2019 / 17:42:59 / Claus Gittinger"
|
24217
|
1828 |
!
|
|
1829 |
|
|
1830 |
inPlaceAbs
|
24220
|
1831 |
mantissa := mantissa abs
|
|
1832 |
|
|
1833 |
"Modified (format): / 28-05-2019 / 17:43:09 / Claus Gittinger"
|
24217
|
1834 |
!
|
|
1835 |
|
24202
|
1836 |
inPlaceAdd: b
|
|
1837 |
| delta |
|
|
1838 |
|
24207
|
1839 |
b isZero ifTrue: [^self roundToPrecision].
|
24202
|
1840 |
self isZero ifTrue:[
|
24220
|
1841 |
mantissa := b mantissa.
|
|
1842 |
biasedExponent := b biasedExponent
|
24202
|
1843 |
] ifFalse:[
|
|
1844 |
biasedExponent = b biasedExponent ifTrue: [
|
24220
|
1845 |
mantissa := mantissa + b mantissa
|
24202
|
1846 |
] ifFalse:[
|
|
1847 |
"check for early truncation. beware, keep 2 bits for rounding"
|
|
1848 |
|
24220
|
1849 |
delta := biasedExponent - b biasedExponent.
|
24202
|
1850 |
delta - 2 > (precision max: self precisionInMantissa) ifFalse:[
|
|
1851 |
delta negated - 2 > (precision max: b precisionInMantissa) ifTrue:[
|
24220
|
1852 |
mantissa := b mantissa.
|
|
1853 |
biasedExponent := b exponent
|
24202
|
1854 |
] ifFalse:[
|
24220
|
1855 |
delta := biasedExponent - b exponent.
|
24202
|
1856 |
delta > 0 ifTrue:[
|
24220
|
1857 |
mantissa := (self shift: mantissa by: delta) + b mantissa.
|
|
1858 |
biasedExponent := biasedExponent - delta
|
24202
|
1859 |
] ifFalse: [
|
24220
|
1860 |
mantissa := mantissa + (self shift: b mantissa by: delta negated)
|
24202
|
1861 |
]
|
|
1862 |
]
|
|
1863 |
]
|
|
1864 |
]
|
|
1865 |
].
|
24207
|
1866 |
self roundToPrecision
|
24202
|
1867 |
|
|
1868 |
"Created: / 26-05-2019 / 03:44:50 / Claus Gittinger"
|
24207
|
1869 |
"Modified: / 28-05-2019 / 08:49:15 / Claus Gittinger"
|
24220
|
1870 |
"Modified (format): / 28-05-2019 / 17:43:15 / Claus Gittinger"
|
24202
|
1871 |
!
|
|
1872 |
|
|
1873 |
inPlaceAddNoRound: b
|
|
1874 |
| delta |
|
|
1875 |
|
|
1876 |
b isZero ifTrue: [^self].
|
|
1877 |
self isZero ifTrue:[
|
|
1878 |
mantissa := b mantissa.
|
|
1879 |
biasedExponent := b biasedExponent.
|
|
1880 |
^ self.
|
|
1881 |
].
|
|
1882 |
delta := biasedExponent - b biasedExponent.
|
|
1883 |
delta isZero ifTrue: [
|
|
1884 |
mantissa := mantissa + b mantissa
|
|
1885 |
] ifFalse:[
|
|
1886 |
delta > 0 ifTrue: [
|
|
1887 |
mantissa := (self shift: mantissa by: delta) + b mantissa.
|
|
1888 |
biasedExponent := biasedExponent - delta
|
|
1889 |
] ifFalse: [
|
|
1890 |
mantissa := mantissa + (self shift: b mantissa by: delta negated)
|
|
1891 |
]
|
|
1892 |
]
|
|
1893 |
|
|
1894 |
"Created: / 26-05-2019 / 03:41:29 / Claus Gittinger"
|
|
1895 |
"Modified: / 27-05-2019 / 16:39:21 / Claus Gittinger"
|
|
1896 |
!
|
|
1897 |
|
|
1898 |
inPlaceCopy: b
|
|
1899 |
"copy another arbitrary precision float into self"
|
|
1900 |
|
|
1901 |
mantissa := b mantissa.
|
|
1902 |
biasedExponent := b biasedExponent.
|
|
1903 |
precision := b precision
|
|
1904 |
|
|
1905 |
"Created: / 26-05-2019 / 03:39:04 / Claus Gittinger"
|
|
1906 |
"Modified: / 27-05-2019 / 16:39:24 / Claus Gittinger"
|
|
1907 |
!
|
|
1908 |
|
|
1909 |
inPlaceDivideBy: y
|
|
1910 |
"Reference: Accelerating Correctly Rounded Floating-Point Division when the Divisor
|
|
1911 |
Is Known in Advance - Nicolas Brisebarre,
|
|
1912 |
Jean-Michel Muller, Member, IEEE, and
|
|
1913 |
Saurabh Kumar Raina -
|
|
1914 |
http://perso.ens-lyon.fr/jean-michel.muller/DivIEEETC-aug04.pdf"
|
|
1915 |
|
|
1916 |
| zh x q |
|
|
1917 |
|
|
1918 |
zh := y reciprocal normalize.
|
|
1919 |
x := self copy.
|
|
1920 |
self inPlaceMultiplyBy: zh.
|
|
1921 |
q := self copy.
|
|
1922 |
"r := "self inPlaceMultiplyBy: y negated andAccumulate: x.
|
|
1923 |
"q' := "self inPlaceMultiplyBy: zh andAccumulate: q.
|
|
1924 |
|
|
1925 |
"ALGO 4
|
|
1926 |
| zh r zl |
|
|
1927 |
zh := b reciprocal.
|
|
1928 |
r := b negated inPlaceMultiplyBy: zh andAccumulate: (1 asLargeFloatPrecision: precision).
|
|
1929 |
zl := (b asLargeFloatPrecision: precision + 1) reciprocal inPlaceMultiplyBy: r.
|
|
1930 |
self inPlaceMultiplyBy: zh andAccumulate: (zl inPlaceMultiplyBy: self)"
|
|
1931 |
|
|
1932 |
"Created: / 26-05-2019 / 03:38:41 / Claus Gittinger"
|
|
1933 |
"Modified: / 27-05-2019 / 10:12:13 / Claus Gittinger"
|
|
1934 |
!
|
|
1935 |
|
|
1936 |
inPlaceMultiplyBy:b
|
|
1937 |
self inPlaceMultiplyNoRoundBy:b.
|
24207
|
1938 |
self roundToPrecision
|
24202
|
1939 |
|
|
1940 |
"
|
|
1941 |
2.4 asLargeFloat inPlaceMultiplyBy:2.0
|
|
1942 |
"
|
|
1943 |
|
|
1944 |
"Created: / 26-05-2019 / 03:37:36 / Claus Gittinger"
|
24207
|
1945 |
"Modified: / 28-05-2019 / 08:49:04 / Claus Gittinger"
|
24202
|
1946 |
!
|
|
1947 |
|
|
1948 |
inPlaceMultiplyBy:b andAccumulate:c
|
|
1949 |
"only do rounding after the two operations.
|
|
1950 |
This is the traditional muladd operation in aritmetic units"
|
|
1951 |
|
|
1952 |
self inPlaceMultiplyNoRoundBy: b.
|
|
1953 |
self inPlaceAdd:c
|
|
1954 |
|
|
1955 |
"
|
|
1956 |
2.4 asLargeFloat inPlaceMultiplyBy:2.0 asLargeFloat andAccumulate:10.0 asLargeFloat
|
|
1957 |
"
|
|
1958 |
|
|
1959 |
"Created: / 26-05-2019 / 03:37:16 / Claus Gittinger"
|
|
1960 |
"Modified (comment): / 27-05-2019 / 16:35:43 / Claus Gittinger"
|
|
1961 |
!
|
|
1962 |
|
|
1963 |
inPlaceMultiplyNoRoundBy:b
|
|
1964 |
mantissa := mantissa * b mantissa.
|
|
1965 |
biasedExponent := biasedExponent + b biasedExponent.
|
|
1966 |
|
|
1967 |
"
|
|
1968 |
2.4 asLargeFloat inPlaceMultiplyNoRoundBy:2.0
|
|
1969 |
"
|
|
1970 |
|
|
1971 |
"Created: / 26-05-2019 / 03:36:00 / Claus Gittinger"
|
|
1972 |
"Modified: / 27-05-2019 / 16:39:27 / Claus Gittinger"
|
|
1973 |
!
|
|
1974 |
|
|
1975 |
inPlaceNegated
|
|
1976 |
"destructive"
|
|
1977 |
|
|
1978 |
mantissa := mantissa negated
|
|
1979 |
|
|
1980 |
"Created: / 26-05-2019 / 03:34:34 / Claus Gittinger"
|
|
1981 |
!
|
|
1982 |
|
|
1983 |
inPlaceReciprocal
|
|
1984 |
| ma h |
|
|
1985 |
self isZero ifTrue: [(ZeroDivide dividend: self) signal].
|
|
1986 |
ma := mantissa abs.
|
|
1987 |
h := ma highBit.
|
|
1988 |
mantissa := (1 bitShift: h + precision) + ma quo: (self shift: mantissa by: 1).
|
|
1989 |
biasedExponent := biasedExponent negated - h - precision + 1.
|
24207
|
1990 |
self roundToPrecision
|
24202
|
1991 |
|
|
1992 |
"Implementation notes: if m is a power of 2, reciprocal is trivial.
|
|
1993 |
Else, we have 2^h > m >2^(h-1)
|
|
1994 |
thus 1 < 2^h/m < 2.
|
|
1995 |
thus 2^(n-1) < 2^(h+n-1)/m < 2^n
|
|
1996 |
We thus have to evaluate (2^(h+n-1)/m) rounded
|
|
1997 |
Tie is away from zero because there are always trailing bits (inexact op)
|
|
1998 |
(num/den) rounded is also ((num/den)+(sign/2)) truncated
|
|
1999 |
or (num*2)+(sign*den) quo: den*2
|
|
2000 |
That's finally what we evaluate"
|
|
2001 |
|
24207
|
2002 |
"Modified: / 28-05-2019 / 08:48:59 / Claus Gittinger"
|
24202
|
2003 |
!
|
|
2004 |
|
|
2005 |
inPlaceSqrt
|
24207
|
2006 |
"Replace the receiver by its square root."
|
24202
|
2007 |
|
24207
|
2008 |
| guess guessSquared delta shift |
|
|
2009 |
self negative
|
|
2010 |
ifTrue:
|
|
2011 |
[^ DomainError signal: 'sqrt undefined for number less than zero.'].
|
|
2012 |
self isZero ifTrue: [^self].
|
24202
|
2013 |
|
24218
|
2014 |
shift := 2 * precision - mantissa highBit.
|
|
2015 |
biasedExponent := biasedExponent - shift.
|
24207
|
2016 |
biasedExponent odd
|
|
2017 |
ifTrue:
|
24218
|
2018 |
[shift := shift + 1.
|
|
2019 |
biasedExponent := biasedExponent - 1].
|
|
2020 |
mantissa := mantissa bitShift: shift.
|
|
2021 |
guess := mantissa bitShift: (mantissa highBit + 1) // 2.
|
24207
|
2022 |
[
|
24218
|
2023 |
guessSquared := guess * guess.
|
|
2024 |
delta := guessSquared - mantissa quo: (guess bitShift: 1).
|
24207
|
2025 |
delta = 0 ] whileFalse:
|
24218
|
2026 |
[ guess := guess - delta ].
|
24207
|
2027 |
guessSquared = mantissa
|
|
2028 |
ifFalse:
|
24218
|
2029 |
[(guessSquared - guess - mantissa) negative ifFalse: [guess := guess - 1]].
|
|
2030 |
mantissa := guess.
|
|
2031 |
biasedExponent := biasedExponent quo: 2.
|
24207
|
2032 |
self roundToPrecision
|
|
2033 |
|
|
2034 |
"Modified: / 28-05-2019 / 08:48:55 / Claus Gittinger"
|
24218
|
2035 |
"Modified (format): / 28-05-2019 / 16:17:39 / Claus Gittinger"
|
24202
|
2036 |
!
|
|
2037 |
|
|
2038 |
inPlaceSubtract: b
|
|
2039 |
| delta |
|
24207
|
2040 |
b isZero ifTrue: [^self roundToPrecision].
|
24202
|
2041 |
self isZero
|
|
2042 |
ifTrue:
|
24220
|
2043 |
[mantissa := b mantissa negated.
|
|
2044 |
biasedExponent := b biasedExponent]
|
24202
|
2045 |
ifFalse:
|
|
2046 |
[biasedExponent = b biasedExponent
|
24220
|
2047 |
ifTrue: [mantissa := mantissa - b mantissa]
|
24202
|
2048 |
ifFalse:
|
|
2049 |
["check for early truncation. beware, keep 2 bits for rounding"
|
|
2050 |
|
24220
|
2051 |
delta := biasedExponent - b biasedExponent.
|
24202
|
2052 |
delta - 2 > (precision max: self precisionInMantissa)
|
|
2053 |
ifFalse:
|
|
2054 |
[delta negated - 2 > (precision max: b precisionInMantissa)
|
|
2055 |
ifTrue:
|
24220
|
2056 |
[mantissa := b mantissa negated.
|
|
2057 |
biasedExponent := b biasedExponent]
|
24202
|
2058 |
ifFalse:
|
24220
|
2059 |
[delta := biasedExponent - b biasedExponent.
|
24202
|
2060 |
delta >= 0
|
|
2061 |
ifTrue:
|
24220
|
2062 |
[mantissa := (self shift: mantissa by: delta) - b mantissa.
|
|
2063 |
biasedExponent := biasedExponent - delta]
|
|
2064 |
ifFalse: [mantissa := mantissa - (self shift: b mantissa by: delta negated)]]]]].
|
24207
|
2065 |
self roundToPrecision
|
24202
|
2066 |
|
24207
|
2067 |
"Modified: / 28-05-2019 / 08:48:46 / Claus Gittinger"
|
24220
|
2068 |
"Modified (format): / 28-05-2019 / 17:43:21 / Claus Gittinger"
|
24202
|
2069 |
!
|
|
2070 |
|
|
2071 |
inPlaceSubtractNoRound: b
|
24218
|
2072 |
| delta |
|
|
2073 |
b isZero ifTrue: [^self].
|
|
2074 |
self isZero
|
|
2075 |
ifTrue:
|
|
2076 |
[mantissa := b mantissa negated.
|
|
2077 |
biasedExponent := b biasedExponent]
|
|
2078 |
ifFalse:
|
|
2079 |
[delta := biasedExponent - b biasedExponent.
|
|
2080 |
delta isZero
|
|
2081 |
ifTrue: [mantissa := mantissa - b mantissa]
|
|
2082 |
ifFalse:
|
|
2083 |
[delta >= 0
|
|
2084 |
ifTrue:
|
|
2085 |
[mantissa := (self shift: mantissa by: delta) - b mantissa.
|
|
2086 |
biasedExponent := biasedExponent - delta]
|
|
2087 |
ifFalse: [mantissa := mantissa - (self shift: b mantissa by: delta negated)]]]
|
|
2088 |
|
|
2089 |
"Modified (format): / 28-05-2019 / 16:17:47 / Claus Gittinger"
|
24202
|
2090 |
!
|
|
2091 |
|
|
2092 |
inPlaceTimesTwoPower: n
|
24220
|
2093 |
self isZero
|
|
2094 |
ifFalse: [biasedExponent := biasedExponent + n]
|
|
2095 |
|
|
2096 |
"Modified (format): / 28-05-2019 / 17:43:24 / Claus Gittinger"
|
24202
|
2097 |
!
|
|
2098 |
|
7445
|
2099 |
mantissa:mantissaArg exponent:exponentArg
|
7546
|
2100 |
"set instance variables.
|
22041
|
2101 |
Notice, that the float's value is m * 2^e"
|
7445
|
2102 |
|
24202
|
2103 |
biasedExponent := exponentArg.
|
7445
|
2104 |
mantissa := mantissaArg.
|
24208
|
2105 |
precision := self class defaultPrecision.
|
7445
|
2106 |
self normalize.
|
22041
|
2107 |
|
|
2108 |
"Modified (comment): / 17-07-2017 / 14:50:14 / cg"
|
24208
|
2109 |
"Modified: / 28-05-2019 / 09:20:11 / Claus Gittinger"
|
7445
|
2110 |
!
|
|
2111 |
|
|
2112 |
mantissa:mantissaArg exponent:exponentArg precision:precisionArg
|
7546
|
2113 |
"set instance variables.
|
22041
|
2114 |
Notice, that the float's value is m * 2^e"
|
7546
|
2115 |
|
24202
|
2116 |
biasedExponent := exponentArg.
|
7445
|
2117 |
mantissa := mantissaArg.
|
|
2118 |
precision := precisionArg.
|
24217
|
2119 |
self roundToPrecision "/ normalize
|
22041
|
2120 |
|
|
2121 |
"Modified (comment): / 17-07-2017 / 14:50:10 / cg"
|
24217
|
2122 |
"Modified: / 28-05-2019 / 11:19:14 / Claus Gittinger"
|
24202
|
2123 |
!
|
|
2124 |
|
|
2125 |
moduloNegPiToPi
|
24220
|
2126 |
"answer a copy of the receiver modulo 2*pi, with doubled precision"
|
|
2127 |
|
|
2128 |
| x pi twoPi quo |
|
|
2129 |
x := (self asLargeFloatPrecision: precision * 2).
|
|
2130 |
self negative ifTrue: [x inPlaceNegated].
|
|
2131 |
pi := x pi.
|
|
2132 |
twoPi := pi timesTwoPower: 1.
|
|
2133 |
x > pi ifTrue:
|
|
2134 |
[quo := x + pi quo: twoPi.
|
|
2135 |
quo highBitOfMagnitude > precision ifTrue:
|
|
2136 |
[x := (self abs asLargeFloatPrecision: precision + quo highBitOfMagnitude).
|
|
2137 |
pi := x pi.
|
|
2138 |
twoPi := pi timesTwoPower: 1.
|
|
2139 |
quo := x + pi quo: twoPi].
|
|
2140 |
x inPlaceSubtract: twoPi * quo.
|
|
2141 |
self negative ifTrue: [x inPlaceNegated]].
|
|
2142 |
^x asLargeFloatPrecision: precision * 2
|
|
2143 |
|
|
2144 |
"Modified (format): / 28-05-2019 / 17:43:36 / Claus Gittinger"
|
7445
|
2145 |
!
|
|
2146 |
|
|
2147 |
normalize
|
|
2148 |
"adjust m & e such that m is the smallest possible
|
7546
|
2149 |
(i.e. has no least significant zero bit).
|
24202
|
2150 |
Notice, that the float's value is m * 2^e"
|
7445
|
2151 |
|
|
2152 |
|shift|
|
|
2153 |
|
|
2154 |
shift := mantissa lowBit - 1.
|
|
2155 |
shift > 0 ifTrue:[
|
|
2156 |
mantissa := mantissa bitShift:shift negated.
|
24202
|
2157 |
biasedExponent := biasedExponent + shift
|
7445
|
2158 |
].
|
|
2159 |
|
|
2160 |
"
|
7546
|
2161 |
self mantissa:1 exponent:0
|
|
2162 |
self mantissa:2 exponent:0
|
|
2163 |
self mantissa:4 exponent:0
|
|
2164 |
self mantissa:8 exponent:0
|
|
2165 |
self mantissa:10 exponent:-1
|
|
2166 |
self mantissa:10 exponent:0
|
|
2167 |
self mantissa:10 exponent:1
|
24202
|
2168 |
self mantissa:-10 exponent:1
|
7445
|
2169 |
"
|
24202
|
2170 |
|
|
2171 |
"Modified (comment): / 26-05-2019 / 03:34:00 / Claus Gittinger"
|
22041
|
2172 |
!
|
|
2173 |
|
24217
|
2174 |
powerExpansionArCoshp1Precision: precBits
|
24220
|
2175 |
"Evaluate arcosh(x+1)/sqrt(2*x) for the receiver x by power series expansion.
|
|
2176 |
The algorithm is interesting when the receiver is close to zero"
|
|
2177 |
|
|
2178 |
| one two count count2 sum term term1 term2 |
|
|
2179 |
one := self one.
|
|
2180 |
two := one timesTwoPower: 1.
|
|
2181 |
count := one copy.
|
|
2182 |
count2 := one copy.
|
|
2183 |
sum := one copy.
|
|
2184 |
term1 := one copy.
|
|
2185 |
term2 := one copy.
|
|
2186 |
|
|
2187 |
[term1 inPlaceMultiplyBy: self.
|
|
2188 |
term1 inPlaceNegated.
|
|
2189 |
term2 inPlaceMultiplyBy: count2.
|
|
2190 |
term2 inPlaceMultiplyBy: count2.
|
|
2191 |
term2 inPlaceDivideBy: count.
|
|
2192 |
count inPlaceAdd: one.
|
|
2193 |
count2 inPlaceAdd: two.
|
|
2194 |
term2 inPlaceDivideBy: count2.
|
|
2195 |
term2 inPlaceTimesTwoPower: -2.
|
|
2196 |
term := term1 * term2.
|
|
2197 |
sum inPlaceAdd: term.
|
|
2198 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2199 |
^sum
|
|
2200 |
|
|
2201 |
"Modified (comment): / 28-05-2019 / 17:43:51 / Claus Gittinger"
|
24217
|
2202 |
!
|
|
2203 |
|
|
2204 |
powerExpansionArSinhPrecision: precBits
|
24220
|
2205 |
"Evaluate the area hypebolic sine of the receiver by power series expansion.
|
|
2206 |
The algorithm is interesting when the receiver is close to zero"
|
|
2207 |
|
|
2208 |
| one x2 two count sum term |
|
|
2209 |
one := self one.
|
|
2210 |
two := one timesTwoPower: 1.
|
|
2211 |
count := one copy.
|
|
2212 |
sum := one copy.
|
|
2213 |
term := one copy.
|
|
2214 |
x2 := self squared.
|
|
2215 |
|
|
2216 |
[term inPlaceMultiplyBy: x2.
|
|
2217 |
term inPlaceMultiplyBy: count.
|
|
2218 |
term inPlaceDivideBy: count + one.
|
|
2219 |
term inPlaceNegated.
|
|
2220 |
count inPlaceAdd: two.
|
|
2221 |
sum inPlaceAdd: term / count.
|
|
2222 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2223 |
sum inPlaceMultiplyBy: self.
|
|
2224 |
^sum
|
|
2225 |
|
|
2226 |
"Modified (comment): / 28-05-2019 / 17:43:57 / Claus Gittinger"
|
24217
|
2227 |
!
|
|
2228 |
|
|
2229 |
powerExpansionArTanhPrecision: precBits
|
24220
|
2230 |
"Evaluate the area hyperbolic tangent of the receiver by power series expansion.
|
|
2231 |
arTanh (x) = x (1 + x^2/3 + x^4/5 + ... ) for -1 < x < 1
|
|
2232 |
The algorithm is interesting when the receiver is close to zero"
|
|
2233 |
|
|
2234 |
| one x2 two count sum term |
|
|
2235 |
one := self one.
|
|
2236 |
two := one timesTwoPower: 1.
|
|
2237 |
count := one copy.
|
|
2238 |
sum := one copy.
|
|
2239 |
term := one copy.
|
|
2240 |
x2 := self squared.
|
|
2241 |
|
|
2242 |
[term inPlaceMultiplyBy: x2.
|
|
2243 |
count inPlaceAdd: two.
|
|
2244 |
sum inPlaceAdd: term / count.
|
|
2245 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2246 |
sum inPlaceMultiplyBy: self.
|
|
2247 |
^sum
|
|
2248 |
|
|
2249 |
"Modified (comment): / 28-05-2019 / 17:44:04 / Claus Gittinger"
|
24217
|
2250 |
!
|
|
2251 |
|
|
2252 |
powerExpansionArcSinPrecision: precBits
|
24220
|
2253 |
"Evaluate the arc sine of the receiver by power series expansion.
|
|
2254 |
The algorithm is interesting when the receiver is close to zero"
|
|
2255 |
|
|
2256 |
| one x2 two count sum term |
|
|
2257 |
one := self one.
|
|
2258 |
two := one timesTwoPower: 1.
|
|
2259 |
count := one copy.
|
|
2260 |
sum := one copy.
|
|
2261 |
term := one copy.
|
|
2262 |
x2 := self squared.
|
|
2263 |
|
|
2264 |
[term inPlaceMultiplyBy: x2.
|
|
2265 |
term inPlaceMultiplyBy: count.
|
|
2266 |
term inPlaceDivideBy: count + one.
|
|
2267 |
count inPlaceAdd: two.
|
|
2268 |
sum inPlaceAdd: term / count.
|
|
2269 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2270 |
sum inPlaceMultiplyBy: self.
|
|
2271 |
^sum
|
|
2272 |
|
|
2273 |
"Modified (comment): / 28-05-2019 / 17:44:09 / Claus Gittinger"
|
24217
|
2274 |
!
|
|
2275 |
|
|
2276 |
powerExpansionArcTanPrecision: precBits
|
24220
|
2277 |
"Evaluate the arc tangent of the receiver by power series expansion.
|
|
2278 |
arcTan (x) = x (1 - x^2/3 + x^4/5 - ... ) for -1 < x < 1
|
|
2279 |
The algorithm is interesting when the receiver is close to zero"
|
|
2280 |
|
|
2281 |
| count one sum term two x2 |
|
|
2282 |
one := self one.
|
|
2283 |
two := one timesTwoPower: 1.
|
|
2284 |
count := one copy.
|
|
2285 |
sum := one copy.
|
|
2286 |
term := one copy.
|
|
2287 |
x2 := self squared.
|
|
2288 |
|
|
2289 |
[term inPlaceMultiplyBy: x2.
|
|
2290 |
term inPlaceNegated.
|
|
2291 |
count inPlaceAdd: two.
|
|
2292 |
sum inPlaceAdd: term / count.
|
|
2293 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2294 |
sum inPlaceMultiplyBy: self.
|
|
2295 |
^sum
|
|
2296 |
|
|
2297 |
"Modified (comment): / 28-05-2019 / 17:44:15 / Claus Gittinger"
|
24217
|
2298 |
!
|
|
2299 |
|
|
2300 |
powerExpansionCosPrecision: precBits
|
24220
|
2301 |
"Evaluate the cosine of the receiver by power series expansion.
|
|
2302 |
The algorithm is interesting when the receiver is close to zero"
|
|
2303 |
|
|
2304 |
| count one sum term two x2 |
|
|
2305 |
one := self one.
|
|
2306 |
two := one timesTwoPower: 1.
|
|
2307 |
count := one copy.
|
|
2308 |
sum := one copy.
|
|
2309 |
term := one copy.
|
|
2310 |
x2 := self squared.
|
|
2311 |
|
|
2312 |
[term inPlaceMultiplyBy: x2.
|
|
2313 |
term inPlaceDivideBy: count * (count + one).
|
|
2314 |
term inPlaceNegated.
|
|
2315 |
count inPlaceAdd: two.
|
|
2316 |
sum inPlaceAdd: term.
|
|
2317 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2318 |
^sum
|
|
2319 |
|
|
2320 |
"Modified (comment): / 28-05-2019 / 17:44:25 / Claus Gittinger"
|
24217
|
2321 |
!
|
|
2322 |
|
|
2323 |
powerExpansionCoshPrecision: precBits
|
24220
|
2324 |
"Evaluate the hyperbolic cosine of the receiver by power series expansion.
|
|
2325 |
The algorithm is interesting when the receiver is close to zero"
|
|
2326 |
|
|
2327 |
| count one sum term two x2 |
|
|
2328 |
one := self one.
|
|
2329 |
two := one timesTwoPower: 1.
|
|
2330 |
count := one copy.
|
|
2331 |
sum := one copy.
|
|
2332 |
term := one copy.
|
|
2333 |
x2 := self squared.
|
|
2334 |
|
|
2335 |
[term inPlaceMultiplyBy: x2.
|
|
2336 |
term inPlaceDivideBy: count * (count + one).
|
|
2337 |
count inPlaceAdd: two.
|
|
2338 |
sum inPlaceAdd: term.
|
|
2339 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2340 |
^sum
|
|
2341 |
|
|
2342 |
"Modified (comment): / 28-05-2019 / 17:44:30 / Claus Gittinger"
|
24217
|
2343 |
!
|
|
2344 |
|
|
2345 |
powerExpansionLnPrecision: precBits
|
24220
|
2346 |
"Evaluate the neperian logarithm of the receiver by power series expansion.
|
|
2347 |
For quadratic convergence, use:
|
|
2348 |
ln ((1+y)/(1-y)) = 2 y (1 + y^2/3 + y^4/5 + ... ) = 2 ar tanh( y )
|
|
2349 |
(1+y)/(1-y) = self => y = (self-1)/(self+1)
|
|
2350 |
This algorithm is interesting when the receiver is close to 1"
|
|
2351 |
|
|
2352 |
| one |
|
|
2353 |
one := self one.
|
|
2354 |
^((self - one)/(self + one) powerExpansionArTanhPrecision: precBits) timesTwoPower: 1
|
|
2355 |
|
|
2356 |
"Modified (comment): / 28-05-2019 / 17:44:38 / Claus Gittinger"
|
24217
|
2357 |
!
|
|
2358 |
|
|
2359 |
powerExpansionSinCosPrecision: precBits
|
24220
|
2360 |
"Evaluate the sine and cosine of the receiver by power series expansion.
|
|
2361 |
The algorithm is interesting when the receiver is close to zero"
|
|
2362 |
|
|
2363 |
| count one sin cos term |
|
|
2364 |
one := self one.
|
|
2365 |
count := one copy.
|
|
2366 |
cos := one copy.
|
|
2367 |
sin := self copy.
|
|
2368 |
term := self copy.
|
|
2369 |
|
|
2370 |
[count inPlaceAdd: one.
|
|
2371 |
term
|
|
2372 |
inPlaceMultiplyBy: self;
|
|
2373 |
inPlaceDivideBy: count;
|
|
2374 |
inPlaceNegated.
|
|
2375 |
cos inPlaceAdd: term.
|
|
2376 |
|
|
2377 |
count inPlaceAdd: one.
|
|
2378 |
term
|
|
2379 |
inPlaceMultiplyBy: self;
|
|
2380 |
inPlaceDivideBy: count.
|
|
2381 |
sin inPlaceAdd: term.
|
|
2382 |
|
|
2383 |
term exponent + precBits < sin exponent] whileFalse.
|
|
2384 |
^Array with: sin with: cos
|
|
2385 |
|
|
2386 |
"Modified (comment): / 28-05-2019 / 17:44:43 / Claus Gittinger"
|
24217
|
2387 |
!
|
|
2388 |
|
|
2389 |
powerExpansionSinPrecision: precBits
|
24220
|
2390 |
"Evaluate the sine of the receiver by power series expansion.
|
|
2391 |
The algorithm is interesting when the receiver is close to zero"
|
|
2392 |
|
|
2393 |
| count one sum term two x2 |
|
|
2394 |
one := self one.
|
|
2395 |
two := one timesTwoPower: 1.
|
|
2396 |
count := two copy.
|
|
2397 |
sum := self copy.
|
|
2398 |
term := self copy.
|
|
2399 |
x2 := self squared.
|
|
2400 |
|
|
2401 |
[term inPlaceMultiplyBy: x2.
|
|
2402 |
term inPlaceDivideBy: count * (count + one).
|
|
2403 |
term inPlaceNegated.
|
|
2404 |
count inPlaceAdd: two.
|
|
2405 |
sum inPlaceAdd: term.
|
|
2406 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2407 |
^sum
|
|
2408 |
|
|
2409 |
"Modified (comment): / 28-05-2019 / 17:44:50 / Claus Gittinger"
|
24217
|
2410 |
!
|
|
2411 |
|
|
2412 |
powerExpansionSinhPrecision: precBits
|
24220
|
2413 |
"Evaluate the hyperbolic sine of the receiver by power series expansion.
|
|
2414 |
The algorithm is interesting when the receiver is close to zero"
|
|
2415 |
|
|
2416 |
| count one sum term two x2 |
|
|
2417 |
one := self one.
|
|
2418 |
two := one timesTwoPower: 1.
|
|
2419 |
count := two copy.
|
|
2420 |
sum := self copy.
|
|
2421 |
term := self copy.
|
|
2422 |
x2 := self squared.
|
|
2423 |
|
|
2424 |
[term inPlaceMultiplyBy: x2.
|
|
2425 |
term inPlaceDivideBy: count * (count + one).
|
|
2426 |
count inPlaceAdd: two.
|
|
2427 |
sum inPlaceAdd: term.
|
|
2428 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2429 |
^sum
|
|
2430 |
|
|
2431 |
"Modified (comment): / 28-05-2019 / 17:44:56 / Claus Gittinger"
|
24217
|
2432 |
!
|
|
2433 |
|
|
2434 |
powerExpansionTanPrecision: precBits
|
24220
|
2435 |
"Evaluate the tangent of the receiver by power series expansion.
|
|
2436 |
The algorithm is interesting when the receiver is close to zero"
|
|
2437 |
|
|
2438 |
| count one sum term pow two x2 seidel |
|
|
2439 |
one := self one.
|
|
2440 |
two := one timesTwoPower: 1.
|
|
2441 |
count := two copy.
|
|
2442 |
sum := one copy.
|
|
2443 |
pow := one copy.
|
|
2444 |
x2 := self squared.
|
|
2445 |
seidel := OrderedCollection new: 256.
|
|
2446 |
seidel add: 1.
|
|
2447 |
|
|
2448 |
[pow inPlaceMultiplyBy: x2.
|
|
2449 |
pow inPlaceDivideBy: count * (count + one).
|
|
2450 |
count inPlaceAdd: two.
|
|
2451 |
2 to: seidel size do: [:i | seidel at: i put: (seidel at: i-1) + (seidel at: i)].
|
|
2452 |
seidel addLast: seidel last.
|
|
2453 |
seidel size to: 2 by: -1 do: [:i | seidel at: i - 1 put: (seidel at: i-1) + (seidel at: i)].
|
|
2454 |
seidel addFirst: seidel first.
|
|
2455 |
term := pow * seidel first.
|
|
2456 |
sum inPlaceAdd: term.
|
|
2457 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2458 |
sum inPlaceMultiplyBy: self.
|
|
2459 |
^sum
|
|
2460 |
|
|
2461 |
"Modified (comment): / 28-05-2019 / 17:45:02 / Claus Gittinger"
|
24217
|
2462 |
!
|
|
2463 |
|
|
2464 |
powerExpansionTanhPrecision: precBits
|
24220
|
2465 |
"Evaluate the hyperbolic tangent of the receiver by power series expansion.
|
|
2466 |
The algorithm is interesting when the receiver is close to zero"
|
|
2467 |
|
|
2468 |
| count one sum term pow two x2 seidel |
|
|
2469 |
one := self one.
|
|
2470 |
two := one timesTwoPower: 1.
|
|
2471 |
count := two copy.
|
|
2472 |
sum := one copy.
|
|
2473 |
pow := one copy.
|
|
2474 |
x2 := self squared.
|
|
2475 |
seidel := OrderedCollection new: 256.
|
|
2476 |
seidel add: 1.
|
|
2477 |
|
|
2478 |
[pow inPlaceMultiplyBy: x2.
|
|
2479 |
pow inPlaceDivideBy: count * (count + one).
|
|
2480 |
pow inPlaceNegated.
|
|
2481 |
count inPlaceAdd: two.
|
|
2482 |
2 to: seidel size do: [:i | seidel at: i put: (seidel at: i-1) + (seidel at: i)].
|
|
2483 |
seidel addLast: seidel last.
|
|
2484 |
seidel size to: 2 by: -1 do: [:i | seidel at: i - 1 put: (seidel at: i-1) + (seidel at: i)].
|
|
2485 |
seidel addFirst: seidel first.
|
|
2486 |
term := pow * seidel first.
|
|
2487 |
sum inPlaceAdd: term.
|
|
2488 |
term exponent + precBits < sum exponent] whileFalse.
|
|
2489 |
sum inPlaceMultiplyBy: self.
|
|
2490 |
^sum
|
|
2491 |
|
|
2492 |
"Modified (comment): / 28-05-2019 / 17:45:07 / Claus Gittinger"
|
24217
|
2493 |
!
|
|
2494 |
|
22041
|
2495 |
precision:precisionArg
|
|
2496 |
"set instance variables.
|
|
2497 |
Notice, that the float's value is m * 2^e"
|
|
2498 |
|
|
2499 |
precision := precisionArg.
|
|
2500 |
self normalize
|
|
2501 |
|
|
2502 |
"Created: / 17-07-2017 / 14:50:04 / cg"
|
24202
|
2503 |
!
|
|
2504 |
|
|
2505 |
precisionInMantissa
|
|
2506 |
"this is equal to precision only if we are normalized.
|
|
2507 |
If we are reduced (low bits being zero are removed), then it will be less.
|
|
2508 |
If we haven't been rounded/truncated then it will be more"
|
|
2509 |
|
|
2510 |
^ mantissa highBitOfMagnitude
|
|
2511 |
|
|
2512 |
"Created: / 26-05-2019 / 03:45:02 / Claus Gittinger"
|
|
2513 |
!
|
|
2514 |
|
24217
|
2515 |
reduce
|
24220
|
2516 |
"remove trailing zero bits from mantissa so that we can do arithmetic on smaller integer
|
|
2517 |
(that will un-normalize self)"
|
|
2518 |
|
|
2519 |
| trailing |
|
|
2520 |
trailing := mantissa abs lowBit - 1.
|
|
2521 |
trailing > 0
|
|
2522 |
ifFalse: [ ^ self ].
|
|
2523 |
mantissa := self shift: mantissa by: trailing negated.
|
|
2524 |
biasedExponent := biasedExponent + trailing
|
|
2525 |
|
|
2526 |
"Modified (comment): / 28-05-2019 / 17:45:13 / Claus Gittinger"
|
24217
|
2527 |
!
|
|
2528 |
|
24207
|
2529 |
roundToPrecision
|
24202
|
2530 |
"destructive inplace round
|
|
2531 |
apply algorithm round to nearest even used by IEEE arithmetic"
|
|
2532 |
|
|
2533 |
"inexact := ma lowBit <= excess."
|
|
2534 |
|
|
2535 |
| excess ma carry |
|
|
2536 |
|
|
2537 |
mantissa isZero ifTrue: [
|
|
2538 |
biasedExponent := 0.
|
|
2539 |
^ self
|
|
2540 |
].
|
|
2541 |
ma := mantissa abs.
|
|
2542 |
excess := ma highBit - precision.
|
|
2543 |
excess > 0 ifFalse: [ ^ self ].
|
|
2544 |
|
|
2545 |
carry := ma bitAt: excess.
|
|
2546 |
mantissa := self shift: mantissa by: excess negated.
|
|
2547 |
biasedExponent := biasedExponent + excess.
|
|
2548 |
(carry = 1 and: [ mantissa odd or: [ ma lowBit < excess ] ]) ifFalse: [ ^ self ].
|
|
2549 |
mantissa := mantissa + mantissa sign.
|
|
2550 |
self truncate
|
|
2551 |
|
24207
|
2552 |
"Created: / 28-05-2019 / 08:49:25 / Claus Gittinger"
|
24202
|
2553 |
!
|
|
2554 |
|
|
2555 |
shift:m by:d
|
|
2556 |
"shift mantissa m absolute value by some d bits, then restore sign"
|
|
2557 |
|
|
2558 |
^m negative
|
|
2559 |
ifTrue: [(m negated bitShift:d) negated]
|
|
2560 |
ifFalse: [m bitShift:d]
|
|
2561 |
|
|
2562 |
"Created: / 26-05-2019 / 03:22:12 / Claus Gittinger"
|
24217
|
2563 |
!
|
|
2564 |
|
|
2565 |
sin: x
|
24220
|
2566 |
"Evaluate the sine of x by sin(5x) formula and power series expansion."
|
|
2567 |
|
|
2568 |
| sin sin2 sin4 fifth five |
|
|
2569 |
x isZero ifTrue: [^x zero].
|
|
2570 |
five := 5 asLargeFloatPrecision: x precision.
|
|
2571 |
fifth := x / five.
|
|
2572 |
sin := fifth powerExpansionSinPrecision: precision + 8.
|
|
2573 |
sin2 := sin squared.
|
|
2574 |
sin2 inPlaceTimesTwoPower: 2.
|
|
2575 |
sin4 := sin2 squared.
|
|
2576 |
sin2 inPlaceMultiplyBy: five.
|
|
2577 |
^sin4
|
|
2578 |
inPlaceSubtract: sin2;
|
|
2579 |
inPlaceAdd: five;
|
|
2580 |
inPlaceMultiplyBy: sin;
|
|
2581 |
yourself
|
|
2582 |
|
|
2583 |
"Modified (format): / 28-05-2019 / 17:45:21 / Claus Gittinger"
|
24217
|
2584 |
!
|
|
2585 |
|
|
2586 |
sincos: x
|
24220
|
2587 |
"Evaluate the sine and cosine of x by recursive sin(2x) and cos(2x) formula and power series expansion.
|
|
2588 |
Note that it is better to use this method with x <= pi/4."
|
|
2589 |
|
|
2590 |
| one sin cos sincos fraction power |
|
|
2591 |
x isZero ifTrue: [^Array with: x zero with: x one].
|
|
2592 |
power := ((precision bitShift: -1) + x exponent max: 0) highBit.
|
|
2593 |
fraction := x timesTwoPower: power negated.
|
|
2594 |
sincos := fraction powerExpansionSinCosPrecision: precision + (1 bitShift: 1 + power).
|
|
2595 |
sin := sincos first.
|
|
2596 |
cos := sincos last.
|
|
2597 |
one := x one.
|
|
2598 |
power timesRepeat:
|
|
2599 |
["Evaluate sin(2x)=2 sin(x) cos(x)"
|
|
2600 |
sin inPlaceMultiplyBy: cos; inPlaceTimesTwoPower: 1.
|
|
2601 |
"Evaluate cos(2x)=2 cos(x)^2-1"
|
|
2602 |
cos inPlaceMultiplyBy: cos; inPlaceTimesTwoPower: 1; inPlaceSubtract: one].
|
|
2603 |
^sincos
|
|
2604 |
|
|
2605 |
"Modified (comment): / 28-05-2019 / 17:45:33 / Claus Gittinger"
|
7445
|
2606 |
! !
|
|
2607 |
|
8634
|
2608 |
!LargeFloat methodsFor:'queries'!
|
|
2609 |
|
|
2610 |
epsilon
|
21902
|
2611 |
"return the maximum relative spacing of instances of mySelf
|
|
2612 |
(i.e. the value-delta of the least significant bit)"
|
8634
|
2613 |
|
|
2614 |
|p|
|
|
2615 |
|
|
2616 |
p := precision.
|
|
2617 |
p isFinite ifTrue:[
|
|
2618 |
^ self class radix asFloat raisedTo:(1 - p)
|
|
2619 |
].
|
22299
|
2620 |
|
|
2621 |
"/ mhmh - what should we use here for an infinite precision ???
|
|
2622 |
^ 1e-300
|
|
2623 |
"/ ^ LongFloat epsilon
|
21902
|
2624 |
|
22299
|
2625 |
"Modified: / 10-10-2017 / 15:55:12 / cg"
|
24208
|
2626 |
!
|
|
2627 |
|
|
2628 |
numBitsInMantissa
|
|
2629 |
^ precision
|
|
2630 |
|
|
2631 |
"Created: / 28-05-2019 / 09:14:36 / Claus Gittinger"
|
8634
|
2632 |
! !
|
|
2633 |
|
7445
|
2634 |
!LargeFloat methodsFor:'testing'!
|
|
2635 |
|
24202
|
2636 |
isAnExactFloat
|
24217
|
2637 |
^self exponent <= Float emax
|
|
2638 |
and: [Float emin - Float precision < self exponent
|
|
2639 |
and: [precision <= Float precision or: [mantissa isAnExactFloat]]]
|
24202
|
2640 |
!
|
|
2641 |
|
7445
|
2642 |
isFinite
|
24202
|
2643 |
^ mantissa ~= 0 or:[biasedExponent = 0]
|
7445
|
2644 |
!
|
|
2645 |
|
|
2646 |
isInfinite
|
24202
|
2647 |
^ mantissa = 0 and:[biasedExponent ~= 0]
|
7445
|
2648 |
!
|
|
2649 |
|
|
2650 |
isNaN
|
|
2651 |
^ self == NaN
|
|
2652 |
!
|
|
2653 |
|
|
2654 |
isZero
|
24202
|
2655 |
^mantissa isZero
|
7445
|
2656 |
!
|
|
2657 |
|
|
2658 |
negative
|
|
2659 |
"return true if the receiver is negative"
|
|
2660 |
|
24257
|
2661 |
mantissa == 0 ifTrue:[ ^ biasedExponent negative]. "/ +/-INF
|
7445
|
2662 |
^ mantissa negative
|
24257
|
2663 |
|
|
2664 |
"Modified (comment): / 05-06-2019 / 20:08:19 / Claus Gittinger"
|
7445
|
2665 |
!
|
|
2666 |
|
24217
|
2667 |
positive
|
24257
|
2668 |
mantissa == 0 ifTrue:[^ biasedExponent positive]. "/ +/-INF
|
|
2669 |
^ mantissa positive
|
|
2670 |
|
|
2671 |
"Modified (comment): / 05-06-2019 / 20:08:07 / Claus Gittinger"
|
24217
|
2672 |
!
|
|
2673 |
|
7445
|
2674 |
sign
|
|
2675 |
"return the sign of the receiver"
|
|
2676 |
|
7546
|
2677 |
mantissa == 0 ifTrue:[
|
|
2678 |
"special value for infinites"
|
24202
|
2679 |
^ biasedExponent sign
|
7546
|
2680 |
].
|
7445
|
2681 |
^ mantissa sign
|
|
2682 |
! !
|
|
2683 |
|
24202
|
2684 |
!LargeFloat methodsFor:'truncation & rounding'!
|
|
2685 |
|
|
2686 |
truncate
|
|
2687 |
"remove trailing bits if they exceed our allocated number of bits"
|
|
2688 |
|
|
2689 |
| excess |
|
|
2690 |
excess := precision - precision.
|
|
2691 |
excess > 0 ifFalse: [ ^ self ].
|
|
2692 |
mantissa := self shift:mantissa by:excess negated.
|
|
2693 |
biasedExponent := biasedExponent + excess
|
|
2694 |
|
|
2695 |
"Created: / 26-05-2019 / 03:24:10 / Claus Gittinger"
|
|
2696 |
!
|
|
2697 |
|
|
2698 |
truncated
|
|
2699 |
"answer the integer that is nearest to self in the interval between zero and self"
|
|
2700 |
|
|
2701 |
^ biasedExponent negated > precision
|
|
2702 |
ifTrue: [0]
|
|
2703 |
ifFalse: [self shift: mantissa by: biasedExponent]
|
|
2704 |
|
|
2705 |
"
|
|
2706 |
2.4 asLargeFloat truncated
|
|
2707 |
2e34 asLargeFloat truncated
|
|
2708 |
"
|
|
2709 |
|
|
2710 |
"Created: / 26-05-2019 / 03:21:52 / Claus Gittinger"
|
|
2711 |
! !
|
|
2712 |
|
24217
|
2713 |
!LargeFloat methodsFor:'truncation and round off'!
|
|
2714 |
|
|
2715 |
predecessor
|
|
2716 |
mantissa = 0 ifTrue: [^self].
|
|
2717 |
mantissa negative ifTrue: [^self negated successor negated].
|
|
2718 |
^mantissa isPowerOfTwo
|
|
2719 |
ifTrue: [self - (self ulp timesTwoPower: -1)]
|
|
2720 |
ifFalse: [self - self ulp]
|
|
2721 |
!
|
|
2722 |
|
|
2723 |
successor
|
|
2724 |
mantissa = 0 ifTrue: [^self].
|
|
2725 |
mantissa negative ifTrue: [^self negated predecessor negated].
|
|
2726 |
^self + self ulp
|
|
2727 |
!
|
|
2728 |
|
|
2729 |
ulp
|
|
2730 |
mantissa = 0 ifTrue: [^self].
|
|
2731 |
^self one timesTwoPower: self exponent - precision + 1
|
|
2732 |
! !
|
|
2733 |
|
7445
|
2734 |
!LargeFloat class methodsFor:'documentation'!
|
|
2735 |
|
|
2736 |
version
|
21803
|
2737 |
^ '$Header$'
|
22042
|
2738 |
!
|
|
2739 |
|
|
2740 |
version_CVS
|
|
2741 |
^ '$Header$'
|
7445
|
2742 |
! !
|
|
2743 |
|
21803
|
2744 |
|
7445
|
2745 |
LargeFloat initialize!
|