forked from pharo-project/pharo
/
SmallFloat64.class.st
338 lines (277 loc) · 9.82 KB
/
SmallFloat64.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
"
My instances represent 64-bit Floats whose exponent fits in 8 bits as immediate objects. This representation is only available on 64-bit systems, not 32-bit systems.
"
Class {
#name : #SmallFloat64,
#superclass : #Float,
#type : #immediate,
#category : #'Kernel-Numbers'
}
{ #category : #'instance creation' }
SmallFloat64 class >> basicNew [
self error: 'SmallFloat64s can only be created by performing arithmetic'
]
{ #category : #'instance creation' }
SmallFloat64 class >> basicNew: anInteger [
^self basicNew
]
{ #category : #arithmetic }
SmallFloat64 >> * aNumber [
"Primitive. Answer the result of multiplying the receiver by aNumber.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 549>
^ aNumber adaptToFloat: self andSend: #*
]
{ #category : #arithmetic }
SmallFloat64 >> + aNumber [
"Primitive. Answer the sum of the receiver and aNumber. Essential.
Fail if the argument is not a Float. See Object documentation
whatIsAPrimitive."
<primitive: 541>
^ aNumber adaptToFloat: self andSend: #+
]
{ #category : #arithmetic }
SmallFloat64 >> - aNumber [
"Primitive. Answer the difference between the receiver and aNumber.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 542>
^ aNumber adaptToFloat: self andSend: #-
]
{ #category : #arithmetic }
SmallFloat64 >> / aNumber [
"Primitive. Answer the result of dividing receiver by aNumber.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 550>
aNumber = 0.0 ifTrue: [ ^ ZeroDivide signalWithDividend: self].
^aNumber adaptToFloat: self andSend: #/
]
{ #category : #comparing }
SmallFloat64 >> < aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is less than the argument. Otherwise return false.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 543>
^ aNumber adaptToFloat: self andCompare: #<
]
{ #category : #comparing }
SmallFloat64 >> <= aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is less than or equal to the argument. Otherwise return
false. Fail if the argument is not a Float. Optional. See Object
documentation whatIsAPrimitive."
<primitive: 545>
^ aNumber adaptToFloat: self andCompare: #<=
]
{ #category : #comparing }
SmallFloat64 >> = aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is equal to the argument. Otherwise return false.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 547>
aNumber isNumber ifFalse: [^ false].
^ aNumber adaptToFloat: self andCompare: #=
]
{ #category : #comparing }
SmallFloat64 >> > aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is greater than the argument. Otherwise return false.
Fail if the argument is not a Float. Essential. See Object documentation
whatIsAPrimitive."
<primitive: 544>
^ aNumber adaptToFloat: self andCompare: #>
]
{ #category : #comparing }
SmallFloat64 >> >= aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is greater than or equal to the argument. Otherwise return
false. Fail if the argument is not a Float. Optional. See Object documentation
whatIsAPrimitive. "
<primitive: 546>
^ aNumber adaptToFloat: self andCompare: #>=
]
{ #category : #comparing }
SmallFloat64 >> basicIdentityHash [
"Answer an integer unique to the receiver."
"primitive 171 is the primitiveImmediateAsInteger primitive that converts SmallIntegers to themselves, Characters to their integer codes, and SmallFloat64 to an integer representing their bits. e.g.
#(-0.0 0.0 -1.0 1.0) collect: [:n| n -> n identityHash hex -> (n identityHash bitAnd: 2 << 64 - 1) hex]
{-0.0->'-16r1000000000000000'->'16r1F000000000000000' .
0.0->'16r0'->'16r0' .
-1.0->'-16r810000000000000'->'16r1F7F0000000000000' .
1.0->'16r7F0000000000000'->'16r7F0000000000000'}"
<primitive: 171>
^self primitiveFailed
]
{ #category : #copying }
SmallFloat64 >> clone [
"Answer the receiver, because SmallFloat64s are unique."
^self
]
{ #category : #copying }
SmallFloat64 >> copy [
"Answer the receiver, because SmallFloat64s are unique."
^self
]
{ #category : #copying }
SmallFloat64 >> deepCopy [
"Answer the receiver, because SmallFloat64s are unique."
^self
]
{ #category : #'mathematical functions' }
SmallFloat64 >> exp [
"Answer E raised to the receiver power.
Optional. See Object documentation whatIsAPrimitive."
| base fract correction delta div |
<primitive: 559>
"Taylor series"
"check the special cases"
self < 0.0 ifTrue: [^ (self negated exp) reciprocal].
self = 0.0 ifTrue: [^ 1].
self abs > MaxValLn ifTrue: [self error: 'exp overflow'].
"get first approximation by raising e to integer power"
base := E raisedToInteger: (self truncated).
"now compute the correction with a short Taylor series"
"fract will be 0..1, so correction will be 1..E"
"in the worst case, convergance time is logarithmic with 1/Epsilon"
fract := self fractionPart.
fract = 0.0 ifTrue: [ ^ base ]. "no correction required"
correction := 1.0 + fract.
delta := fract * fract / 2.0.
div := 2.0.
[delta > Epsilon] whileTrue: [
correction := correction + delta.
div := div + 1.0.
delta := delta * fract / div].
correction := correction + delta.
^ base * correction
]
{ #category : #'mathematical functions' }
SmallFloat64 >> exponent [
"Primitive. Consider the receiver to be represented as a power of two
multiplied by a mantissa (between one and two). Answer with the
SmallInteger to whose power two is raised. Optional. See Object
documentation whatIsAPrimitive."
| positive |
<primitive: 553>
self >= 1.0 ifTrue: [^self floorLog: 2].
self > 0.0
ifTrue:
[positive := (1.0 / self) exponent.
self = (1.0 / (1.0 timesTwoPower: positive))
ifTrue: [^positive negated]
ifFalse: [^positive negated - 1]].
self = 0.0 ifTrue: [^-1].
^self negated exponent
]
{ #category : #'truncation and round off' }
SmallFloat64 >> fractionPart [
"Primitive. Answer a Float whose value is the difference between the
receiver and the receiver's asInteger value. Optional. See Object
documentation whatIsAPrimitive."
<primitive: 552>
^self - self truncated asFloat
]
{ #category : #comparing }
SmallFloat64 >> identityHash [
"We need the override since basicIdentityHash is already in SmallInteger range,
the bitShift: 8 of the super implementation would lead to a LargeInteger"
^ self basicIdentityHash
]
{ #category : #testing }
SmallFloat64 >> isImmediateObject [
"This is needed for the boostrap"
^ true
]
{ #category : #'mathematical functions' }
SmallFloat64 >> ln [
"Answer the natural logarithm of the receiver.
Optional. See Object documentation whatIsAPrimitive."
| expt n mant x div pow delta sum eps |
<primitive: 558>
"Taylor series"
self <= 0.0 ifTrue: [^DomainError signal: 'ln is only defined for x > 0' from: 0].
"get a rough estimate from binary exponent"
expt := self exponent.
n := Ln2 * expt.
mant := self timesTwoPower: 0 - expt.
"compute fine correction from mantinssa in Taylor series"
"mant is in the range [0..2]"
"we unroll the loop to avoid use of abs"
x := mant - 1.0.
div := 1.0.
pow := delta := sum := x.
x := x negated. "x <= 0"
eps := Epsilon * (n abs + 1.0).
[delta > eps] whileTrue: [
"pass one: delta is positive"
div := div + 1.0.
pow := pow * x.
delta := pow / div.
sum := sum + delta.
"pass two: delta is negative"
div := div + 1.0.
pow := pow * x.
delta := pow / div.
sum := sum + delta].
^ n + sum
"2.718284 ln 1.0"
]
{ #category : #'memory scanning' }
SmallFloat64 >> nextObject [
"SmallFloat64 are immediate objects, and, as such, do not have successors in object memory."
self shouldNotImplement
]
{ #category : #copying }
SmallFloat64 >> shallowCopy [
"Answer the receiver, because SmallFloat64s are unique."
^self
]
{ #category : #'mathematical functions' }
SmallFloat64 >> timesTwoPower: anInteger [
"Primitive. Answer with the receiver multiplied by 2.0 raised
to the power of the argument.
Optional. See Object documentation whatIsAPrimitive."
<primitive: 554>
anInteger < -29 ifTrue: [^ self * (2.0 raisedToInteger: anInteger)].
anInteger < 0 ifTrue: [^ self / (1 bitShift: (0 - anInteger)) asFloat].
anInteger < 30 ifTrue: [^ self * (1 bitShift: anInteger) asFloat].
^ self * (2.0 raisedToInteger: anInteger)
]
{ #category : #'truncation and round off' }
SmallFloat64 >> truncated [
"Answer with a SmallInteger equal to the value of the receiver without
its fractional part. The primitive fails if the truncated value cannot be
represented as a SmallInteger. In that case, the code below will compute
a LargeInteger truncated value.
Essential. See Object documentation whatIsAPrimitive. "
<primitive: 551>
(self isInfinite or: [self isNaN]) ifTrue: [self error: 'Cannot truncate this number'].
self abs < 2.0e16
ifTrue: ["Fastest way when it may not be an integer"
"^ (self quo: 1073741823.0) * 1073741823 + (self rem: 1073741823.0) truncated"
| di df q r |
di := (SmallInteger maxVal bitShift: -1)+1.
df := di asFloat.
q := self quo: df.
r := self - (q asFloat * df).
^q*di+r truncated]
ifFalse: [^ self asTrueFraction. "Extract all bits of the mantissa and shift if necess"]
]
{ #category : #copying }
SmallFloat64 >> veryDeepCopyWith: deepCopier [
"Answer the receiver, because SmallFloat64s are unique."
^self
]
{ #category : #comparing }
SmallFloat64 >> ~= aNumber [
"Primitive. Compare the receiver with the argument and return true
if the receiver is not equal to the argument. Otherwise return false.
Fail if the argument is not a Float. Optional. See Object documentation
whatIsAPrimitive."
<primitive: 548>
^super ~= aNumber
]