-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rkt
453 lines (367 loc) · 13.9 KB
/
main.rkt
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
#lang racket
(require math/flonum math/bigfloat softposit-rkt herbie/plugin rival)
(define (shift bits fn)
(define shift-val (expt 2 bits))
(λ (x) (fn (- x shift-val))))
(define (unshift bits fn)
(define shift-val (expt 2 bits))
(λ (x) (+ (fn x) shift-val)))
(eprintf "Loading posits support...\n")
(define posit8-max (ordinal->posit8 (- (expt 2 (- 8 1)) 1)))
(define posit16-max (ordinal->posit16 (- (expt 2 (- 16 1)) 1)))
(define posit32-max (ordinal->posit32 (- (expt 2 (- 32 1)) 1)))
;; Max quire is difficult to compute:
;;
;; A quire is a 2s-complement signed fixed-point number with
;; - `000...000` representing 0,
;; - `100...000` representing NAR.
;; Unlike traditional fixed-point numbers, quires are actually symmetric.
;; For an `n`-bit posit, the associated quire has bitwidth `16 * n`
;; with a scale of `2^(16 - 8*n)`.
;;
;; posit quire size max value nearest double w/ epsilon
;; -------|------------|----------------------|------------------------------------------|
;; 8 128 (2^(127) - 1) * 2^-48 2^79 - 2^-48 (6.044629098073146e+23)
;; 16 256 (2^(255) - 1) * 2^-112 2^143 - 2^-112 (1.1150372599265312e+43)
;; 32 512 (2^(511) - 1) * 2^-240 2^270 - 2^-240 (3.794275180128377e+81)
;;
;; Unfortunately, we don't have a good way to convert doubles to quire.
;; The libsoftposit library only has double to posit; the Racket shim
;; incorrectly composes double-posit, posit-quire conversions.
;;
(define quire8-max (quire8-fdp-add (double->quire8 0.0) posit8-max posit8-max))
(define quire8-nmax (quire8-fdp-sub (double->quire8 0.0) posit8-max posit8-max))
(define quire16-max (quire16-fdp-add (double->quire16 0.0) posit16-max posit16-max))
(define quire16-nmax (quire16-fdp-sub (double->quire16 0.0) posit16-max posit16-max))
; These crash
; (define quire32-max (quire32-fdp-add (double->quire32 0.0) posit32-max posit32-max))
; (define quire32-nmax (quire32-fdp-sub (double->quire32 0.0) posit32-max posit32-max))
(define (bf-inf->nan x) (let ([y (bf x)]) (if (bfinfinite? y) +nan.bf y)))
(define (double->posit8* x)
(let ([y (double->posit8 x)])
(if (posit8= y (posit8-nar))
(if (> x 0) posit8-max (posit8-neg posit8-max))
y)))
(define (double->posit16* x)
(let ([y (double->posit16 x)])
(if (posit16= y (posit16-nar))
(if (> x 0) posit16-max (posit16-neg posit16-max))
y)))
(define (double->posit32* x)
(let ([y (double->posit32 x)])
(if (posit32= y (posit32-nar))
(if (> x 0) posit32-max (posit32-neg posit32-max))
y)))
(define (double->quire8* x)
(let ([y (double->quire8 x)])
(if (infinite? (quire8->double y))
(if (> x 0) quire8-max quire8-nmax)
y)))
(define (double->quire16* x)
(let ([y (double->quire16 x)])
(if (infinite? (quire16->double y))
(if (> x 0) quire16-max quire16-nmax)
y)))
#;(define (double->quire32* x)
(let ([y (double->quire32 x)])
(if (infinite? (quire32->double y))
(if (> x 0) quire32-max quire32-nmax)
y)))
;; Defining the representations
(define-representation (posit8 real posit8?)
(compose double->posit8* bigfloat->flonum)
(compose bf-inf->nan posit8->double)
(shift 7 ordinal->posit8)
(unshift 7 posit8->ordinal)
8
(curry posit8= (posit8-nar)))
(define-representation (posit16 real posit16?)
(compose double->posit16* bigfloat->flonum)
(compose bf-inf->nan posit16->double)
(shift 15 ordinal->posit16)
(unshift 15 posit16->ordinal)
16
(curry posit16= (posit16-nar)))
(define-representation (posit32 real posit32?)
(compose double->posit32* bigfloat->flonum)
(compose bf-inf->nan posit32->double)
(shift 31 ordinal->posit32)
(unshift 31 posit32->ordinal)
32
(curry posit32= (posit32-nar)))
;;TODO correct functions for quire (incorrect now for testing)
(define-representation (quire8 real quire8?)
(compose double->quire8* bigfloat->flonum)
(compose bf-inf->nan quire8->double)
(compose double->quire8 ordinal->flonum)
(compose flonum->ordinal quire8->double)
64
(const #f))
(define-representation (quire16 real quire16?)
(compose double->quire16* bigfloat->flonum)
(compose bf-inf->nan quire16->double)
(compose double->quire16 ordinal->flonum)
(compose flonum->ordinal quire16->double)
64
(const #f))
(define-representation (quire32 real quire32?)
(compose double->quire32 bigfloat->flonum) ; TODO: use double->quire32* when crash fixed
(compose bf-inf->nan quire32->double)
(compose double->quire32 ordinal->flonum)
(compose flonum->ordinal quire32->double)
64
(const #f))
;; Defining the operators
(define-operator-impl (+.p8 [x : posit8] [y : posit8]) posit8
#:spec (+ x y)
#:fpcore (! :precision posit8 (+ x y))
#:fl posit8-add)
(define-operator-impl (+.p16 [x : posit16] [y : posit16]) posit16
#:spec (+ x y)
#:fpcore (! :precision posit16 (+ x y))
#:fl posit16-add)
(define-operator-impl (+.p32 [x : posit32] [y : posit32]) posit32
#:spec (+ x y)
#:fpcore (! :precision posit32 (+ x y))
#:fl posit32-add)
(define-operator-impl (neg.p8 [x : posit8]) posit8
#:spec (neg x)
#:fpcore (! :precision posit8 (- x))
#:fl posit8-neg)
(define-operator-impl (neg.p16 [x : posit16]) posit16
#:spec (neg x)
#:fpcore (! :precision posit16 (- x))
#:fl posit16-neg)
(define-operator-impl (neg.p32 [x : posit32]) posit32
#:spec (neg x)
#:fpcore (! :precision posit32 (- x))
#:fl posit32-neg)
(define-operator-impl (-.p8 [x : posit8] [y : posit8]) posit8
#:spec (- x y)
#:fpcore (! :precision posit8 (- x y))
#:fl posit8-sub)
(define-operator-impl (-.p16 [x : posit16] [y : posit16]) posit16
#:spec (- x y)
#:fpcore (! :precision posit16 (- x y))
#:fl posit16-sub)
(define-operator-impl (-.p32 [x : posit32] [y : posit32]) posit32
#:spec (- x y)
#:fpcore (! :precision posit32 (- x y))
#:fl posit32-sub)
(define-operator-impl (*.p8 [x : posit8] [y : posit8]) posit8
#:spec (* x y)
#:fpcore (! :precision posit8 (* x y))
#:fl posit8-mul)
(define-operator-impl (*.p16 [x : posit16] [y : posit16]) posit16
#:spec (* x y)
#:fpcore (! :precision posit16 (* x y))
#:fl posit16-mul)
(define-operator-impl (*.p32 [x : posit32] [y : posit32]) posit32
#:spec (* x y)
#:fpcore (! :precision posit32 (* x y))
#:fl posit32-mul)
(define-operator-impl (/.p8 [x : posit8] [y : posit8]) posit8
#:spec (/ x y)
#:fpcore (! :precision posit8 (/ x y))
#:fl posit8-div)
(define-operator-impl (/.p16 [x : posit16] [y : posit16]) posit16
#:spec (/ x y)
#:fpcore (! :precision posit16 (/ x y))
#:fl posit16-div)
(define-operator-impl (/.p32 [x : posit32] [y : posit32]) posit32
#:spec (/ x y)
#:fpcore (! :precision posit32 (/ x y))
#:fl posit32-div)
(define-operator-impl (sqrt.p8 [x : posit8]) posit8
#:spec (sqrt x)
#:fpcore (! :precision posit8 (sqrt x))
#:fl posit8-sqrt)
(define-operator-impl (sqrt.p16 [x : posit16]) posit16
#:spec (sqrt x)
#:fpcore (! :precision posit16 (sqrt x))
#:fl posit16-sqrt)
(define-operator-impl (sqrt.p32 [x : posit32]) posit32
#:spec (sqrt x)
#:fpcore (! :precision posit32 (sqrt x))
#:fl posit32-sqrt)
(define-operator-impl (==.p8 [x : posit8] [y : posit8]) bool
#:spec (== x y)
#:fl posit8=)
(define-operator-impl (==.p16 [x : posit16] [y : posit16]) bool
#:spec (== x y)
#:fl posit16=)
(define-operator-impl (==.p32 [x : posit32] [y : posit32]) bool
#:spec (== x y)
#:fl posit32=)
(define-operator-impl (!=.p8 [x : posit8] [y : posit8]) bool
#:spec (!= x y)
#:fl (negate posit8=))
(define-operator-impl (!=.p16 [x : posit16] [y : posit16]) bool
#:spec (!= x y)
#:fl (negate posit16=))
(define-operator-impl (!=.p32 [x : posit32] [y : posit32]) bool
#:spec (!= x y)
#:fl (negate posit32=))
(define-operator-impl (<.p8 [x : posit8] [y : posit8]) bool
#:spec (< x y)
#:fl posit8<)
(define-operator-impl (<.p16 [x : posit16] [y : posit16]) bool
#:spec (< x y)
#:fl posit16<)
(define-operator-impl (<.p32 [x : posit32] [y : posit32]) bool
#:spec (< x y)
#:fl posit32<)
(define-operator-impl (>.p8 [x : posit8] [y : posit8]) bool
#:spec (> x y)
#:fl posit8>)
(define-operator-impl (>.p16 [x : posit16] [y : posit16]) bool
#:spec (> x y)
#:fl posit16>)
(define-operator-impl (>.p32 [x : posit32] [y : posit32]) bool
#:spec (> x y)
#:fl posit32>)
(define-operator-impl (<=.p8 [x : posit8] [y : posit8]) bool
#:spec (<= x y)
#:fl posit8<=)
(define-operator-impl (<=.p16 [x : posit16] [y : posit16]) bool
#:spec (<= x y)
#:fl posit16<=)
(define-operator-impl (<=.p32 [x : posit32] [y : posit32]) bool
#:spec (<= x y)
#:fl posit32<=)
(define-operator-impl (>=.p8 [x : posit8] [y : posit8]) bool
#:spec (>= x y)
#:fl posit8>=)
(define-operator-impl (>=.p16 [x : posit16] [y : posit16]) bool
#:spec (>= x y)
#:fl posit16>=)
(define-operator-impl (>=.p32 [x : posit32] [y : posit32]) bool
#:spec (>= x y)
#:fl posit32>=)
;; Posit/float implementations
(define-operator-impl (binary64->posit8 [x : binary64]) posit8
#:spec x
#:fpcore (! :precision posit8 (cast x))
#:fl double->posit8)
(define-operator-impl (binary64->posit16 [x : binary64]) posit16
#:spec x
#:fpcore (! :precision posit16 (cast x))
#:fl double->posit16)
(define-operator-impl (binary64->posit32 [x : binary64]) posit32
#:spec x
#:fpcore (! :precision posit32 (cast x))
#:fl double->posit32)
(define-operator-impl (posit8->binary64 [x : posit8]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl posit8->double)
(define-operator-impl (posit16->binary64 [x : posit16]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl posit16->double)
(define-operator-impl (posit32->binary64 [x : posit32]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl posit32->double)
;; Quire/float implementations
(define-operator-impl (binary64->quire8 [x : binary64]) quire8
#:spec x
#:fpcore (! :precision quire8 (cast x))
#:fl double->quire8)
(define-operator-impl (binary64->quire16 [x : binary64]) quire16
#:spec x
#:fpcore (! :precision quire16 (cast x))
#:fl double->quire16)
(define-operator-impl (binary64->quire32 [x : binary64]) quire32
#:spec x
#:fpcore (! :precision quire32 (cast x))
#:fl double->quire32)
(define-operator-impl (quire8->binary64 [x : quire8]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl quire8->double)
(define-operator-impl (quire16->binary64 [x : quire16]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl quire16->double)
(define-operator-impl (quire32->binary64 [x : quire32]) binary64
#:spec x
#:fpcore (! :precision binary64 (cast x))
#:fl quire32->double)
;; Quire/posit fused ops
;; Quire/posit fused impl
(define-operator-impl (quire8-mul-add [x : quire8] [y : posit8] [z : posit8]) quire8
#:spec (+ x (* y z))
#:fpcore (! :precision quire8 (fdp x y z))
#:fl quire8-fdp-add)
(define-operator-impl (quire16-mul-add [x : quire16] [y : posit16] [z : posit16]) quire16
#:spec (+ x (* y z))
#:fpcore (! :precision quire16 (fdp x y z))
#:fl quire16-fdp-add)
(define-operator-impl (quire32-mul-add [x : quire32] [y : posit32] [z : posit32]) quire32
#:spec (+ x (* y z))
#:fpcore (! :precision quire32 (fdp x y z))
#:fl quire32-fdp-add)
(define-operator-impl (quire8-mul-sub [x : quire8] [y : posit8] [z : posit8]) quire8
#:spec (- x (* y z))
#:fpcore (! :precision quire8 (fdm x y z))
#:fl quire8-fdp-sub)
(define-operator-impl (quire16-mul-sub [x : quire16] [y : posit16] [z : posit16]) quire16
#:spec (- x (* y z))
#:fpcore (! :precision quire16 (fdm x y z))
#:fl quire16-fdp-sub)
(define-operator-impl (quire32-mul-sub [x : quire32] [y : posit32] [z : posit32]) quire32
#:spec (- x (* y z))
#:fpcore (! :precision quire32 (fdm x y z))
#:fl quire32-fdp-sub)
;; Quire/posit impl
(define-operator-impl (quire8->posit8 [x : quire8]) posit8
#:spec x
#:fpcore (! :precision posit8 (cast x))
#:fl quire8->posit8)
(define-operator-impl (quire16->posit16 [x : quire16]) posit16
#:spec x
#:fpcore (! :precision posit16 (cast x))
#:fl quire16->posit16)
(define-operator-impl (quire32->posit32 [x : quire32]) posit32
#:spec x
#:fpcore (! :precision posit32 (cast x))
#:fl quire32->posit32)
(define-operator-impl (posit8->quire8 [x : posit8]) quire8
#:spec x
#:fpcore (! :precision quire8 (cast x))
#:fl posit8->quire8)
(define-operator-impl (posit16->quire16 [x : posit16]) quire16
#:spec x
#:fpcore (! :precision quire16 (cast x))
#:fl posit16->quire16)
(define-operator-impl (posit32->quire32 [x : posit32]) quire32
#:spec x
#:fpcore (! :precision quire32 (cast x))
#:fl posit32->quire32)
;; Defining the rules
(define-ruleset commutativity.p16 (arithmetic simplify posit)
#:type ([a posit16] [b posit16])
[+-commutative.p16 (+.p16 a b) (+.p16 b a)]
[*-commutative.p16 (*.p16 a b) (*.p16 b a)])
; Posit conversions
(define-ruleset insert-p16 (arithmetic posit)
#:type ([a binary64])
[insert-posit16 a (posit16->binary64 (binary64->posit16 a))])
(define-ruleset remove-p16 (arithmetic simplify posit)
#:type ([a binary64])
[remove-posit16 (posit16->binary64 (binary64->posit16 a)) a])
;; TODO: Multiply add to mulAdd
;; TODO: We only cast back to posit after quire operations because herbie can't handle
;; non-double output right now (similar situtation for posits)
(define-ruleset q16-arithmetic (arithmetic posit)
#:type ([a posit16] [b posit16] [c posit16] [q quire16])
[introduce-quire a (quire16->posit16 (posit16->quire16 a))]
[insert-quire-add (+.p16 (quire16->posit16 q) a)
(quire16->posit16 (quire16-mul-add q a (binary64->posit16 1.0)))]
[insert-quire-sub (-.p16 (quire16->posit16 q) a)
(quire16->posit16 (quire16-mul-sub q a (binary64->posit16 1.0)))]
[insert-quire-fdp-add (+.p16 (quire16->posit16 q) (*.p16 a b))
(quire16->posit16 (quire16-mul-add q a b))]
[insert-quire-fdp-sub (-.p16 (quire16->posit16 q) (*.p16 a b))
(quire16->posit16 (quire16-mul-sub q a b))])