float-formats 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,669 +1,633 @@
1
- # Float-Formats
2
- # Definition of common floating-point formats
3
-
4
- require 'nio'
5
- require 'nio/sugar'
6
-
7
- require 'enumerator'
8
-
9
- require 'float-formats/classes.rb'
10
-
11
-
12
- module FltPnt
13
-
14
-
15
- # Floating Point Format Definitions ==========================================
16
-
17
- # Helper methods to define IEEE 754r formats
18
- module IEEE
19
- # Define an IEEE binary format by passing parameters in a hash;
20
- # :significand and :exponent are used to defined the fields,
21
- # optional parameters may follow.
22
- def self.binary(parameters)
23
- significand_bits = parameters[:significand]
24
- exponent_bits = parameters[:exponent]
25
- BinaryFormat.new({
26
- :fields=>[:significand,significand_bits,:exponent,exponent_bits,:sign,1],
27
- :bias=>2**(exponent_bits-1)-1, :bias_mode=>:normalized_significand,
28
- :hidden_bit=>true,
29
- :endianness=>:little_endian, :round=>:even,
30
- :gradual_underflow=>true, :infinity=>true, :nan=>true
31
- }.merge(parameters))
32
- end
33
-
34
- # Define an IEEE binary interchange format given its width in bits
35
- def self.interchange_binary(width_in_bits, options={})
36
- raise "Invalid IEEE binary interchange format definition: size (#{width_in_bits}) is not valid" unless (width_in_bits%32)==0 && (width_in_bits/32)>=4
37
- p = width_in_bits - (4*Math.log(width_in_bits)/Math.log(2)).round.to_i + 13
38
- binary({:significand=>p-1, :exponent=>width_in_bits-p}.merge(options))
39
- end
40
-
41
- # Define an IEEE decimal format by passing parameters in a hash;
42
- # :significand and :exponent are used to defined the fields,
43
- # optional parameters may follow.
44
- def self.decimal(parameters)
45
- significand_continuation_bits = parameters[:significand]
46
- exponent_continuation_bits = parameters[:exponent]
47
- DPDFormat.new({
48
- :fields=>[:significand_continuation,significand_continuation_bits,:exponent_continuation,exponent_continuation_bits,:combination,5,:sign,1],
49
- :endianness=>:big_endian,
50
- :gradual_underflow=>true, :infinity=>true, :nan=>true
51
- }.merge(parameters))
52
- end
53
-
54
- # Define an IEEE decimal interchange format given its width in bits
55
- def self.interchange_decimal(width_in_bits, options={})
56
- raise "Invalid IEEE decimal interchange format definition: size (#{width_in_bits}) is not valid" unless (width_in_bits%32)==0
57
- p = width_in_bits*9/32 - 2
58
- t = (p-1)*10/3
59
- w = width_in_bits - t - 6
60
- decimal({:significand=>t, :exponent=>w}.merge(options))
61
- end
62
-
63
- end
64
-
65
- # IEEE 754 binary types, as stored in little endian architectures such as Intel, Alpha
66
-
67
- IEEE_binary16 = IEEE.binary(:significand=>10, :exponent=>5)
68
- IEEE_binary32 = IEEE.binary(:significand=>23,:exponent=>8)
69
- IEEE_binary64 = IEEE.binary(:significand=>52,:exponent=>11)
70
- IEEE_binary80 = IEEE.binary(:significand=>64,:exponent=>15, :hidden_bit=>false, :min_encoded_exp=>1)
71
- IEEE_binary128 = IEEE.binary(:significand=>112,:exponent=>15)
72
-
73
-
74
- # IEEE 754 in big endian order (SPARC, Motorola 68k, PowerPC)
75
-
76
- IEEE_binary16_BE = IEEE.binary(:significand=>10, :exponent=>5, :endianness=>:big_endian)
77
- IEEE_binary32_BE = IEEE.binary(:significand=>23,:exponent=>8, :endianness=>:big_endian)
78
- IEEE_binary64_BE = IEEE.binary(:significand=>52,:exponent=>11, :endianness=>:big_endian)
79
- IEEE_binary80_BE = IEEE.binary(:significand=>64,:exponent=>15, :endianness=>:big_endian, :hidden_bit=>false, :min_encoded_exp=>1)
80
- IEEE_binary128_BE = IEEE.binary(:significand=>112,:exponent=>15, :endianness=>:big_endian)
81
-
82
-
83
- # some IEEE745r interchange binary formats
84
-
85
- IEEE_binary256 = IEEE.interchange_binary(256)
86
- IEEE_binary512 = IEEE.interchange_binary(512)
87
- IEEE_binary1024 = IEEE.interchange_binary(1024)
88
- IEEE_binary256_BE = IEEE.interchange_binary(256, :endianness=>:big_endian)
89
- IEEE_binary512_BE = IEEE.interchange_binary(512, :endianness=>:big_endian)
90
- IEEE_binary1024_BE = IEEE.interchange_binary(1024, :endianness=>:big_endian)
91
-
92
-
93
- # old names
94
- IEEE_binaryx = IEEE_binary80
95
- IEEE_HALF = IEEE_binary16
96
- IEEE_SINGLE = IEEE_binary32
97
- IEEE_DOUBLE = IEEE_binary64
98
- IEEE_EXTENDED = IEEE_binary80
99
- IEEE_QUAD = IEEE_binary128
100
- IEEE_128 = IEEE_binary128IEEE_H_BE = IEEE_binary16_BE
101
- IEEE_S_BE = IEEE_binary32_BE
102
- IEEE_D_BE = IEEE_binary64_BE
103
- IEEE_X_BE = IEEE_binary80_BE
104
- IEEE_128_BE = IEEE_binary128_BE
105
- IEEE_Q_BE = IEEE_binary128_BE
106
-
107
-
108
- # Decimal IEEE 754r formats
109
-
110
- IEEE_decimal32 = IEEE.decimal(:significand=>20, :exponent=>6)
111
- IEEE_decimal64 = IEEE.decimal(:significand=>50, :exponent=>8)
112
- IEEE_decimal128 = IEEE.decimal(:significand=>110, :exponent=>12)
113
-
114
- # some IEEE745r interchange binary formats
115
-
116
- IEEE_decimal96 = IEEE.interchange_decimal(96)
117
- IEEE_decimal192 = IEEE.interchange_decimal(192)
118
- IEEE_decimal256 = IEEE.interchange_decimal(256)
119
-
120
- # old names
121
-
122
- IEEE_DEC32 = IEEE_decimal32
123
- IEEE_DEC64 = IEEE_decimal64
124
- IEEE_DEC128 = IEEE_decimal128
125
-
126
- # Excess 128 used by Microsoft Basic in 8-bit micros, Spectrum, ...
127
-
128
- XS128 = BinaryFormat.new(
129
- :fields=>[:significand,31,:sign,1,:exponent,8],
130
- :bias=>128, :bias_mode=>:fractional_significand,
131
- :hidden_bit=>true,
132
- :endianness=>:big_endian, :round=>:inf,
133
- :endianness=>:big_endian,
134
- :gradual_underflow=>false, :infinity=>false, :nan=>false
135
- )
136
-
137
- # HP-3000 excess 256 format, HP-Tandem...
138
-
139
- XS256 = BinaryFormat.new(
140
- :fields=>[:significand,22,:exponent,9,:sign,1],
141
- :bias=>256, :bias_mode=>:normalized_significand,
142
- :hidden_bit=>true, :min_encoded_exp=>0,
143
- :endianness=>:big_endian, :round=>:inf,
144
- :gradual_underflow=>false, :infinity=>false, :nan=>false
145
- )
146
- XS256_DOUBLE = BinaryFormat.new(
147
- :fields=>[:significand,54,:exponent,9,:sign,1],
148
- :bias=>256, :bias_mode=>:normalized_significand,
149
- :hidden_bit=>true, :min_encoded_exp=>0,
150
- :endianness=>:big_endian, :round=>:inf,
151
- :gradual_underflow=>false, :infinity=>false, :nan=>false
152
- )
153
-
154
- # Borland Pascal 48 bits "Real" Format
155
-
156
- BORLAND48 = BinaryFormat.new(
157
- :fields=>[:exponent,8,:significand,39,:sign,1],
158
- :bias=>128, :bias_mode=>:fractional_significand,
159
- :hidden_bit=>true,
160
- :endianness=>:little_endian,
161
- :gradual_underflow=>false, :infinity=>false, :nan=>false
162
- )
163
-
164
- # Microsoft Binary Floating-point (Quickbasic)
165
-
166
- MBF_SINGLE = BinaryFormat.new(
167
- :fields=>[:significand,23,:sign,1,:exponent,8],
168
- :bias=>128, :bias_mode=>:fractional_significand,
169
- :hidden_bit=>true,
170
- :endianness=>:little_endian,
171
- :gradual_underflow=>false, :infinity=>false, :nan=>false
172
- )
173
- MBF_DOUBLE = BinaryFormat.new(
174
- :fields=>[:significand,55,:sign,1,:exponent,8],
175
- :bias=>128, :bias_mode=>:fractional_significand,
176
- :hidden_bit=>true,
177
- :endianness=>:little_endian,
178
- :gradual_underflow=>false, :infinity=>false, :nan=>false
179
- )
180
-
181
- # DEC formats (VAX)
182
-
183
- VAX_F = BinaryFormat.new(
184
- :fields=>[:significand, 23, :exponent, 8, :sign, 1],
185
- :bias=>128, :bias_mode=>:fractional_significand,
186
- :hidden_bit=>true,
187
- :endianness=>:little_big_endian,
188
- :gradual_underflow=>false, :infinity=>false, :nan=>false
189
- )
190
-
191
- VAX_D = BinaryFormat.new(
192
- :fields=>[:significand, 55, :exponent, 8, :sign, 1],
193
- :bias=>128, :bias_mode=>:fractional_significand,
194
- :hidden_bit=>true,
195
- :endianness=>:little_big_endian,
196
- :gradual_underflow=>false, :infinity=>false, :nan=>false
197
- )
198
-
199
- VAX_G = BinaryFormat.new(
200
- :fields=>[:significand, 52, :exponent, 11, :sign, 1],
201
- :bias=>1024, :bias_mode=>:fractional_significand,
202
- :hidden_bit=>true,
203
- :endianness=>:little_big_endian,
204
- :gradual_underflow=>false, :infinity=>false, :nan=>false
205
- )
206
-
207
- VAX_H = BinaryFormat.new(
208
- :fields=>[:significand, 112, :exponent, 15, :sign, 1],
209
- :bias=>16384, :bias_mode=>:fractional_significand,
210
- :hidden_bit=>true,
211
- :endianness=>:little_big_endian,
212
- :gradual_underflow=>false, :infinity=>false, :nan=>false
213
- )
214
-
215
- # DEC PDP 11 variants (minimum exponent used for normalized values other than zero)
216
-
217
- PDP11_F = BinaryFormat.new(
218
- :fields=>[:significand, 23, :exponent, 8, :sign, 1],
219
- :bias=>128, :bias_mode=>:fractional_significand,
220
- :hidden_bit=>true, :min_encoded_exp=>0,
221
- :endianness=>:little_big_endian,
222
- :gradual_underflow=>false, :infinity=>false, :nan=>false
223
- )
224
-
225
- PDP11_D = BinaryFormat.new(
226
- :fields=>[:significand, 55, :exponent, 8, :sign, 1],
227
- :bias=>128, :bias_mode=>:fractional_significand,
228
- :hidden_bit=>true, :min_encoded_exp=>0,
229
- :endianness=>:little_big_endian,
230
- :gradual_underflow=>false, :infinity=>false, :nan=>false
231
- )
232
-
233
-
234
- # Format used in HP Saturn-based RPL calculators (HP48,HP49,HP50, also HP32s, HP42s --which use RPL internally)
235
- # (these formats are not used in the HP-71B which is a Saturn, non-RPL machine)
236
-
237
- SATURN = BCDFormat.new(
238
- :fields=>[:prolog,5,:exponent,3,:significand,12,:sign,1],
239
- :fields_handler=>lambda{|fields| fields[0]=2933},
240
- :exponent_mode=>:radix_complement,
241
- :endianness=>:little_endian, :round=>:even,
242
- :gradual_underflow=>false, :infinity=>false, :nan=>false
243
- )
244
- SATURN_X = BCDFormat.new(
245
- :fields=>[:prolog,5,:exponent,5,:significand,15,:sign,1],
246
- :fields_handler=>lambda{|fields| fields[0]=2955},
247
- :exponent_mode=>:radix_complement,
248
- :endianness=>:little_endian, :round=>:even,
249
- :gradual_underflow=>false, :infinity=>false, :nan=>false
250
- )
251
-
252
-
253
- RPL = SATURN
254
- RPL_X = SATURN_X
255
-
256
- # SATURN HP-71B (IEEE, NON-RPL) formats
257
-
258
- # HP-71B REAL format (12-form) which is stored in a single register
259
- HP71B = BCDFormat.new(
260
- :fields=>[:exponent,3,:significand,12,:sign,1],
261
- :exponent_mode=>:radix_complement,
262
- :endianness=>:little_endian, :round=>:even,
263
- :gradual_underflow=>true, :infinity=>true, :nan=>true,
264
- :denormal_encoded_exp=>501,
265
- :nan_encoded_exp=>"F01", # signaling NaN is F02
266
- :infinite_encoded_exp=>"F00"
267
- )
268
-
269
- # HP-71B internal 15-digit format (15-form), stored in a pair of registers
270
- # we use here a little-endian order for the registers, otherwise the
271
- # definition would be [:significand,15,:unused1,1,:exponent,5,:unused2,10,:sign,1]
272
- HP71B_X = BCDFormat.new(
273
- :fields=>[:exponent,5,:unused2,10,:sign,1, :significand,15,:unused1,1],
274
- :exponent_mode=>:radix_complement,
275
- :endianness=>:little_endian, :round=>:even,
276
- :gradual_underflow=>false, :infinity=>true, :nan=>true,
277
- :nan_encoded_exp=>"00F01",
278
- :infinite_encoded_exp=>"00F00"
279
- )
280
-
281
- # Format used in classic HP calculators (HP-35, ... HP-15C)
282
- # Endianness is indeterminate, since these machines have named registers that
283
- # hold a floating-point value in a single 56-bit word.
284
- # (But intra-word field/nibble addressing is little-endian)
285
- HP_CLASSIC = BCDFormat.new(
286
- :fields=>[:exponent,3,:significand,10,:sign,1],
287
- :exponent_mode=>:radix_complement,
288
- :min_exp=>-99, :max_exp=>99, # the most significant nibble of exponent if for sign only
289
- :endianness=>:big_endian, :round=>:inf,
290
- :gradual_underflow=>false, :infinity=>false, :nan=>false
291
- )
292
-
293
-
294
- # IBM Floating Point Architecture (IBM 360,370, DG Eclipse, ...)
295
-
296
- # short
297
- IBM32 = HexadecimalFormat.new(
298
- :fields=>[:significand,24,:exponent,7,:sign,1],
299
- :bias=>64, :bias_mode=>:fractional_significand,
300
- :endianness=>:big_endian
301
- )
302
- # long
303
- IBM64 = HexadecimalFormat.new(
304
- :fields=>[:significand,56,:exponent,7,:sign,1],
305
- :bias=>64, :bias_mode=>:fractional_significand,
306
- :endianness=>:big_endian
307
- )
308
-
309
- # extended: two long values pasted together
310
- IBM128 = HexadecimalFormat.new(
311
- :fields=>[:significand,14*4,:lo_exponent,7,:lo_sign,1,:significand,14*4,:exponent,7,:sign,1],
312
- :fields_handler=>lambda{|fields| fields[1]=(fields[4]>=14&&fields[4]<127) ? fields[4]-14 : fields[4];fields[2]=fields[5] },
313
- :bias=>64, :bias_mode=>:fractional_significand,
314
- :min_encoded_exp=>14, # to avoid out-of-range exponents in the lower half
315
- :endianness=>:big_endian
316
- )
317
-
318
- # It think this has never been used:
319
- IBMX = HexadecimalFormat.new(
320
- :fields=>[:significand,14*4,:exponent,7,:unused_sign,1,:significand,14*4,:exponent,7,:sign,1],
321
- :fields_handler=>lambda{|fields| fields[2]=0},
322
- :bias=>8192, :bias_mode=>:fractional_significand,
323
- :endianness=>:big_endian
324
- )
325
-
326
- # Cray-1
327
- CRAY = BinaryFormat.new(
328
- :fields=>[:significand,48,:exponent,15,:sign,1],
329
- :bias=>16384, :bias_mode=>:fractional_significand,
330
- :hidden_bit=>false,
331
- :min_encoded_exp=>8192, :max_encoded_exp=>24575, :zero_encoded_exp=>0,
332
- :endianness=>:big_endian,
333
- :gradual_underflow=>false, :infinity=>false, :nan=>false
334
- )
335
-
336
- # CDC 6600/7600
337
- # Byte endianness is arbitrary, since these machines were word-addressable, in 60-bit words,
338
- # but the two words used in double precision numbers are in big endian order
339
- # TO DO: apply this:
340
- # The exponent encoded value 1023 is used for NaN
341
- # The exponent encoded value 0 is used for underflow
342
- # The exponent encoded value 2047 is used for overflow
343
- #
344
- # The exponent needs special treatment, because instead of excess encoding, which is equivalent to two's complement followed
345
- # by sign bit reversal, one's complement followed by sign bit reversal is used, which is equivalent
346
- # to use a bias diminished by one for negative exponents. Note that the exponent encoded value that equals the bias is
347
- # not used (is used as a NaN indicator)
348
- class CDCFLoatingPoint < BinaryFormat # :nodoc:
349
- def encode_exponent(e,mode)
350
- ee = super
351
- ee -= 1 if e<0
352
- ee
353
- end
354
- def decode_exponent(ee,mode)
355
- e = super
356
- e += 1 if e<0
357
- e
358
- end
359
- end
360
-
361
- CDC_SINGLE = CDCFLoatingPoint.new(
362
- :fields=>[:significand,48, :exponent,11, :sign,1],
363
- :bias=>1024, :bias_mode=>:integral_significand,
364
- :min_exp=>-1023,
365
- :neg_mode=>:diminished_radix_complement,
366
- :hidden_bit=>false,
367
- :endianess=>:big_endian,
368
- :gradual_underflow=>false, :infinity=>false, :nan=>false
369
- )
370
-
371
- # The CDC_DOUBLE can be splitted in two CDC_SINGLE values:
372
- # get_bitfields(v,[CDC_SINGLE.total_bits]*2,CDC_DOUBLE.endianness).collect{|x| int_to_bytes(x,0,CDC_SINGLE.endianness)}
373
- # and the value of the double is the sum of the values of the singles.
374
- # Unlike the single, we must use :fractional_significand mode because with :integral_significand
375
- # the exponent would refer to the whole significand, but it must refer only to the most significant half.
376
- # we substract the number of bits in the single to the bias and exponent because of this change,
377
- # and add 48 to the min_exponent to avoid the exponent of the low order single to be out of range
378
- # because the exponent of the low order single is adjusted to
379
- # the position of its digits by substracting 48 from the high order exponent
380
- # when its exponent would be out of range
381
- # Note that when computing the low order exponent with the fields handler we must take into account the sign
382
- # because for negative numbers all the fields are one-complemented.
383
- CDC_DOUBLE= CDCFLoatingPoint.new(
384
- :fields=>[:significand,48,:lo_exponent,11,:lo_sign,1,:significand,48,:exponent,11,:sign,1],
385
- :fields_handler=>lambda{|fields|
386
- fields[1]=(fields[4]>0&&fields[4]<2047) ? fields[4]-((-1)**fields[5])*48 : fields[4]
387
- fields[2]=fields[5]
388
- },
389
- :bias=>1024-48, :bias_mode=>:fractional_significand,
390
- :min_encoded_exp=>48+1, # + 1 because the bias for negative is 1023
391
- :neg_mode=>:diminished_radix_complement,
392
- :hidden_bit=>false,
393
- :endianess=>:big_endian,
394
- :gradual_underflow=>false, :infinity=>false, :nan=>false
395
- )
396
-
397
-
398
- # Univac 1100
399
- # Byte endianness is arbitrary, since these machines were word-addressable, in 36-bit words,
400
- # but the two words used in double precision numbers are in big endian order
401
- UNIVAC_SINGLE = BinaryFormat.new(
402
- :fields=>[:significand,27, :exponent,8, :sign,1],
403
- :bias=>128, :bias_mode=>:fractional_significand,
404
- :neg_mode=>:diminished_radix_complement,
405
- :hidden_bit=>false,
406
- :endianess=>:big_endian,
407
- :gradual_underflow=>false, :infinity=>false, :nan=>false
408
- )
409
-
410
- UNIVAC_DOUBLE = BinaryFormat.new(
411
- :fields=>[:significand,60, :exponent,11, :sign,1],
412
- :bias=>1024, :bias_mode=>:fractional_significand,
413
- :neg_mode=>:diminished_radix_complement,
414
- :hidden_bit=>false,
415
- :endianess=>:big_endian,
416
- :gradual_underflow=>false, :infinity=>false, :nan=>false
417
- )
418
-
419
-
420
- # :stopdoc: # the next definition is not handled correctly by RDoc
421
- APPLE_INSANE = BinaryFormat.new(
422
- :fields=>[:significand,23,:sign,1,:exponent,8],
423
- :bias=>128, :bias_mode=>:normalized_significand,
424
- :hidden_bit=>false, :min_encoded_exp=>0,
425
- :neg_mode=>:radix_complement_significand,
426
- :endianness=>:big_endian,
427
- :gradual_underflow=>true, :infinity=>false, :nan=>false) { |fp|
428
- # This needs a peculiar treatment for the negative values, which not simply use two's complement
429
- # but also avoid having the sign and msb of the significand equal.
430
- # Note that here we have a separate sign bit, but it can also be considered as the msb of the significand
431
- # in two's complement, in which case the radix point is after the two msbs, which are the ones that
432
- # should not be equal. (except for zero and other values using the minimum exponent).
433
- def fp.neg_significand_exponent(s,f,e)
434
- #puts "before: #{s} #{f.to_s(16)}"
435
- f,e = super
436
- s = (s+1)%2
437
- #print "neg #{f.to_s(16)}"
438
- if e>@zero_encoded_exp && f==0
439
- f = 1<<(significand_digits-1)
440
- e += 1
441
- else
442
- while (e>@zero_encoded_exp) && (f>>(significand_digits-1))&1 == s
443
- e -= 1
444
- f = (f << 1) & (radix_power(significand_digits)-1)
445
- #print " << "
446
- end
447
- end
448
- #puts ""
449
- [f,e]
450
- end
451
- }
452
- # :startdoc:
453
-
454
-
455
- # Sofware floating point implementatin for the Apple II (6502)
456
- # the significand & sign are a single field in two's commplement
457
- APPLE = APPLE_INSANE
458
-
459
- # Wang 2200 Basic Decimal floating point
460
- WANG2200 = BCDFormat.new(
461
- :fields=>[:significand,13,:exponent,2,:signs,1],
462
- :endiannes=>:big_endian,
463
- :bias_mode=>:normalized_significand,
464
- :min_exp=>-99, :max_exp=>99,
465
- :zero_encoded_exp=>0, :min_encoded_exp=>0
466
- ) { |wang2200|
467
-
468
- # needs special handling because significand and exponent are both stored
469
- # as sign-magnitude, with both signs combined in a single nibble (decimal digit)
470
- def wang2200.to_integral_sign_significand_exponent(v)
471
- f = to_fields_hash(v)
472
- m = f[:significand]
473
- e = f[:exponent]
474
- ss = f[:signs]
475
- s = (ss==9 || ss==1) ? 9 : 0
476
- es = (ss==8 || ss==1) ? 9 : 0
477
- if m==0
478
- # +-zero
479
- e = :zero
480
- elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
481
- # +-inifinity
482
- e = :infinity
483
- elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
484
- # NaN
485
- e = :nan
486
- else
487
- # normalized number
488
- # reverse exponent nibbles
489
- e = ("%0#{exponent_digits}d"%e).reverse.to_i
490
- e = -e if es%2!=0
491
- e -= (significand_digits-1)
492
- end
493
- [s,m,e]
494
- end
495
-
496
- def wang2200.from_integral_sign_significand_exponent(s,m,e)
497
- msb = radix_power(@significand_digits-1)
498
- es = 0
499
- if e==:zero
500
- e = @zero_encoded_exp
501
- m = 0
502
- elsif e==:infinity
503
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
504
- m = 0
505
- elsif e==:nan
506
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
507
- s = minus_sign_value # ?
508
- m = radix_power(@significand_digits-2) if m==0
509
- elsif e==:denormal
510
- e = @denormal_encoded_exp
511
- else
512
- # to do: try to adjust m to keep e in range if out of valid range
513
- # to do: reduce m and adjust e if m too big
514
-
515
- min_exp = radix_min_exp(:integral_significand)
516
- if m>0
517
- while m<msb && e>min_exp
518
- e -= 1
519
- m *= radix
520
- end
521
- end
522
- if m<msb && @denormal_encoded_exp
523
- e = @denormal_encoded_exp
524
- elsif m==0 # => && @denormal_encoded_exp.nil?
525
- e = 0
526
- else
527
- e += (significand_digits-1)
528
- if e<0
529
- e = -e
530
- es = 9
531
- else
532
- es = 0
533
- end
534
- end
535
- end
536
- ss = (s%2) + (es==0 ? 0 : 8)
537
- # reverse exponent nibbles
538
- e = ("%0#{exponent_digits}d"%e).reverse.to_i
539
- from_fields_hash :signs=>ss, :significand=>m, :exponent=>e
540
- end
541
- }
542
-
543
-
544
- # C51 (C compiler for the Intel 8051) BCD Floating point formats
545
- class C51BCDFloatingPoint < BCDFormat # :nodoc:
546
- def exponent_radix
547
- 2
548
- end
549
- def exponent_digits
550
- @fields[:exponent_sign]*4-1
551
- end
552
- def minus_sign_value
553
- 1
554
- end
555
- def to_integral_sign_significand_exponent(v)
556
- f = to_fields_hash(v)
557
- m = f[:significand]
558
- e_s = f[:exponent_sign]
559
- exp_bits = exponent_digits
560
- e = e_s & (2**exp_bits-1)
561
- s = e_s >> exp_bits
562
- if m==0
563
- # +-zero
564
- e = :zero
565
- elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
566
- # +-inifinity
567
- e = :infinity
568
- elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
569
- # NaN
570
- e = :nan
571
- else
572
- # normalized number
573
- e = decode_exponent(e, :integral_significand)
574
- end
575
- [s,m,e]
576
- end
577
- def bcd_field?(i)
578
- @field_meaning[i]==:significand
579
- end
580
-
581
- def from_integral_sign_significand_exponent(s,m,e)
582
- msb = radix_power(@significand_digits-1)
583
- es = 0
584
- if e==:zero
585
- e = @zero_encoded_exp
586
- m = 0
587
- elsif e==:infinity
588
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
589
- m = 0
590
- elsif e==:nan
591
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
592
- s = minus_sign_value # ?
593
- m = radix_power(@significand_digits-2) if m==0
594
- elsif e==:denormal
595
- e = @denormal_encoded_exp
596
- else
597
- # to do: try to adjust m to keep e in range if out of valid range
598
- # to do: reduce m and adjust e if m too big
599
-
600
- min_exp = radix_min_exp(:integral_significand)
601
- if m>0
602
- while m<msb && e>min_exp
603
- e -= 1
604
- m *= radix
605
- end
606
- end
607
- if m<msb && @denormal_encoded_exp
608
- e = @denormal_encoded_exp
609
- elsif m==0 # => && @denormal_encoded_exp.nil?
610
- e = 0
611
- else
612
- e = encode_exponent(e, :integral_significand)
613
- end
614
- end
615
- exp_bits = exponent_digits
616
- e_s = e + (s << exp_bits)
617
- from_fields_hash :significand=>m, :exponent_sign=>e_s
618
- end
619
- end
620
-
621
- C51_BCD_FLOAT = C51BCDFloatingPoint.new(
622
- :fields=>[:exponent_sign, 2, :significand,6],
623
- :endiannes=>:big_endian,
624
- :bias=>64, :bias_mode=>:fractional_significand,
625
- :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
626
- )
627
- C51_BCD_DOUBLE = C51BCDFloatingPoint.new(
628
- :fields=>[:exponent_sign, 2, :significand,10],
629
- :endiannes=>:big_endian,
630
- :bias=>64, :bias_mode=>:fractional_significand,
631
- :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
632
- )
633
- C51_BCD_LONG_DOUBLE = C51BCDFloatingPoint.new(
634
- :fields=>[:exponent_sign, 2, :significand,12],
635
- :endiannes=>:big_endian,
636
- :bias=>64, :bias_mode=>:fractional_significand,
637
- :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
638
- )
639
-
640
- =begin
641
- # Note:
642
- # One could be tempted to define a double-double type as:
643
- IEEE_DOUBLE_DOUBLE = BinaryFormat.new(
644
- :fields=>[:significand,52,:lo_exponent,11,:lo_sign,1,:significand,52,:exponent,11,:sign,1],
645
- :fields_handler=>lambda{|fields|
646
- fields[2] = fields[5];
647
- bits,max_exp = 53,2047
648
- if fields[4]>bits && fields[4]<max_exp
649
- fields[1] = fields[4] - bits
650
- else # 0, denormals, small numbers, NaN, Infinities
651
- fields[0] = fields[1] = 0
652
- end
653
- },
654
- :bias=>1023, :bias_mode=>:normalized_significand,
655
- :hidden_bit=>true,
656
- :endianness=>:little_endian, :round=>:even,
657
- :gradual_underflow=>true, :infinity=>true, :nan=>true
658
- )
659
- # But this is incorrect since there's a hidden bit in the low double too and it must be normalized.
660
- # In general the halfs of the significand need not be adjacent, they
661
- # can have exponets with a separation higher than 53; (in fact the minimum separation seems to be 54)
662
- # and they can have different sings, too;
663
- # double-double is too tricky to be supported by this package.
664
- =end
665
-
666
-
667
-
668
- end
669
-
1
+ # Float-Formats
2
+ # Definition of common floating-point formats
3
+
4
+ require 'nio'
5
+ require 'nio/sugar'
6
+
7
+ require 'enumerator'
8
+
9
+ require 'float-formats/classes.rb'
10
+
11
+
12
+ module Flt
13
+
14
+
15
+ # Floating Point Format Definitions ==========================================
16
+
17
+ # Helper methods to define IEEE 754r formats
18
+ module IEEE
19
+ # Define an IEEE binary format by passing parameters in a hash;
20
+ # :significand and :exponent are used to defined the fields,
21
+ # optional parameters may follow.
22
+ def self.binary(name, parameters)
23
+ significand_bits = parameters[:significand]
24
+ exponent_bits = parameters[:exponent]
25
+ Flt.define(name,{
26
+ :base=>BinaryFormat,
27
+ :fields=>[:significand,significand_bits,:exponent,exponent_bits,:sign,1],
28
+ :bias=>2**(exponent_bits-1)-1, :bias_mode=>:scientific_significand,
29
+ :hidden_bit=>true,
30
+ :endianness=>:little_endian, :round=>:half_even,
31
+ :gradual_underflow=>true, :infinity=>true, :nan=>true
32
+ }.merge(parameters))
33
+ end
34
+
35
+ # Define an IEEE binary interchange format given its width in bits
36
+ def self.interchange_binary(name,width_in_bits, options={})
37
+ raise "Invalid IEEE binary interchange format definition: size (#{width_in_bits}) is not valid" unless (width_in_bits%32)==0 && (width_in_bits/32)>=4
38
+ p = width_in_bits - (4*Math.log(width_in_bits)/Math.log(2)).round.to_i + 13
39
+ binary(name,{:significand=>p-1, :exponent=>width_in_bits-p}.merge(options))
40
+ end
41
+
42
+ # Define an IEEE decimal format by passing parameters in a hash;
43
+ # :significand and :exponent are used to defined the fields,
44
+ # optional parameters may follow.
45
+ def self.decimal(name,parameters)
46
+ significand_continuation_bits = parameters[:significand]
47
+ exponent_continuation_bits = parameters[:exponent]
48
+ Flt.define(name,{
49
+ :base=>DPDFormat,
50
+ :fields=>[:significand_continuation,significand_continuation_bits,:exponent_continuation,exponent_continuation_bits,:combination,5,:sign,1],
51
+ :normalized=>false,
52
+ :endianness=>:big_endian,
53
+ :gradual_underflow=>true, :infinity=>true, :nan=>true,
54
+ :round=>:half_even
55
+ }.merge(parameters))
56
+ end
57
+
58
+ # Define an IEEE decimal interchange format given its width in bits
59
+ def self.interchange_decimal(name,width_in_bits, options={})
60
+ raise "Invalid IEEE decimal interchange format definition: size (#{width_in_bits}) is not valid" unless (width_in_bits%32)==0
61
+ p = width_in_bits*9/32 - 2
62
+ t = (p-1)*10/3
63
+ w = width_in_bits - t - 6
64
+ decimal(name,{:significand=>t, :exponent=>w}.merge(options))
65
+ end
66
+
67
+ end
68
+
69
+ # IEEE 754 binary types, as stored in little endian architectures such as Intel, Alpha
70
+
71
+ IEEE.binary :IEEE_binary16, :significand=>10, :exponent=>5
72
+ IEEE.binary :IEEE_binary32, :significand=>23,:exponent=>8
73
+ IEEE.binary :IEEE_binary64, :significand=>52,:exponent=>11
74
+ IEEE.binary :IEEE_binary80, :significand=>64,:exponent=>15, :hidden_bit=>false, :min_encoded_exp=>1
75
+ IEEE.binary :IEEE_binary128, :significand=>112,:exponent=>15
76
+
77
+
78
+ # IEEE 754 in big endian order (SPARC, Motorola 68k, PowerPC)
79
+
80
+ IEEE.binary :IEEE_binary16_BE, :significand=>10, :exponent=>5, :endianness=>:big_endian
81
+ IEEE.binary :IEEE_binary32_BE, :significand=>23,:exponent=>8, :endianness=>:big_endian
82
+ IEEE.binary :IEEE_binary64_BE, :significand=>52,:exponent=>11, :endianness=>:big_endian
83
+ IEEE.binary :IEEE_binary80_BE, :significand=>64,:exponent=>15, :endianness=>:big_endian, :hidden_bit=>false, :min_encoded_exp=>1
84
+ IEEE.binary :IEEE_binary128_BE, :significand=>112,:exponent=>15, :endianness=>:big_endian
85
+
86
+
87
+ # some IEEE745r interchange binary formats
88
+
89
+ IEEE.interchange_binary :IEEE_binary256, 256
90
+ IEEE.interchange_binary :IEEE_binary512, 512
91
+ IEEE.interchange_binary :IEEE_binary1024, 1024
92
+ IEEE.interchange_binary :IEEE_binary256_BE, 256, :endianness=>:big_endian
93
+ IEEE.interchange_binary :IEEE_binary512_BE, 512, :endianness=>:big_endian
94
+ IEEE.interchange_binary :IEEE_binary1024_BE, 1024, :endianness=>:big_endian
95
+
96
+
97
+ # old names
98
+ IEEE_binaryx = IEEE_binary80
99
+ IEEE_HALF = IEEE_binary16
100
+ IEEE_SINGLE = IEEE_binary32
101
+ IEEE_DOUBLE = IEEE_binary64
102
+ IEEE_EXTENDED = IEEE_binary80
103
+ IEEE_QUAD = IEEE_binary128
104
+ IEEE_128 = IEEE_binary128
105
+ IEEE_H_BE = IEEE_binary16_BE
106
+ IEEE_S_BE = IEEE_binary32_BE
107
+ IEEE_D_BE = IEEE_binary64_BE
108
+ IEEE_X_BE = IEEE_binary80_BE
109
+ IEEE_128_BE = IEEE_binary128_BE
110
+ IEEE_Q_BE = IEEE_binary128_BE
111
+
112
+
113
+ # Decimal IEEE 754r formats
114
+
115
+ IEEE.decimal :IEEE_decimal32, :significand=>20, :exponent=>6
116
+ IEEE.decimal :IEEE_decimal64, :significand=>50, :exponent=>8
117
+ IEEE.decimal :IEEE_decimal128, :significand=>110, :exponent=>12
118
+
119
+ # some IEEE745r interchange binary formats
120
+
121
+ IEEE.interchange_decimal :IEEE_decimal96, 96
122
+ IEEE.interchange_decimal :IEEE_decimal192, 192
123
+ IEEE.interchange_decimal :IEEE_decimal256, 256
124
+
125
+ # old names
126
+
127
+ IEEE_DEC32 = IEEE_decimal32
128
+ IEEE_DEC64 = IEEE_decimal64
129
+ IEEE_DEC128 = IEEE_decimal128
130
+
131
+ # Excess 128 used by Microsoft Basic in 8-bit micros, Spectrum, ...
132
+
133
+ Flt.define BinaryFormat, :XS128,
134
+ :fields=>[:significand,31,:sign,1,:exponent,8],
135
+ :bias=>128, :bias_mode=>:fractional_significand,
136
+ :hidden_bit=>true,
137
+ :endianness=>:big_endian, :round=>:half_up,
138
+ :endianness=>:big_endian,
139
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
140
+
141
+ # HP-3000 excess 256 format, HP-Tandem...
142
+
143
+ Flt.define BinaryFormat, :XS256,
144
+ :fields=>[:significand,22,:exponent,9,:sign,1],
145
+ :bias=>256, :bias_mode=>:scientific_significand,
146
+ :hidden_bit=>true, :min_encoded_exp=>0,
147
+ :endianness=>:big_endian, :round=>:half_up,
148
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
149
+
150
+ Flt.define :XS256_DOUBLE, BinaryFormat,
151
+ :fields=>[:significand,54,:exponent,9,:sign,1],
152
+ :bias=>256, :bias_mode=>:scientific_significand,
153
+ :hidden_bit=>true, :min_encoded_exp=>0,
154
+ :endianness=>:big_endian, :round=>:half_up,
155
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
156
+
157
+ # Borland Pascal 48 bits "Real" Format
158
+
159
+ Flt.define :BORLAND48, BinaryFormat,
160
+ :fields=>[:exponent,8,:significand,39,:sign,1],
161
+ :bias=>128, :bias_mode=>:fractional_significand,
162
+ :hidden_bit=>true,
163
+ :endianness=>:little_endian,
164
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
165
+
166
+ # Microsoft Binary Floating-point (Quickbasic)
167
+
168
+ Flt.define :MBF_SINGLE, BinaryFormat,
169
+ :fields=>[:significand,23,:sign,1,:exponent,8],
170
+ :bias=>128, :bias_mode=>:fractional_significand,
171
+ :hidden_bit=>true,
172
+ :endianness=>:little_endian,
173
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
174
+
175
+ Flt.define :MBF_DOUBLE, BinaryFormat,
176
+ :fields=>[:significand,55,:sign,1,:exponent,8],
177
+ :bias=>128, :bias_mode=>:fractional_significand,
178
+ :hidden_bit=>true,
179
+ :endianness=>:little_endian,
180
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
181
+
182
+ # DEC formats (VAX)
183
+
184
+ Flt.define :VAX_F, BinaryFormat,
185
+ :fields=>[:significand, 23, :exponent, 8, :sign, 1],
186
+ :bias=>128, :bias_mode=>:fractional_significand,
187
+ :hidden_bit=>true,
188
+ :endianness=>:little_big_endian,
189
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
190
+
191
+ Flt.define :VAX_D, BinaryFormat,
192
+ :fields=>[:significand, 55, :exponent, 8, :sign, 1],
193
+ :bias=>128, :bias_mode=>:fractional_significand,
194
+ :hidden_bit=>true,
195
+ :endianness=>:little_big_endian,
196
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
197
+
198
+ Flt.define :VAX_G, BinaryFormat,
199
+ :fields=>[:significand, 52, :exponent, 11, :sign, 1],
200
+ :bias=>1024, :bias_mode=>:fractional_significand,
201
+ :hidden_bit=>true,
202
+ :endianness=>:little_big_endian,
203
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
204
+
205
+ Flt.define :VAX_H, BinaryFormat,
206
+ :fields=>[:significand, 112, :exponent, 15, :sign, 1],
207
+ :bias=>16384, :bias_mode=>:fractional_significand,
208
+ :hidden_bit=>true,
209
+ :endianness=>:little_big_endian,
210
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
211
+
212
+ # DEC PDP 11 variants (minimum exponent used for normalized values other than zero)
213
+
214
+ Flt.define :PDP11_F, BinaryFormat,
215
+ :fields=>[:significand, 23, :exponent, 8, :sign, 1],
216
+ :bias=>128, :bias_mode=>:fractional_significand,
217
+ :hidden_bit=>true, :min_encoded_exp=>0,
218
+ :endianness=>:little_big_endian,
219
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
220
+
221
+ Flt.define :PDP11_D, BinaryFormat,
222
+ :fields=>[:significand, 55, :exponent, 8, :sign, 1],
223
+ :bias=>128, :bias_mode=>:fractional_significand,
224
+ :hidden_bit=>true, :min_encoded_exp=>0,
225
+ :endianness=>:little_big_endian,
226
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
227
+
228
+
229
+ # Format used in HP Saturn-based RPL calculators (HP48,HP49,HP50, also HP32s, HP42s --which use RPL internally)
230
+ # (these formats are not used in the HP-71B which is a Saturn, non-RPL machine)
231
+
232
+ Flt.define :SATURN, BCDFormat,
233
+ :fields=>[:prolog,5,:exponent,3,:significand,12,:sign,1],
234
+ :fields_handler=>lambda{|fields| fields[0]=2933},
235
+ :exponent_mode=>:radix_complement,
236
+ :endianness=>:little_endian, :round=>:half_even,
237
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
238
+
239
+ Flt.define :SATURN_X, BCDFormat,
240
+ :fields=>[:prolog,5,:exponent,5,:significand,15,:sign,1],
241
+ :fields_handler=>lambda{|fields| fields[0]=2955},
242
+ :exponent_mode=>:radix_complement,
243
+ :endianness=>:little_endian, :round=>:half_even,
244
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
245
+
246
+
247
+ RPL = SATURN
248
+ RPL_X = SATURN_X
249
+
250
+ # SATURN HP-71B (IEEE, NON-RPL) formats
251
+
252
+ # HP-71B REAL format (12-form) which is stored in a single register
253
+ Flt.define :HP71B, BCDFormat,
254
+ :fields=>[:exponent,3,:significand,12,:sign,1],
255
+ :exponent_mode=>:radix_complement,
256
+ :endianness=>:little_endian, :round=>:half_even,
257
+ :gradual_underflow=>true, :infinity=>true, :nan=>true,
258
+ :denormal_encoded_exp=>501,
259
+ :nan_encoded_exp=>"F01", # signaling NaN is F02
260
+ :infinite_encoded_exp=>"F00"
261
+
262
+ # HP-71B internal 15-digit format (15-form), stored in a pair of registers
263
+ # we use here a little-endian order for the registers, otherwise the
264
+ # definition would be [:significand,15,:unused1,1,:exponent,5,:unused2,10,:sign,1]
265
+ Flt.define :HP71B_X, BCDFormat,
266
+ :fields=>[:exponent,5,:unused2,10,:sign,1, :significand,15,:unused1,1],
267
+ :exponent_mode=>:radix_complement,
268
+ :endianness=>:little_endian, :round=>:half_even,
269
+ :gradual_underflow=>false, :infinity=>true, :nan=>true,
270
+ :nan_encoded_exp=>"00F01",
271
+ :infinite_encoded_exp=>"00F00"
272
+
273
+ # Format used in classic HP calculators (HP-35, ... HP-15C)
274
+ # Endianness is indeterminate, since these machines have named registers that
275
+ # hold a floating-point value in a single 56-bit word.
276
+ # (But intra-word field/nibble addressing is little-endian)
277
+ Flt.define :HP_CLASSIC, BCDFormat,
278
+ :fields=>[:exponent,3,:significand,10,:sign,1],
279
+ :exponent_mode=>:radix_complement,
280
+ :min_exp=>-99, :max_exp=>99, # the most significant nibble of exponent if for sign only
281
+ :endianness=>:big_endian, :round=>:half_up,
282
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
283
+
284
+
285
+ # IBM Floating Point Architecture (IBM 360,370, DG Eclipse, ...)
286
+
287
+ # short
288
+ Flt.define :IBM32, HexadecimalFormat,
289
+ :fields=>[:significand,24,:exponent,7,:sign,1],
290
+ :bias=>64, :bias_mode=>:fractional_significand,
291
+ :endianness=>:big_endian
292
+
293
+ # long
294
+ Flt.define :IBM64, HexadecimalFormat,
295
+ :fields=>[:significand,56,:exponent,7,:sign,1],
296
+ :bias=>64, :bias_mode=>:fractional_significand,
297
+ :endianness=>:big_endian
298
+
299
+ # extended: two long values pasted together
300
+ Flt.define :IBM128, HexadecimalFormat,
301
+ :fields=>[:significand,14*4,:lo_exponent,7,:lo_sign,1,:significand,14*4,:exponent,7,:sign,1],
302
+ :fields_handler=>lambda{|fields| fields[1]=(fields[4]>=14&&fields[4]<127) ? fields[4]-14 : fields[4];fields[2]=fields[5] },
303
+ :bias=>64, :bias_mode=>:fractional_significand,
304
+ :min_encoded_exp=>14, # to avoid out-of-range exponents in the lower half
305
+ :endianness=>:big_endian
306
+
307
+ # It think this has never been used:
308
+ Flt.define :IBMX, HexadecimalFormat,
309
+ :fields=>[:significand,14*4,:exponent,7,:unused_sign,1,:significand,14*4,:exponent,7,:sign,1],
310
+ :fields_handler=>lambda{|fields| fields[2]=0},
311
+ :bias=>8192, :bias_mode=>:fractional_significand,
312
+ :endianness=>:big_endian
313
+
314
+ # Cray-1
315
+ Flt.define :CRAY, BinaryFormat,
316
+ :fields=>[:significand,48,:exponent,15,:sign,1],
317
+ :bias=>16384, :bias_mode=>:fractional_significand,
318
+ :hidden_bit=>false,
319
+ :min_encoded_exp=>8192, :max_encoded_exp=>24575, :zero_encoded_exp=>0,
320
+ :endianness=>:big_endian,
321
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
322
+
323
+ # CDC 6600/7600
324
+ # Byte endianness is arbitrary, since these machines were word-addressable, in 60-bit words,
325
+ # but the two words used in double precision numbers are in big endian order
326
+ # TO DO: apply this:
327
+ # The exponent encoded value 1023 is used for NaN
328
+ # The exponent encoded value 0 is used for underflow
329
+ # The exponent encoded value 2047 is used for overflow
330
+ #
331
+ # The exponent needs special treatment, because instead of excess encoding, which is equivalent to two's complement followed
332
+ # by sign bit reversal, one's complement followed by sign bit reversal is used, which is equivalent
333
+ # to use a bias diminished by one for negative exponents. Note that the exponent encoded value that equals the bias is
334
+ # not used (is used as a NaN indicator)
335
+ class CDCFormat < BinaryFormat # :nodoc:
336
+ def self.encode_exponent(e,mode)
337
+ ee = super
338
+ ee -= 1 if e<0
339
+ ee
340
+ end
341
+ def self.decode_exponent(ee,mode)
342
+ e = super
343
+ e += 1 if e<0
344
+ e
345
+ end
346
+ end
347
+
348
+ Flt.define :CDC_SINGLE, CDCFormat,
349
+ :fields=>[:significand,48, :exponent,11, :sign,1],
350
+ :bias=>1024, :bias_mode=>:integral_significand,
351
+ :min_exp=>-1023,
352
+ :neg_mode=>:diminished_radix_complement,
353
+ :hidden_bit=>false,
354
+ :endianess=>:big_endian,
355
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
356
+
357
+ # The CDC_DOUBLE can be splitted in two CDC_SINGLE values:
358
+ # get_bitfields(v,[CDC_SINGLE.total_bits]*2,CDC_DOUBLE.endianness).collect{|x| int_to_bytes(x,0,CDC_SINGLE.endianness)}
359
+ # and the value of the double is the sum of the values of the singles.
360
+ # Unlike the single, we must use :fractional_significand mode because with :integral_significand
361
+ # the exponent would refer to the whole significand, but it must refer only to the most significant half.
362
+ # we substract the number of bits in the single to the bias and exponent because of this change,
363
+ # and add 48 to the min_exponent to avoid the exponent of the low order single to be out of range
364
+ # because the exponent of the low order single is adjusted to
365
+ # the position of its digits by substracting 48 from the high order exponent
366
+ # when its exponent would be out of range
367
+ # Note that when computing the low order exponent with the fields handler we must take into account the sign
368
+ # because for negative numbers all the fields are one-complemented.
369
+ Flt.define :CDC_DOUBLE, CDCFormat,
370
+ :fields=>[:significand,48,:lo_exponent,11,:lo_sign,1,:significand,48,:exponent,11,:sign,1],
371
+ :fields_handler=>lambda{|fields|
372
+ fields[1]=(fields[4]>0&&fields[4]<2047) ? fields[4]-((-1)**fields[5])*48 : fields[4]
373
+ fields[2]=fields[5]
374
+ },
375
+ :bias=>1024-48, :bias_mode=>:fractional_significand,
376
+ :min_encoded_exp=>48+1, # + 1 because the bias for negative is 1023
377
+ :neg_mode=>:diminished_radix_complement,
378
+ :hidden_bit=>false,
379
+ :endianess=>:big_endian,
380
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
381
+
382
+
383
+ # Univac 1100
384
+ # Byte endianness is arbitrary, since these machines were word-addressable, in 36-bit words,
385
+ # but the two words used in double precision numbers are in big endian order
386
+ Flt.define :UNIVAC_SINGLE, BinaryFormat,
387
+ :fields=>[:significand,27, :exponent,8, :sign,1],
388
+ :bias=>128, :bias_mode=>:fractional_significand,
389
+ :neg_mode=>:diminished_radix_complement,
390
+ :hidden_bit=>false,
391
+ :endianess=>:big_endian,
392
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
393
+
394
+ Flt.define :UNIVAC_DOUBLE, BinaryFormat,
395
+ :fields=>[:significand,60, :exponent,11, :sign,1],
396
+ :bias=>1024, :bias_mode=>:fractional_significand,
397
+ :neg_mode=>:diminished_radix_complement,
398
+ :hidden_bit=>false,
399
+ :endianess=>:big_endian,
400
+ :gradual_underflow=>false, :infinity=>false, :nan=>false
401
+
402
+
403
+ # :stopdoc: # the next definition is not handled correctly by RDoc
404
+ Flt.define(:APPLE_INSANE,BinaryFormat,
405
+ :fields=>[:significand,23,:sign,1,:exponent,8],
406
+ :bias=>128, :bias_mode=>:scientific_significand,
407
+ :hidden_bit=>false, :min_encoded_exp=>0,
408
+ :neg_mode=>:radix_complement_significand,
409
+ :endianness=>:big_endian,
410
+ :gradual_underflow=>true, :infinity=>false, :nan=>false) { |fp|
411
+ # This needs a peculiar treatment for the negative values, which not simply use two's complement
412
+ # but also avoid having the sign and msb of the significand equal.
413
+ # Note that here we have a separate sign bit, but it can also be considered as the msb of the significand
414
+ # in two's complement, in which case the radix point is after the two msbs, which are the ones that
415
+ # should not be equal. (except for zero and other values using the minimum exponent).
416
+ def fp.neg_significand_exponent(s,f,e)
417
+ #puts "before: #{s} #{f.to_s(16)}"
418
+ f,e = super
419
+ s = (s+1)%2
420
+ #print "minus #{f.to_s(16)}"
421
+ if e>@zero_encoded_exp && f==0
422
+ f = 1<<(significand_digits-1)
423
+ e += 1
424
+ else
425
+ while (e>@zero_encoded_exp) && (f>>(significand_digits-1))&1 == s
426
+ e -= 1
427
+ f = (f << 1) & (radix_power(significand_digits)-1)
428
+ #print " << "
429
+ end
430
+ end
431
+ #puts ""
432
+ [f,e]
433
+ end
434
+ }
435
+ # :startdoc:
436
+
437
+
438
+ # Sofware floating point implementatin for the Apple II (6502)
439
+ # the significand & sign are a single field in two's commplement
440
+ APPLE = APPLE_INSANE
441
+
442
+ # Wang 2200 Basic Decimal floating point
443
+ Flt.define(:WANG2200,BCDFormat,
444
+ :fields=>[:significand,13,:exponent,2,:signs,1],
445
+ :endiannes=>:big_endian,
446
+ :bias_mode=>:scientific_significand,
447
+ :min_exp=>-99, :max_exp=>99,
448
+ :zero_encoded_exp=>0, :min_encoded_exp=>0
449
+ ) { |wang2200|
450
+
451
+ # needs special handling because significand and exponent are both stored
452
+ # as sign-magnitude, with both signs combined in a single nibble (decimal digit)
453
+ def wang2200.unpack(v)
454
+ f = unpack_fields_hash(v)
455
+ m = f[:significand]
456
+ e = f[:exponent]
457
+ ss = f[:signs]
458
+ s = (ss==9 || ss==1) ? 9 : 0
459
+ es = (ss==8 || ss==1) ? 9 : 0
460
+ if m==0
461
+ # +-zero
462
+ e = :zero
463
+ elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
464
+ # +-inifinity
465
+ e = :infinity
466
+ elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
467
+ # NaN
468
+ e = :nan
469
+ else
470
+ # normalized number
471
+ # reverse exponent nibbles
472
+ e = ("%0#{exponent_digits}d"%e).reverse.to_i
473
+ e = -e if es%2!=0
474
+ e -= (significand_digits-1)
475
+ end
476
+ s = sign_to_unit(s)
477
+ [s,m,e]
478
+ end
479
+
480
+ def wang2200.pack(s,m,e)
481
+ s = sign_from_unit(s)
482
+ msb = radix_power(@significand_digits-1)
483
+ es = 0
484
+ if e==:zero
485
+ e = @zero_encoded_exp
486
+ m = 0
487
+ elsif e==:infinity
488
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
489
+ m = 0
490
+ elsif e==:nan
491
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
492
+ s = minus_sign_value # ?
493
+ m = radix_power(@significand_digits-2) if m==0
494
+ elsif e==:denormal
495
+ e = @denormal_encoded_exp
496
+ else
497
+ # to do: try to adjust m to keep e in range if out of valid range
498
+ # to do: reduce m and adjust e if m too big
499
+
500
+ min_exp = radix_min_exp(:integral_significand)
501
+ if m>0
502
+ while m<msb && e>min_exp
503
+ e -= 1
504
+ m *= radix
505
+ end
506
+ end
507
+ if m<msb && @denormal_encoded_exp
508
+ e = @denormal_encoded_exp
509
+ elsif m==0 # => && @denormal_encoded_exp.nil?
510
+ e = 0
511
+ else
512
+ e += (significand_digits-1)
513
+ if e<0
514
+ e = -e
515
+ es = 9
516
+ else
517
+ es = 0
518
+ end
519
+ end
520
+ end
521
+ ss = (s%2) + (es==0 ? 0 : 8)
522
+ # reverse exponent nibbles
523
+ e = ("%0#{exponent_digits}d"%e).reverse.to_i
524
+ pack_fields_hash :signs=>ss, :significand=>m, :exponent=>e
525
+ end
526
+ }
527
+
528
+
529
+ # C51 (C compiler for the Intel 8051) BCD Floating point formats
530
+ class C51BCDFormat < BCDFormat # :nodoc:
531
+ def self.exponent_radix
532
+ 2
533
+ end
534
+ def self.exponent_digits
535
+ @fields[:exponent_sign]*4-1
536
+ end
537
+ def self.minus_sign_value
538
+ 1
539
+ end
540
+ def self.unpack(v)
541
+ f = to_fields_hash(v)
542
+ m = f[:significand]
543
+ e_s = f[:exponent_sign]
544
+ exp_bits = exponent_digits
545
+ e = e_s & (2**exp_bits-1)
546
+ s = e_s >> exp_bits
547
+ if m==0
548
+ # +-zero
549
+ e = :zero
550
+ elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
551
+ # +-inifinity
552
+ e = :infinity
553
+ elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
554
+ # NaN
555
+ e = :nan
556
+ else
557
+ # normalized number
558
+ e = decode_exponent(e, :integral_significand)
559
+ end
560
+ s = sign_to_unit(s)
561
+ [s,m,e]
562
+ end
563
+ def self.bcd_field?(i)
564
+ @field_meaning[i]==:significand
565
+ end
566
+
567
+ def self.pack(s,m,e)
568
+ s = sign_from_unit(s)
569
+ msb = radix_power(@significand_digits-1)
570
+ es = 0
571
+ if e==:zero
572
+ e = @zero_encoded_exp
573
+ m = 0
574
+ elsif e==:infinity
575
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
576
+ m = 0
577
+ elsif e==:nan
578
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
579
+ s = minus_sign_value # ?
580
+ m = radix_power(@significand_digits-2) if m==0
581
+ elsif e==:denormal
582
+ e = @denormal_encoded_exp
583
+ else
584
+ # to do: try to adjust m to keep e in range if out of valid range
585
+ # to do: reduce m and adjust e if m too big
586
+
587
+ min_exp = radix_min_exp(:integral_significand)
588
+ if m>0
589
+ while m<msb && e>min_exp
590
+ e -= 1
591
+ m *= radix
592
+ end
593
+ end
594
+ if m<msb && @denormal_encoded_exp
595
+ e = @denormal_encoded_exp
596
+ elsif m==0 # => && @denormal_encoded_exp.nil?
597
+ e = 0
598
+ else
599
+ e = encode_exponent(e, :integral_significand)
600
+ end
601
+ end
602
+ exp_bits = exponent_digits
603
+ e_s = e + (s << exp_bits)
604
+ pack_fields_hash :significand=>m, :exponent_sign=>e_s
605
+ end
606
+ end
607
+
608
+ Flt.define :C51_BCD_FLOAT, C51BCDFormat,
609
+ :fields=>[:exponent_sign, 2, :significand,6],
610
+ :endiannes=>:big_endian,
611
+ :bias=>64, :bias_mode=>:fractional_significand,
612
+ :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
613
+
614
+ Flt.define :C51_BCD_DOUBLE,C51BCDFormat,
615
+ :fields=>[:exponent_sign, 2, :significand,10],
616
+ :endiannes=>:big_endian,
617
+ :bias=>64, :bias_mode=>:fractional_significand,
618
+ :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
619
+
620
+ Flt.define :C51_BCD_LONG_DOUBLE, C51BCDFormat,
621
+ :fields=>[:exponent_sign, 2, :significand,12],
622
+ :endiannes=>:big_endian,
623
+ :bias=>64, :bias_mode=>:fractional_significand,
624
+ :zero_encoded_exp=>0, :min_encoded_exp=>0,:max_encoded_exp=>127
625
+
626
+
627
+ # double-double format as used in the PowerPC
628
+ Flt.define :IEEE_DOUBLE_DOUBLE, DoubleFormat, :half=>IEEE_binary64, :extra_prec=>true
629
+
630
+
631
+
632
+ end
633
+