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