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,1605 +1,1950 @@
1
- # Float-Formats
2
- # Floating-point classes -- tools to handle floating point formats
3
-
4
- # Nomenclature:
5
- # * radix: the numerical base of the floating point notation
6
- # * significand: the digits part of the number; also called coefficient or, arguably, mantissa.
7
- # * exponent: the radix exponent, also called characteristic;
8
- # * encoded exponent: the value stored in the f.p. format to denote the exponent
9
- #
10
- # Significand modes determine the interpretation of the significand value and also
11
- # of the exponent values. For excess-notation encoded exponents this means that
12
- # the value of the bias depends upon the interpretation of the significand.
13
- # * integral significand: the significand is interpreted as an integer, i.e. the radix
14
- # point is at the right (after the last digit);
15
- # Some examples of this pont of view:
16
- # - HP-50G LONGFLOAT library
17
- # - HP-16C Floating Point-Integer conversion
18
- # * fractional significand: the radix point is at the left, before the first significand digit
19
- # (before the hidden bit if there is one); the value v of a normalized significand is 1/r<=v<1
20
- # Examples:
21
- # - The C standard library frexp/ldexp uses this interpretation, and the <float.h> constants.
22
- # (and so this is also used by Ruby's Math.frexp and the constants defined in Float)
23
- # - Don Knuth's The Art of Computer Programming, Vol.2
24
- # - BigDecimal#split
25
- # * normalized significand: the radix point is after the first digit (after the hidden bit if present)
26
- # the value v of a normalized significand is 1<=v<r
27
- # Examples:
28
- # - IEEE 754 definitions
29
- # - RPL's MANT/XPON
30
- # - HP calculators SCI mode
31
- #
32
- # zero representation in hidden bit formats:
33
- # * with gradual underflow: the minimium encoded exponent (0) is used for zero and denormal numbers;
34
- # i.e. the minimum encoded exponent implies the hidden bit is 0
35
- # * minimum encoded exponent reserved for zero (nonzero significands are not used with it)
36
- # * special all zeros representation: minimun encoded exponent is a regular exponent except for 0
37
-
38
- require 'nio'
39
- require 'nio/sugar'
40
- require 'enumerator'
41
- require 'float-formats/bytes.rb'
42
-
43
- module FltPnt
44
-
45
- # General Floating Point Format Base class
46
- class FormatBase
47
- include FltPnt
48
-
49
- # Common parameters for all floating-point formats:
50
- # [<tt>:bias_mode</tt>] This defines how the significand is interpreted:
51
- # * <tt>:fractional_significand</tt> The radix point is before the most significant
52
- # digit of the significand (including a hidden bit if there's one).
53
- # * <tt>:normalized_significand</tt> The radix point is after the most significant
54
- # digit of the significand (including a hidden bit if there's one).
55
- # * <tt>:integral_significand</tt> The significand is assumed to be an integer, i.e.
56
- # the radix point is after the least significant digit.
57
- # [<tt>:bias</tt>] Defines the exponent encoding method to be excess notation
58
- # and defines the bias.
59
- # [<tt>:endianness</tt>] Defines the byte endianness. One of:
60
- # * <tt>:little_endian</tt> Least significant bytes come first. (Intel etc.)
61
- # * <tt>:big_endian</tt> (Network order): most significant bytes come first. (Motorola, SPARC,...)
62
- # * <tt>:little_big_endian</tt> (Middle endian) Each pair of bytes (16-bit word) has the bytes in
63
- # little endian order, but the words are stored in big endian order
64
- # (we assume the number of bytes is even). (PDP-11).
65
- def initialize(params={})
66
-
67
- @fields_handler = params[:fields_handler]
68
-
69
- @exponent_radix = params[:exponent_radix] || radix
70
-
71
- @zero_encoded_exp = params[:zero_encoded_exp] || 0
72
- @min_encoded_exp = params[:min_encoded_exp] || 0
73
- @denormal_encoded_exp = params[:denormal_encoded_exp]
74
- @gradual_underflow = params[:gradual_underflow] || (@denormal_encoded_exp ? true : false)
75
- if @gradual_underflow
76
- @denormal_encoded_exp = 0 if !@denormal_encoded_exp
77
- if @denormal_encoded_exp>=@min_encoded_exp
78
- @min_encoded_exp = @denormal_encoded_exp
79
- # originally, we incremented min_encoded_exp here unconditionally, but
80
- # now we don't if there's no hidden bit
81
- # (we assume the minimum exponent can be used for normalized and denormalized numbers)
82
- # because of this, IEEE_EXTENDED & 128 formats now specify :min_encoded_exp=>1 in it's definitions
83
- @min_encoded_exp += 1 if @hidden_bit
84
- end
85
- end
86
- # Note that if there's a hidden bit and no gradual underflow, the minimum encoded exponent will only
87
- # be used for zero unless a parameter :min_encoded_exp (=0) is passed. In this case all numbers with
88
- # minimun exponent and nonzero encoded significand will have a 1-valued hidden bit. Otherwise
89
- # the only valid encoded significand with minimun encoded exponent is 0.
90
- # In case of gradual underflow, the minimum exponent implies a hidden bit value of 0
91
- @min_encoded_exp += 1 if @min_encoded_exp==@zero_encoded_exp && (@hidden_bit && params[:min_encoded_exp].nil?)
92
-
93
- @infinite_encoded_exp = params[:infinite_encoded_exp]
94
- @nan_encoded_exp = params[:nan_encoded_exp]
95
-
96
- @infinity = params[:infinity] || (@infinite_encoded_exp ? true : false)
97
- @max_encoded_exp = params[:max_encoded_exp] || @exponent_radix**@fields[:exponent]-1 # maximum regular exponent, encoded
98
- if @infinity
99
- @infinite_encoded_exp = @nan_encoded_exp || @max_encoded_exp if !@infinite_encoded_exp
100
- @max_encoded_exp = @infinite_encoded_exp - 1 if @infinite_encoded_exp.kind_of?(Integer) && @infinite_encoded_exp<=@max_encoded_exp
101
- end
102
- @nan = params[:nan] || (@nan_encoded_exp ? true : false)
103
- if @nan
104
- @nan_encoded_exp = @infinite_encoded_exp || @max_encoded_exp if !@nan_encoded_exp
105
- @max_encoded_exp = @nan_encoded_exp - 1 if @nan_encoded_exp.kind_of?(Integer) && @nan_encoded_exp<=@max_encoded_exp
106
- end
107
-
108
- @exponent_mode = params[:exponent_mode]
109
- if @exponent_mode.nil?
110
- if params[:bias]
111
- @exponent_mode = :excess
112
- else
113
- @exponent_mode = :radix_complement
114
- end
115
- end
116
- @exponent_digits = @fields[:exponent]
117
-
118
- if @exponent_mode==:excess
119
- @bias = params[:bias] || (@exponent_radix**(@fields[:exponent]-1)-1)
120
- @bias_mode = params[:bias_mode] || :normalized_significand
121
- @min_exp = params[:min_exp]
122
- @max_exp = params[:max_exp]
123
- case @bias_mode
124
- when :integral_significand
125
- @integral_bias = @bias
126
- @fractional_bias = @integral_bias-@significand_digits
127
- @normalized_bias = @fractional_bias+1
128
- when :fractional_significand
129
- @fractional_bias = @bias
130
- @integral_bias = @fractional_bias+@significand_digits
131
- @normalized_bias = @fractional_bias+1
132
- @min_exp -= @significand_digits if @min_exp
133
- @max_exp -= @significand_digits if @max_exp
134
- when :normalized_significand
135
- @normalized_bias = @bias
136
- @fractional_bias = @normalized_bias-1
137
- @integral_bias = @fractional_bias+@significand_digits
138
- @min_exp -= @significand_digits-1 if @min_exp
139
- @max_exp -= @significand_digits-1 if @max_exp
140
- end
141
- else
142
- #@bias_mode = :normalized_significand
143
- @min_exp = params[:min_exp] || (-(@exponent_radix**@exponent_digits)/2 + 1)
144
- @max_exp = params[:max_exp] || ((@exponent_radix**@exponent_digits)/2 - 1)
145
- end
146
- @endianness = params[:endianness] || :little_endian
147
-
148
- @min_exp = @min_encoded_exp - @integral_bias if @min_exp.nil?
149
- @max_exp = @max_encoded_exp - @integral_bias if @max_exp.nil?
150
-
151
- if @exponent_mode==:excess
152
- @integral_max_exp = @max_exp
153
- @integral_min_exp = @min_exp
154
- @fractional_max_exp = @max_exp+@significand_digits
155
- @fractional_min_exp = @min_exp+@significand_digits
156
- @normalized_max_exp = @max_exp+@significand_digits-1
157
- @normalized_min_exp = @min_exp+@significand_digits-1
158
- else
159
- @integral_max_exp = @max_exp - (@significand_digits-1)
160
- @integral_min_exp = @min_exp - (@significand_digits-1)
161
- @fractional_max_exp = @max_exp+1
162
- @fractional_min_exp = @min_exp+1
163
- @normalized_max_exp = @max_exp
164
- @normalized_min_exp = @min_exp
165
- end
166
-
167
- @round = params[:round] # || :even
168
-
169
- @neg_mode = params[:neg_mode] || :sign_magnitude
170
-
171
- yield self if block_given?
172
-
173
- end
174
-
175
- # compute a power of the radix (base)
176
- def radix_power(n)
177
- radix**n
178
- end
179
-
180
- # base-10 logarithm of the radix
181
- def radix_log10
182
- Math.log(radix)/Math.log(10)
183
- end
184
- # radix-base logarithm
185
- def radix_log(x)
186
- Math.log(x)/Math.log(radix)
187
- end
188
- # number of decimal digits that can be stored in a floating point value and restored unaltered
189
- def decimal_digits_stored
190
- ((significand_digits-1)*radix_log10).floor
191
- end
192
- # number of decimal digits necessary to unambiguosly define any floating point value
193
- def decimal_digits_necessary
194
- (significand_digits*radix_log10).ceil+1
195
- end
196
-
197
- # Maximum integer such that 10 raised to that power
198
- # is in the range of the normalised floating point numbers
199
- def decimal_max_exp
200
- (radix_max_exp(:fractional_significand)*radix_log10+(1-radix_power(-significand_digits))*radix_log10).floor
201
- #(Math.log((1-radix**(significand_digits))*radix**radix_max_exp(:fractional_significand))/Math.log(10)).floor
202
- end
203
- # Minimum negative integer such that 10 raised to that power
204
- # is in the range of the normalised floating point numbers
205
- def decimal_min_exp
206
- (radix_min_exp(:fractional_significand)*radix_log10).ceil
207
- end
208
- # Stored (integral) value for the minus sign
209
- def minus_sign_value
210
- (-1) % radix
211
- end
212
- # switch between the encodings of minus and plus
213
- def switch_sign_value(v)
214
- (v==0) ? minus_sign_value : 0
215
- end
216
-
217
- # Rounding mode use for this floating-point format; can be one of:
218
- # [<tt>:even</tt>] round to nearest with ties toward an even digits
219
- # [<tt>:inf</tt>] round to nearest with ties toward infinity (away from zero)
220
- # [<tt>:zero</tt>] round to nearest with ties toward zero
221
- # [<tt>nil</tt>] rounding mode not specified
222
- def rounding_mode
223
- @round
224
- end
225
-
226
- # Number of digits in the significand (precision)
227
- def significand_digits
228
- @significand_digits
229
- end
230
-
231
- # This is a helper to handle floating point values with the auxiliar class Value:
232
- # it is used to return an encoded floating point value as a Value.
233
- def return_bytes(v)
234
- if v.kind_of?(Value)
235
- v
236
- else
237
- Value.new self, v
238
- end
239
- end
240
- # This is a helper to handle floating point values with the auxiliar class Value:
241
- # it is used to get a bytes string from either a Value or a String
242
- def input_bytes(v)
243
- if v.kind_of?(Value)
244
- raise "Invalid f.p. format" if v.fp_format!=self
245
- v = v.bytes
246
- elsif !v.kind_of?(String)
247
- raise "Invalid f.p. object"
248
- v = nil
249
- end
250
- v
251
- end
252
-
253
- # Greatest finite normalized floating point number in the representation.
254
- # It can be made negative by passing the sign (a so this would be the smallest
255
- # finite number).
256
- def max_value(sign=0)
257
- s = sign
258
- m = radix_power(significand_digits)-1
259
- e = radix_max_exp(:integral_significand)
260
- from_integral_sign_significand_exponent(s,m,e)
261
- end
262
- # Smallest normalized floating point number greater than zero in the representation.
263
- # It can be made negative by passing the sign.
264
- def min_normalized_value(sign=0)
265
- s = sign
266
- m = 1
267
- e = radix_min_exp(:normalized_significand)
268
- if @hidden_bit && (@min_encoded_exp==@zero_encoded_exp)
269
- m = 1 + radix_power(significand_digits - 1)
270
- e = radix_min_exp(:integral_significand)
271
- else
272
- m = 1
273
- e = radix_min_exp(:normalized_significand)
274
- end
275
- from_integral_sign_significand_exponent(s,m,e)
276
- end
277
- # Smallest floating point number greater than zero in the representation, including
278
- # denormalized values if the representation supports it.
279
- # It can be made negative by passing the sign.
280
- def min_value(sign=0)
281
- if @denormal_encoded_exp
282
- s = sign
283
- m = 1
284
- e = :denormal
285
- from_integral_sign_significand_exponent(s,m,e)
286
- else
287
- min_normalized_value(sign)
288
- end
289
- end
290
- # This is the difference between 1.0 and the smallest floating-point
291
- # value greater than 1.0, radix_power(1-significand_precision)
292
- def epsilon(sign=0)
293
- s = sign
294
- #m = 1
295
- #e = 1-significand_digits
296
- m = radix_power(significand_digits-1)
297
- e = 2*(1-significand_digits)
298
- from_integral_sign_significand_exponent(s,m,e)
299
- end
300
- # The strict epsilon is the smallest value that produces something different from 1.0
301
- # wehen added to 1.0. It may be smaller than the general epsilon, because
302
- # of the particular rounding rules used with the floating point format.
303
- # This is only meaningful when well-defined rules are used for rounding the result
304
- # of floating-point addition.
305
- # Note that (in pseudo-code):
306
- # ((1.0+strict_epsilon)-1.0)==epsilon
307
- def strict_epsilon(sign=0, round=nil)
308
- round ||= @round
309
- s = sign
310
- m = radix_power(significand_digits-1)
311
- e = 2*(1-significand_digits)
312
- # assume radix is even
313
- case @round
314
- when :even, :zero, :any_rounding
315
- e -= 1
316
- m /= 2
317
- m *= radix
318
- m += 1
319
- when :inf
320
- # note that here :inf means "round to nearest with ties tower infinity"
321
- e -= 1
322
- m /= 2
323
- m *= radix
324
- when :ceiling, :up
325
- # this is the IEEE "toward infinity" rounding
326
- return min_value
327
- end
328
- from_integral_sign_significand_exponent(s,m,e)
329
- end
330
- # This is the maximum relative error corresponding to 1/2 ulp:
331
- # (radix/2)*radix_power(-significand_precision) == epsilon/2
332
- # This is called "machine epsilon" in [Goldberg]
333
- def half_epsilon(sign=0)
334
- s = sign
335
- m = radix/2
336
- e = -significand_digits
337
- # normalize:
338
- m *= radix_power(significand_digits-1)
339
- e -= significand_digits-1
340
- from_integral_sign_significand_exponent(s,m,e)
341
- end
342
-
343
- # Floating point representation of zero.
344
- def zero(sign=0)
345
- from_integral_sign_significand_exponent sign, 0, :zero
346
- end
347
- # Floating point representation of infinity.
348
- def infinity(sign=0)
349
- if @infinite_encoded_exp
350
- from_integral_sign_significand_exponent sign, 0, :infinity
351
- else
352
- nil
353
- end
354
- end
355
- # Floating point representation of Not-a-Number.
356
- def nan
357
- if @nan_encoded_exp
358
- from_integral_sign_significand_exponent 0, 0, :nan
359
- else
360
- nil
361
- end
362
- end
363
-
364
- # Maximum exponent
365
- def radix_max_exp(significand_mode=:normalized_significand)
366
- case significand_mode
367
- when :integral_significand
368
- @integral_max_exp
369
- when :fractional_significand
370
- @fractional_max_exp
371
- when :normalized_significand
372
- @normalized_max_exp
373
- end
374
- end
375
- # Mminimum exponent
376
- def radix_min_exp(significand_mode=:normalized_significand)
377
- case significand_mode
378
- when :integral_significand
379
- @integral_min_exp
380
- when :fractional_significand
381
- @fractional_min_exp
382
- when :normalized_significand
383
- @normalized_min_exp
384
- end
385
- end
386
-
387
- # Endianness of the format (:little_endian, :big_endian or :little_big_endian)
388
- def endianness
389
- @endianness
390
- end
391
-
392
- # Does the format support gradual underflow? (denormalized numbers)
393
- def gradual_underflow?
394
- @gradual_underflow
395
- end
396
-
397
- # Exponent bias for excess notation exponent encoding
398
- # The argument defines the interpretation of the significand and so
399
- # determines the actual bias value.
400
- def bias(significand_mode=:normalized_significand)
401
- case significand_mode
402
- when :integral_significand
403
- @integral_bias
404
- when :fractional_significand
405
- @fractional_bias
406
- when :normalized_significand
407
- @normalized_bias
408
- end
409
- end
410
-
411
- # Produce an encoded floating point value using a number defined by a
412
- # formatted text string (using Nio formats). Returns a Value.
413
- def from_fmt(txt,fmt=Nio::Fmt.default)
414
- neutral = fmt.nio_read_formatted(txt)
415
- if neutral.special?
416
- case neutral.special
417
- when :nan
418
- return nan
419
- when :inf
420
- return infinity(neutral.sign=='-' ? minus_sign_value : 0)
421
- end
422
- end
423
- if neutral.rep_pos<neutral.digits.length
424
- nd = fmt.get_base==10 ? decimal_digits_necessary : (significand_digits*Math.log(radix)/Math.log(fmt.get_base)).ceil+1
425
- fmt = fmt.mode(:sig,nd)
426
- neutral = fmt.nio_read_formatted(fmt.nio_write_formatted(fmt.nio_read_formatted(txt)))
427
- end
428
- f = neutral.digits.to_i(neutral.base)
429
- e = neutral.dec_pos-neutral.digits.length
430
- rounding = neutral.rounding
431
- if neutral.base==radix
432
- x = from_integral_sign_significand_exponent(0,f,e)
433
- else
434
- x = algM(f,e,rounding,neutral.base)
435
- end
436
- if neutral.sign=='-'
437
- x = neg(x)
438
- end
439
- x
440
- end
441
- # Formats an encoded floating point value as a text string (using Nio formats)
442
- # Accepts either a Value or a byte String.
443
- def to_fmt(v,fmt=Nio::Fmt.default)
444
- # this always treats the floating-point values as exact quantities
445
- s,m,e = to_integral_sign_significand_exponent(v)
446
- case e
447
- when :zero
448
- v = 0.0/(s==0 ? +1 : -1)
449
- when :infinity
450
- v = (s==0 ? +1.0 : -1.0)/0.0
451
- when :nan
452
- v = 0.0/0.0
453
- else
454
- v = m*radix_power(e)*((-1)**s)
455
- end
456
- v.nio_write(fmt)
457
- end
458
-
459
- # Produce an encoded floating point value using a numeric value.
460
- # Returns a Value.
461
- def from_number(v, mode=:approx)
462
- fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
463
- from_fmt(v.nio_write(fmt),fmt)
464
- end
465
- # Computes the value in a specified numeric class (Float, Integer, Rational, BigDecimal)
466
- # of an encoded floating point number.
467
- # Accepts either a Value or a byte String.
468
- def to_number(v, number_class, mode=:approx)
469
- fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
470
- v = to_fmt(v,fmt)
471
- number_class.nio_read(v,fmt)
472
- end
473
-
474
- # Converts an ancoded floating point number to an hexadecimal representation;
475
- # bytes are separated if the second argument is true.
476
- # Accepts either a Value or a byte String.
477
- def to_hex(v,sep_bytes=false)
478
- bytes_to_hex(input_bytes(v),sep_bytes)
479
- end
480
- # Produce an encoded floating point value using an hexadecimal representation.
481
- # Returns a Value.
482
- def from_hex(hex)
483
- return_bytes hex_to_bytes(hex)
484
- end
485
-
486
- # Converts an ancoded floating point number to hash containing
487
- # the internal fields that define the number.
488
- # Accepts either a Value or a byte String.
489
- def to_fields_hash(v)
490
- a = to_fields(v)
491
- h = {}
492
- if @splitted_fields.nil?
493
- (0...a.size).each do |i|
494
- h[@field_meaning[i]] = a[i]
495
- end
496
- else
497
-
498
- @fields.each_key do |f|
499
- splits = @splitted_fields[f]
500
- if splits
501
- v = 0
502
- k = 1
503
- splits.each do |i|
504
- v += k*a[i]
505
- k *= fields_radix**(@field_lengths[i])
506
- end
507
- h[f] = v
508
- else
509
- h[f] = a[@field_meaning.index(f)]
510
- end
511
- end
512
- end
513
- h
514
- end
515
- # Produce an encoded floating point value using hash of the internal field values.
516
- # Returns a Value.
517
- def from_fields_hash(h)
518
- if @splitted_fields.nil?
519
- from_fields @field_meaning.collect{|f| h[f]}
520
- else
521
- flds = [nil]*@field_meaning.size
522
- @fields.each_key do |f|
523
- splits = @splitted_fields[f]
524
- if splits
525
- v = h[f]
526
- splits.each do |i|
527
- k = fields_radix**(@field_lengths[i])
528
- flds[i] = v % k
529
- v /= k
530
- end
531
- else
532
- flds[@field_meaning.index(f)] = h[f]
533
- end
534
- end
535
- from_fields flds
536
- end
537
- end
538
-
539
- # Computes the next adjacent floating point value.
540
- # Accepts either a Value or a byte String.
541
- # Returns a Value.
542
- def next_float(v)
543
- s,f,e = to_integral_sign_significand_exponent(v)
544
- return neg(prev_float(neg(v))) if s!=0 && e!=:zero
545
- s = switch_sign_value(s) if e==:zero && s!=0
546
-
547
- if e!=:nan && e!=:infinity
548
- if f==0
549
- if @gradual_underflow
550
- e = radix_min_exp(:integral_significand)
551
- f = 1
552
- else
553
- e = radix_min_exp(:integral_significand)
554
- f = radix_power(@significand_digits-1)
555
- end
556
- else
557
- f += 1
558
- end
559
- if f>=radix_power(@significand_digits)
560
- f /= radix
561
- e += 1
562
- if e>radix_max_exp(:integral_significand)
563
- e = :infinity
564
- f = 0
565
- end
566
- end
567
- from_integral_sign_significand_exponent(s,f,e)
568
- end
569
- end
570
-
571
- # Computes the previous adjacent floating point value.
572
- # Accepts either a Value or a byte String.
573
- # Returns a Value.
574
- def prev_float(v)
575
- s,f,e = to_integral_sign_significand_exponent(v)
576
- return neg(next_float(neg(v))) if s!=0
577
- return neg(next_float(v)) if e==:zero
578
- if e!=:nan && e!=:infinity
579
- f -= 1
580
- if f<radix_power(@significand_digits-1)
581
- if e>radix_min_exp(:integral_significand)
582
- e -= 1
583
- f *= radix
584
- else
585
- if @gradual_underflow
586
- e = :denormal
587
- else
588
- e = :zero
589
- end
590
- end
591
- end
592
- from_integral_sign_significand_exponent(s,f,e)
593
- end
594
- end
595
-
596
- # ulp (unit in the last place) according to the definition proposed by J.M. Muller in
597
- # "On the definition of ulp(x)" INRIA No. 5504
598
- def ulp(v)
599
- sign,sig,exp = to_integral_sign_significand_exponent(v)
600
-
601
- mnexp = radix_min_exp(:integral_significand)
602
- mxexp = radix_max_exp(:integral_significand)
603
- prec = significand_digits
604
-
605
- if exp==:nan
606
- return_bytes v
607
- elsif exp==:infinity
608
- from_integral_sign_significand_exponent(1,1,mxexp) # from_integral_sign_significand_exponent(1,fmt.radix_power(prec-1),mxexp-prec+1)
609
- elsif exp==:zero || exp <= mnexp
610
- min_value
611
- else
612
- exp -= 1 if sig==radix_power(prec-1) # minimum normalized significand
613
- from_integral_sign_significand_exponent(1,1,exp)
614
- end
615
- end
616
-
617
- # Produce an encoded floating point value from the integral value
618
- # of the sign, significand and exponent.
619
- # Returns a Value.
620
- def from_fractional_sign_significand_exponent(sign,fraction,exponent)
621
- msb = radix_power(@significand_digits-1)
622
- while fraction<msb
623
- fraction *= radix
624
- exponent -= 1
625
- end
626
- from_integral_sign_significand_exponent(sign,fraction.to_i,exponent)
627
- end
628
- # Computes an encoded floating-point value from the integral value
629
- # Accepts either a Value or a byte String.
630
- def to_fractional_sign_significand_exponent(v,significand_mode=:normalized_significand)
631
- s,m,e = to_integral_sign_significand_exponent(v)
632
- case significand_mode
633
- when :integral_significand
634
- when :fractional_significand
635
- m = Rational(m,radix_power(@significand_digits))
636
- when :normalized_significand
637
- m = Rational(m,radix_power(@significand_digits-1))
638
- end
639
- [s,m,e]
640
- end
641
-
642
- # Returns the encoded value of a floating-point number as an integer
643
- # Accepts either a Value or a byte String.
644
- def to_bits_integer(v)
645
- bytes_to_int(input_bytes(v), @endianness)
646
- end
647
- # Defines a floating-point number from the encoded integral value.
648
- # Returns a Value.
649
- def from_bits_integer(i)
650
- v = int_to_bytes(i)
651
- if v.size<total_bytes
652
- fill = (0.chr*(total_bytes-v.size))
653
- if @endianness==:little_endian
654
- bytes = fill
655
- else
656
- bytes = fill + bytes
657
- end
658
- elsif v.size>total_bytes
659
- raise "Invalid floating point value"
660
- end
661
- return_bytes v
662
- end
663
- # Returns the encoded integral value of a floating point number
664
- # as a text representation in a given base.
665
- # Accepts either a Value or a byte String.
666
- def to_bits_text(v,base)
667
- i = to_bits_integer(v)
668
- fmt = Nio::Fmt.default.base(base,true).mode(:fix,:exact)
669
- if [2,4,8,16].include?(base)
670
- n = (Math.log(base)/Math.log(2)).round.to_i
671
- digits = (total_bits+n-1)/n
672
- fmt.pad0s!(digits)
673
- end
674
- i.nio_write(fmt)
675
- end
676
- # Defines a floating-point number from a text representation of the
677
- # encoded integral value in a given base.
678
- # Returns a Value.
679
- def from_bits_text(txt,base)
680
- i = Integer.nio_read(txt,Nio::Fmt.base(base))
681
- from_bits_integer i
682
- end
683
-
684
- # Computes the negation of a floating point value
685
- # Accepts either a Value or a byte String.
686
- # Returns a Value.
687
- def neg(v)
688
- s,f,e = to_integral_sign_significand_exponent(v)
689
- s = switch_sign_value(s)
690
- from_integral_sign_significand_exponent(s,f,e)
691
- end
692
-
693
- # Converts a floating point value to another format
694
- def convert_to(v,fpclass)
695
- fpclass.from_fmt(to_fmt(v))
696
- end
697
-
698
- # :stopdoc:
699
- protected
700
- def define_fields(field_definitions)
701
-
702
- @field_lengths = []
703
- @field_meaning = []
704
- @fields = {}
705
- @splitted_fields = nil
706
- field_definitions.enum_slice(2).each do |m,l|
707
- @field_lengths << l
708
- @field_meaning << m
709
- if @fields[m].nil?
710
- @fields[m] = l
711
- else
712
- @splitted_fields ||= {}
713
- @splitted_fields[m] = [@field_meaning.index(m)]
714
- @fields[m] += l
715
- @splitted_fields[m] <<= @field_meaning.size-1
716
- end
717
- end
718
- raise "Invalid format" if @splitted_fields && !@splitted_fields_supported
719
- end
720
- def handle_fields(fields)
721
- if @fields_handler
722
- @fields_handler.call(fields)
723
- end
724
- end
725
-
726
- # s is the sign of f,e
727
- def neg_significand_exponent(s,f,e)
728
- case @neg_mode
729
- when :diminished_radix_complement
730
- if exponent_radix==radix
731
- f = (radix_power(significand_digits)-1) - f
732
- e = (radix_power(exponent_digits)-1) - e
733
- else
734
- # unsupported case; we could use the exponent radix for
735
- # the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
736
- raise "Unsupported format"
737
- end
738
- when :radix_complement_significand
739
- f = ((radix_power(significand_digits)-1) - f + 1) % radix_power(significand_digits)
740
- when :radix_complement
741
- if exponent_radix==radix
742
- if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
743
- ls,ms = e,f
744
- ls_digits = exponent_digits
745
- else
746
- ls,ms = f,e
747
- ls_digits = significand_digits
748
- end
749
- comb = ls + ms*radix_power(ls_digits)
750
- comb = ((radix_power(significand_digits)-1) - comb + 1) % radix_power(significand_digits)
751
- ls = comb % radix_power(ls_digits)
752
- ms = comb / radix_power(ls_digits)
753
- if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
754
- e,f = ls,ms
755
- else
756
- e,f = ms,ls
757
- end
758
- else
759
- # unsupported case; we could use the exponent radix for
760
- # the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
761
- raise "Unsupported format"
762
- end
763
- end
764
- [f,e]
765
- end
766
- def exponent_digits
767
- @fields[:exponent]
768
- end
769
- def exponent_radix
770
- @exponent_radix
771
- end
772
- # radix of the field sizes, used for splitted fields
773
- def fields_radix
774
- radix
775
- end
776
-
777
- def decode_exponent(e,mode)
778
- case @exponent_mode
779
- when :excess
780
- case mode
781
- when :integral_significand
782
- e -= @integral_bias
783
- when :fractional_significand
784
- e -= @fractional_bias
785
- when :normalized_significand
786
- e -= @normalized_bias
787
- end
788
- when :radix_complement
789
- n = @fields[:exponent]
790
- v = radix_power(n)
791
- e = e-v if e >= v/2
792
- case mode
793
- when :integral_significand
794
- e -= (significand_digits-1)
795
- when :fractional_significand
796
- e += 1
797
- when :normalized_significand
798
- end
799
- end
800
- e
801
- end
802
- def encode_exponent(e,mode)
803
- case @exponent_mode
804
- when :excess
805
- case mode
806
- when :integral_significand
807
- e += @integral_bias
808
- when :fractional_significand
809
- e += @fractional_bias
810
- when :normalized_significand
811
- e += @normalized_bias
812
- end
813
- when :radix_complement
814
- case mode
815
- when :integral_significand
816
- e += (significand_digits-1)
817
- when :fractional_significand
818
- e -= 1
819
- when :normalized_significand
820
- end
821
- n = @fields[:exponent]
822
- v = radix_power(n)
823
- e = e+v if e < 0
824
- end
825
- e
826
- end
827
-
828
- # these are functions from Nio::Clinger, generalized for arbitrary floating point formats
829
- def ratio_float(u,v,k,round_mode)
830
- q = u.div v
831
- r = u-q*v
832
- v_r = v-r
833
- z = from_integral_sign_significand_exponent(0,q,k)
834
- if r<v_r
835
- elsif r>v_r
836
- q += 1
837
- elsif (round_mode==:even && q.even?) || (round_mode==:zero)
838
- else
839
- q += 1
840
- end
841
- if q==radix_power(significand_digits)
842
- q = radix_power(significand_digits-1)
843
- k += 1
844
- end
845
- from_integral_sign_significand_exponent(0,q,k)
846
- end
847
-
848
- def algM(f,e,round_mode,eb=10)
849
-
850
- if e<0
851
- u,v,k = f,eb**(-e),0
852
- else
853
- u,v,k = f*(eb**e),1,0
854
- end
855
-
856
- n = significand_digits
857
- min_e = radix_min_exp(:integral_significand)
858
- max_e = radix_max_exp(:integral_significand)
859
-
860
- rp_n = radix_power(n)
861
- rp_n_1 = radix_power(n-1)
862
- r = radix
863
-
864
- loop do
865
- x = u.div(v) # bottleneck
866
- # overflow if k>=max_e
867
- if (x>=rp_n_1 && x<rp_n) || k==min_e || k==max_e
868
- return ratio_float(u,v,k,round_mode)
869
- elsif x<rp_n_1
870
- u *= r
871
- k -= 1
872
- elsif x>=rp_n
873
- v *= r
874
- k += 1
875
- end
876
- end
877
-
878
- end
879
- # :startdoc:
880
- end
881
-
882
- # Base class for decimal floating point formats
883
- class DecimalFormatBase < FormatBase
884
- # :stopdoc:
885
- def initialize(params)
886
- @hidden_bit = false
887
- super params
888
- end
889
- def radix
890
- 10
891
- end
892
- def radix_power(n)
893
- 10**n
894
- end
895
-
896
- def radix_log10
897
- 1
898
- end
899
- def radix_log(x)
900
- Math.log(x)/Math.log(10)
901
- end
902
-
903
- def decimal_digits_stored
904
- significand_digits
905
- end
906
- def decimal_digits_necessary
907
- significand_digits
908
- end
909
- def decimal_max_exp
910
- radix_max_exp(:normalized_significand)
911
- end
912
- def decimal_min_exp
913
- radix_min_exp(:normalized_significand)
914
- end
915
-
916
- def to_fmt(v,fmt=Nio::Fmt.default)
917
- # this always treats the floating-point values as exact quantities
918
- s,m,e = to_integral_sign_significand_exponent(v)
919
- case e
920
- when :zero
921
- v = 0.0/(s==0 ? +1 : -1)
922
- when :infinity
923
- v = (s==0 ? +1.0 : -1.0)/0.0
924
- when :nan
925
- v = 0.0/0.0
926
- else
927
- sign = s==0 ? '' : '-'
928
- v = BigDecimal("#{sign}#{m}E#{e}")
929
- end
930
- v.nio_write(fmt)
931
- end
932
- # :startdoc:
933
- end
934
-
935
- # BCD (Binary-Coded-Decimal) floating point formats
936
- class BCDFormat < DecimalFormatBase
937
- # The fields lengths are defined in decimal digits
938
- def initialize(params)
939
-
940
- @splitted_fields_supported = false
941
- define_fields params[:fields]
942
-
943
- @significand_digits = @fields[:significand]
944
- super params
945
-
946
- end
947
- # :stopdoc:
948
- def total_nibbles
949
- @field_lengths.inject{|x,y| x+y}
950
- end
951
- def total_bytes
952
- (total_nibbles+1)/2
953
- end
954
- def total_bits
955
- 4*total_nibbles
956
- end
957
-
958
- def to_fields(v)
959
- # bytes have always nibbles in big-endian order
960
- v = reverse_byte_nibbles(convert_endianness(input_bytes(v),@endianness,:little_endian))
961
- nibbles = bytes_to_hex(v)
962
- # now we have a little endian nibble string
963
- nibble_fields = []
964
- i = 0
965
- for l in @field_lengths
966
- nibble_fields << nibbles[i,l]
967
- i += l
968
- end
969
- # now we conver the nibble strings to numbers
970
- i = -1
971
- nibble_fields.collect do |ns|
972
- i+=1
973
- if bcd_field?(i)
974
- if /\A\d+\Z/.match(ns)
975
- ns.reverse.to_i
976
- else
977
- ns.reverse
978
- end
979
- else
980
- ns.reverse.to_i(16)
981
- end
982
- end
983
- end
984
- def from_fields(*fields)
985
- fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
986
- handle_fields fields
987
- i = 0
988
- nibbles = ""
989
- for l in @field_lengths
990
- f = fields[i]
991
- unless f.kind_of?(String)
992
- fmt = bcd_field?(i) ? 'd' : 'X'
993
- f = "%0#{l}#{fmt}" % fields[i]
994
- end
995
- nibbles << f.reverse
996
- i += 1
997
- end
998
- v = hex_to_bytes(nibbles)
999
- v = convert_endianness(reverse_byte_nibbles(v),:little_endian,@endianness)
1000
- return_bytes v
1001
- end
1002
- # this has beed added to allow some fields to contain binary integers rather than bcd
1003
- def bcd_field?(i)
1004
- true
1005
- end
1006
-
1007
- # assume @exponent_mode==:radix_complement
1008
-
1009
- def to_integral_sign_significand_exponent(v)
1010
- f = to_fields_hash(v)
1011
- m = f[:significand]
1012
- e = f[:exponent]
1013
- s = f[:sign]
1014
- m,e = neg_significand_exponent(s,m,e) if s%2==1
1015
- if @infinite_encoded_exp && e==@infinite_encoded_exp
1016
- # +-infinity
1017
- e = :infinity
1018
- elsif @nan_encoded_exp && e==@nan_encoded_exp
1019
- # NaN
1020
- e = :nan
1021
- elsif m==0
1022
- # +-zero
1023
- e = :zero
1024
- else
1025
- # normalized number
1026
- e = decode_exponent(e, :integral_significand)
1027
- end
1028
- [s,m,e]
1029
- end
1030
-
1031
- def from_integral_sign_significand_exponent(s,m,e)
1032
- msb = radix_power(@significand_digits-1)
1033
- if e==:zero
1034
- e = @zero_encoded_exp
1035
- m = 0
1036
- elsif e==:infinity
1037
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1038
- m = 0
1039
- elsif e==:nan
1040
- e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1041
- #s = minus_sign_value # ?
1042
- #m = radix_power(@significand_digits-2) if m==0
1043
- elsif e==:denormal
1044
- e = @denormal_encoded_exp
1045
- else
1046
- # to do: try to adjust m to keep e in range if out of valid range
1047
- # to do: reduce m and adjust e if m too big
1048
-
1049
- min_exp = radix_min_exp(:integral_significand)
1050
- if m>0
1051
- while m<msb && e>min_exp
1052
- e -= 1
1053
- m *= radix
1054
- end
1055
- end
1056
- if m<msb && @denormal_encoded_exp
1057
- e = @denormal_encoded_exp
1058
- elsif m==0 # => && @denormal_encoded_exp.nil?
1059
- e = 0
1060
- else
1061
- e = encode_exponent(e, :integral_significand)
1062
- end
1063
- end
1064
- m,e = neg_significand_exponent(0,m,e) if s%2==1
1065
- from_fields_hash :sign=>s, :significand=>m, :exponent=>e
1066
- end
1067
- # :startdoc:
1068
- end
1069
-
1070
- # DPD (Densely-Packed-Decimal) formats
1071
- class DPDFormat < DecimalFormatBase
1072
- # The field that need to be defined (with lenghts given in decimal digits) are
1073
- # * :sign
1074
- # * :combination
1075
- # * :exponent_continuation
1076
- # * :significand_continuation
1077
- def initialize(params)
1078
-
1079
- @splitted_fields_supported = false
1080
- define_fields params[:fields]
1081
- @internal_field_lengths = @field_lengths
1082
- @internal_field_meaning = @field_meaning
1083
- @internal_fields = @fields
1084
- raise "Unsupported DPD format" unless @internal_fields[:combination]==5 && @internal_fields[:sign]==1 && [0,4,7].include?(@internal_fields[:significand_continuation]%10)
1085
-
1086
-
1087
- @exponent_bits = 2 + @internal_fields[:exponent_continuation]
1088
-
1089
- extra_bits = (@internal_fields[:significand_continuation] % 10)
1090
- extra_digits = (extra_bits==0) ? 0 : ((extra_bits==4) ? 1 : 2)
1091
- @significand_digits = 1 + 3*(@internal_fields[:significand_continuation]/10) + extra_digits
1092
-
1093
- define_fields [:type,1,:sign,1,:exponent,@exponent_bits,:significand,@significand_digits]
1094
-
1095
- if params[:bias].nil?
1096
-
1097
- params[:bias_mode] = :normalized_significand
1098
-
1099
- @exp_limit = 3*(2**@internal_fields[:exponent_continuation])-1
1100
-
1101
- params[:max_exp] = @exp_limit/2
1102
- params[:min_exp] = -params[:max_exp]
1103
- params[:max_exp] += 1 if (@exp_limit%2)==1
1104
- params[:bias]= -params[:min_exp]
1105
-
1106
- end
1107
-
1108
- super params
1109
-
1110
- end
1111
-
1112
- # :stopdoc:
1113
- def total_bits
1114
- @internal_field_lengths.inject{|x,y| x+y}
1115
- end
1116
- def total_bytes
1117
- (total_bits+7)/8
1118
- end
1119
-
1120
-
1121
- def to_fields(v)
1122
- # convert internal binary fields to bcd decoded fields
1123
- a = get_bitfields(input_bytes(v),@internal_field_lengths,@endianness)
1124
- h = {}
1125
- (0...a.size).each do |i|
1126
- h[@internal_field_meaning[i]] = a[i]
1127
- end
1128
-
1129
- i_sign = h[:sign]
1130
- i_combination = h[:combination]
1131
- i_exponent_continuation = h[:exponent_continuation]
1132
- i_significand_continuation = h[:significand_continuation]
1133
-
1134
-
1135
- type = nil
1136
- sign = i_sign==0 ? 0 : 9
1137
-
1138
- a,b,c,d,e = ("%05B"%i_combination).split('').collect{|bit| bit.to_i}
1139
-
1140
- exp_msb = 0
1141
- sig_msd = 0
1142
-
1143
- if a==0 || b==0
1144
- exp_msb = (a<<1)|b
1145
- sig_msd = (c<<2)|(d<<1)|e
1146
- elsif c==0 || d==0
1147
- exp_msb = (c<<1)|d
1148
- sig_msd = (1<<3)|e
1149
- elsif e==0
1150
- type = :infinity
1151
- else
1152
- type = :nan
1153
- end
1154
-
1155
-
1156
- hex_sig = sig_msd.to_s
1157
- hex_sig << dpd_to_hexbcd(i_significand_continuation,@internal_fields[:significand_continuation])
1158
- significand = hex_sig.to_i
1159
-
1160
- exponent = i_exponent_continuation | (exp_msb << (@exponent_bits-2))
1161
- [type,sign,exponent,significand]
1162
- end
1163
- def from_fields(*fields)
1164
- fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
1165
- handle_fields fields
1166
- type,sign,exponent,significand = fields
1167
-
1168
- sig_hex = "%0#{@significand_digits-1}d"%significand
1169
- sig_cont_bits = 4*(@significand_digits-1)
1170
- sig_msd = sig_hex[0,1].to_i
1171
- i_significand_continuation,bits = hexbcd_to_dpd(sig_hex[1..-1])
1172
-
1173
-
1174
-
1175
- exp_msb = exponent>>(@exponent_bits-2)
1176
- i_exponent_continuation = exponent&((1<<(@exponent_bits-2))-1)
1177
-
1178
- i_sign = ((sign==0) ? 0 : 1)
1179
-
1180
-
1181
- case type
1182
- when :infinity
1183
- i_combination = 0x1E
1184
- when :nan
1185
- i_combination = 0x1F
1186
- else
1187
- if sig_msd&0x8==0
1188
- i_combination = sig_msd|(exp_msb<<3)
1189
- else
1190
- i_combination = sig_msd|(1<<4)|(exp_msb<<1)
1191
- end
1192
- end
1193
- h = {:sign=>i_sign, :combination=>i_combination, :exponent_continuation=>i_exponent_continuation, :significand_continuation=>i_significand_continuation}
1194
- fields = @internal_field_meaning.collect{|f| h[f]}
1195
- return_bytes set_bitfields(@internal_field_lengths,fields,@endianness)
1196
- end
1197
-
1198
-
1199
- def to_integral_sign_significand_exponent(v)
1200
- f = to_fields_hash(v)
1201
- m = f[:significand]
1202
- e = f[:exponent]
1203
- s = f[:sign]
1204
- t = f[:type]
1205
- m,e = neg_significand_exponent(s,m,e) if s%2==1
1206
- if m==0
1207
- # +-zero
1208
- e = :zero
1209
- elsif t==:infinity
1210
- # +-inifinity
1211
- e = :infinity
1212
- elsif t==:nan
1213
- # NaN
1214
- e = :nan
1215
- else
1216
- # normalized number
1217
- e = decode_exponent(e, :integral_significand)
1218
- end
1219
- [s,m,e]
1220
- end
1221
-
1222
- def from_integral_sign_significand_exponent(s,m,e)
1223
- msb = radix_power(@significand_digits-1)
1224
- t = nil
1225
- if e==:zero
1226
- e = @zero_encoded_exp
1227
- m = 0
1228
- elsif e==:infinity
1229
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1230
- m = 0
1231
- t = :infinity
1232
- elsif e==:nan
1233
- t = :nan
1234
- e = 0
1235
- s = 0
1236
- m = 0
1237
- elsif e==:denormal
1238
- e = @denormal_encoded_exp || @zero_encoded_exp
1239
- else
1240
- # to do: try to adjust m to keep e in range if out of valid range
1241
- # to do: reduce m and adjust e if m too big
1242
-
1243
- min_exp = radix_min_exp(:integral_significand)
1244
- if m>0 && false
1245
- while m<msb && e>min_exp
1246
- e -= 1
1247
- m *= radix
1248
- end
1249
- end
1250
- if m<msb && @denormal_encoded_exp && false
1251
- e = @denormal_encoded_exp
1252
- elsif m==0 # => && @denormal_encoded_exp.nil?
1253
- e = 0
1254
- else
1255
- e = encode_exponent(e, :integral_significand)
1256
- end
1257
- end
1258
- m,e = neg_significand_exponent(0,m,e) if s%2==1
1259
- from_fields_hash :sign=>s, :significand=>m, :exponent=>e, :type=>t
1260
- end
1261
-
1262
- # :startdoc:
1263
-
1264
-
1265
- end
1266
-
1267
- # This is a base class for formats that specify the field lengths in bits
1268
- class FieldsInBitsFormatBase < FormatBase
1269
- # :stopdoc:
1270
- def fields_radix
1271
- 2
1272
- end
1273
- def to_fields(v)
1274
- get_bitfields(input_bytes(v),@field_lengths,@endianness)
1275
- end
1276
- def from_fields(*fields)
1277
- fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
1278
- handle_fields fields
1279
- return_bytes set_bitfields(@field_lengths,fields,@endianness)
1280
- end
1281
- # :startdoc:
1282
- end
1283
-
1284
- # Binary floating point formats
1285
- class BinaryFormat < FieldsInBitsFormatBase
1286
- # a hidden bit can be define with :hidden_bit
1287
- def initialize(params)
1288
- @hidden_bit = params[:hidden_bit]
1289
- @hidden_bit = true if @hidden_bit.nil?
1290
-
1291
- @splitted_fields_supported = true
1292
- define_fields params[:fields]
1293
-
1294
- @significand_digits = @fields[:significand] + (@hidden_bit ? 1 : 0)
1295
- super params
1296
-
1297
- end
1298
-
1299
- # :stopdoc:
1300
-
1301
- def radix
1302
- 2
1303
- end
1304
- def radix_power(n)
1305
- if n>=0
1306
- 1 << n
1307
- else
1308
- 2**n
1309
- end
1310
- end
1311
-
1312
- def total_bits
1313
- @field_lengths.inject{|x,y| x+y}
1314
- end
1315
- def total_bytes
1316
- (total_bits+7)/8
1317
- end
1318
-
1319
- def to_integral_sign_significand_exponent(v)
1320
- f = to_fields_hash(v)
1321
- m = f[:significand]
1322
- e = f[:exponent]
1323
- s = f[:sign]
1324
- m,e = neg_significand_exponent(s,m,e) if s%2==1
1325
- if (m==0 && !@hidden_bit) ||
1326
- (m==0 && (e==@zero_encoded_exp || e==@denormal_encoded_exp)) ||
1327
- (e==@zero_encoded_exp && @min_encoded_exp>@zero_encoded_exp && !@denormal_encoded_exp)
1328
- # +-zero
1329
- e = :zero
1330
- elsif (e==@denormal_encoded_exp)
1331
- e = decode_exponent(e, :integral_significand)
1332
- e += 1 if @denormal_encoded_exp==@zero_encoded_exp
1333
- elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
1334
- # +-inifinity
1335
- e = :infinity
1336
- elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
1337
- # NaN
1338
- e = :nan
1339
- else
1340
- # normalized number
1341
- e = decode_exponent(e, :integral_significand)
1342
- m |= radix_power(@significand_digits-1) if @hidden_bit
1343
- end
1344
- [s,m,e]
1345
- end
1346
-
1347
- def from_integral_sign_significand_exponent(s,m,e)
1348
- msb = radix_power(@significand_digits-1)
1349
-
1350
- if e==:zero
1351
- e = @zero_encoded_exp || @denormal_encoded_exp
1352
- m = 0
1353
- elsif e==:infinity
1354
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1355
- m = 0
1356
- elsif e==:nan
1357
- e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1358
- s = minus_sign_value # ?
1359
- m = radix_power(@significand_digits-2) if m==0
1360
- elsif e==:denormal
1361
- e = @denormal_encoded_exp
1362
- else
1363
- # to do: try to adjust m to keep e in range if out of valid range
1364
- # to do: reduce m and adjust e if m too big
1365
-
1366
- min_exp = radix_min_exp(:integral_significand)
1367
- if m>0
1368
- while m<msb && e>min_exp
1369
- e -= 1
1370
- m <<= 1 # m *= radix
1371
- end
1372
- end
1373
- if m<msb && @denormal_encoded_exp
1374
- e = @denormal_encoded_exp
1375
- elsif m==0 # => && @denormal_encoded_exp.nil?
1376
- e = 0
1377
- else
1378
- m &= (radix_power(@significand_digits-1)-1) if @hidden_bit
1379
- e = encode_exponent(e, :integral_significand)
1380
- end
1381
- end
1382
- m,e = neg_significand_exponent(0,m,e) if s%2==1
1383
- from_fields_hash :sign=>s, :significand=>m, :exponent=>e
1384
- end
1385
- # :startdoc:
1386
-
1387
- end
1388
-
1389
- # Hexadecimal floating point format
1390
- class HexadecimalFormat < FieldsInBitsFormatBase
1391
- def initialize(params)
1392
- @hidden_bit = false
1393
- @splitted_fields_supported = true
1394
- define_fields params[:fields]
1395
- @significand_digits = @fields[:significand]/4
1396
- params[:exponent_radix] = 2
1397
- super params
1398
- end
1399
-
1400
- # :stopdoc:
1401
-
1402
- def radix
1403
- 16
1404
- end
1405
- def fields_radix
1406
- exponent_radix
1407
- end
1408
-
1409
- def total_bits
1410
- @field_lengths.inject{|x,y| x+y}
1411
- end
1412
- def total_bytes
1413
- (total_bits+7)/8
1414
- end
1415
-
1416
-
1417
- def to_integral_sign_significand_exponent(v)
1418
- f = to_fields_hash(v)
1419
- m = f[:significand]
1420
- e = f[:exponent]
1421
- s = f[:sign]
1422
- m,e = neg_significand_exponent(s,m,e) if s%2==1
1423
- if m==0
1424
- # +-zero
1425
- e = :zero
1426
- elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
1427
- # +-inifinity
1428
- e = :infinity
1429
- elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
1430
- # NaN
1431
- e = :nan
1432
- else
1433
- # normalized number
1434
- e = decode_exponent(e, :integral_significand)
1435
- end
1436
- [s,m,e]
1437
- end
1438
-
1439
- def from_integral_sign_significand_exponent(s,m,e)
1440
- msb = radix_power(@significand_digits-1)
1441
-
1442
- if e==:zero
1443
- e = @zero_encoded_exp
1444
- m = 0
1445
- elsif e==:infinity
1446
- e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1447
- m = 0
1448
- elsif e==:nan
1449
- e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1450
- s = minus_sign_value # ?
1451
- m = radix_power(@significand_digits-2) if m==0
1452
- elsif e==:denormal
1453
- e = @denormal_encoded_exp || @zero_encoded_exp
1454
- else
1455
- # to do: try to adjust m to keep e in range if out of valid range
1456
- # to do: reduce m and adjust e if m too big
1457
-
1458
- min_exp = radix_min_exp(:integral_significand)
1459
- if m>0
1460
- while m<msb && e>min_exp
1461
- e -= 1
1462
- m <<= 4 # m *= radix
1463
- end
1464
- end
1465
- if m<msb && @denormal_encoded_exp
1466
- e = @denormal_encoded_exp
1467
- elsif m==0 # => && @denormal_encoded_exp.nil?
1468
- e = 0
1469
- else
1470
- e = encode_exponent(e, :integral_significand)
1471
- end
1472
- end
1473
- m,e = neg_significand_exponent(0,m,e) if s%2==1
1474
- from_fields_hash :sign=>s, :significand=>m, :exponent=>e
1475
- end
1476
-
1477
-
1478
- def minus_sign_value
1479
- (-1) % 2
1480
- end
1481
-
1482
- def exponent_digits
1483
- @fields[exponent]/4
1484
- end
1485
-
1486
- # :startdoc:
1487
-
1488
- end
1489
-
1490
-
1491
- # A class to handle a floating-point representation (bytes) and its format class in a single object.
1492
- # This eases the definition and manipulation of floating-point values:
1493
- #
1494
- # v = FltPnt::Value.from_fmt(FltPnt::IEEE_DOUBLE, '1.1')
1495
- # # or:
1496
- # v = FltPnt::IEEE_DOUBLE.from_fmt('1.1')
1497
- # puts v.to_fields_hash.inspect # -> {:sign=>0, :significand=>450359962737050, :exponent=>1023}
1498
- # puts v.next.to_hex(true) # -> 9B 99 99 99 99 99 F1 3F
1499
- # w = v.convert_to(FltPnt::IEEE_SINGLE)
1500
- # puts w.next.to_hex(true) # -> CE CC 8C 3F
1501
- #
1502
- class Value
1503
- def initialize(fptype,value)
1504
- @fptype = fptype
1505
- @value = value
1506
- end
1507
- def self.from_fmt(fptype,txt,fmt=Nio::Fmt.default)
1508
- self.new fptype, fptype.from_fmt(txt,fmt)
1509
- end
1510
- def self.from_hex(fptype,hx)
1511
- self.new fptype, fptype.from_hex(hx)
1512
- end
1513
- def self.from_fields(fptype, *fields)
1514
- self.new fptype, fptype.from_fields(*fields)
1515
- end
1516
- def self.from_fields_hash(fptype, fields)
1517
- self.new fptype, fptype.from_fields_hash(fields)
1518
- end
1519
- def self.from_integral_sign_significand_exponent(fptype,s,m,e)
1520
- self.new fptype, fptype.from_integral_sign_significand_exponent(s,m,e)
1521
- end
1522
- def self.from_fractional_sign_significand_exponent(fptype,sign,fraction,exponent)
1523
- self.new fptype, fptype.from_fractional_sign_significand_exponent(sign,fraction,exponent)
1524
- end
1525
- def self.from_number(fptype,v,mode=:approx)
1526
- self.new fptype, fptype.from_number(v,mode)
1527
- end
1528
- def self.from_bits_integer(i)
1529
- self.new fptype, fptype.from_bits_integer(i)
1530
- end
1531
- def self.from_bits_text(txt,base)
1532
- self.new fptype, fptype.from_bits_text(txt,base)
1533
- end
1534
-
1535
- def to_fmt(fmt=Nio::Fmt.default)
1536
- @fptype.to_fmt(@value,fmt)
1537
- end
1538
- def to_hex(sep_bytes=false)
1539
- @fptype.to_hex(@value,sep_bytes)
1540
- end
1541
- def to_fields
1542
- @fptype.to_fields(@value)
1543
- end
1544
- def to_fields_hash
1545
- @fptype.to_fields_hash(@value)
1546
- end
1547
- def to_integral_sign_significand_exponent
1548
- @fptype.to_integral_sign_significand_exponent(@value)
1549
- end
1550
- def to_fractional_sign_significand_exponent(significand_mode=:normalized_significand)
1551
- @fptype.to_fractional_sign_significand_exponent(@value, significand_mode)
1552
- end
1553
- def to_number(number_class, mode=:approx)
1554
- @fptype.to_number(@value, number_class, mode)
1555
- end
1556
- def to_bits_integer
1557
- @fptype.to_bits_integer @value
1558
- end
1559
- def to_bits_text(base)
1560
- @fptype.to_bits_text @value, base
1561
- end
1562
-
1563
- def convert_to(fptype2)
1564
- self.class.new fptype2, fptype2.from_fmt(to_fmt)
1565
- end
1566
-
1567
- def next
1568
- self.class.new(@fptype, @fptype.next_float(@value))
1569
- end
1570
- def prev
1571
- self.class.new(@fptype, @fptype.prev_float(@value))
1572
- end
1573
-
1574
- def neg
1575
- @fptype.neg(@value)
1576
- end
1577
-
1578
- def ulp
1579
- @fptype.ulp(@value)
1580
- end
1581
-
1582
- def fp_format
1583
- @fptype
1584
- end
1585
- def bytes
1586
- @value
1587
- end
1588
-
1589
- def ==(obj); test_equal(obj); end
1590
- def eql?(obj); test_equal(obj); end
1591
- def ===(obj); test_equal(obj); end
1592
-
1593
- private
1594
- def test_equal(v)
1595
- @fptype==v.fp_format && @value==v.bytes
1596
- end
1597
-
1598
-
1599
- end
1600
-
1601
-
1602
-
1603
-
1604
- end
1605
-
1
+ # Float-Formats
2
+ # Floating-point classes -- tools to handle floating point formats
3
+
4
+ # Nomenclature:
5
+ # * radix: the numerical base of the floating point notation
6
+ # * significand: the digits part of the number; also called coefficient or, arguably, mantissa.
7
+ # * exponent: the radix exponent, also called characteristic;
8
+ # * encoded exponent: the value stored in the f.p. format to denote the exponent
9
+ #
10
+ # Significand modes determine the interpretation of the significand value and also
11
+ # of the exponent values. For excess-notation encoded exponents this means that
12
+ # the value of the bias depends upon the interpretation of the significand.
13
+ # * integral significand: the significand is interpreted as an integer, i.e. the radix
14
+ # point is at the right (after the last digit);
15
+ # Some examples of this pont of view:
16
+ # - HP-50G LONGFLOAT library
17
+ # - HP-16C Floating Point-Integer conversion
18
+ # * fractional significand: the radix point is at the left, before the first significand digit
19
+ # (before the hidden bit if there is one); the value v of a normalized significand is 1/r<=v<1
20
+ # Examples:
21
+ # - The C standard library frexp/ldexp uses this interpretation, and the <float.h> constants.
22
+ # (and so this is also used by Ruby's Math.frexp and the constants defined in Float)
23
+ # - Don Knuth's The Art of Computer Programming, Vol.2
24
+ # - BigDecimal#split
25
+ # * scientific significand: the radix point is after the first digit (after the hidden bit if present)
26
+ # the value v of a normalized significand is 1<=v<r
27
+ # Examples:
28
+ # - IEEE 754 definitions
29
+ # - RPL's MANT/XPON
30
+ # - HP calculators SCI mode
31
+ #
32
+ # zero representation in hidden bit formats:
33
+ # * with gradual underflow: the minimium encoded exponent (0) is used for zero and denormal numbers;
34
+ # i.e. the minimum encoded exponent implies the hidden bit is 0
35
+ # * minimum encoded exponent reserved for zero (nonzero significands are not used with it)
36
+ # * special all zeros representation: minimun encoded exponent is a regular exponent except for 0
37
+
38
+ require 'nio'
39
+ require 'nio/sugar'
40
+ require 'flt'
41
+ require 'enumerator'
42
+ require 'float-formats/bytes.rb'
43
+
44
+ module Flt
45
+
46
+ # General Floating Point Format Base class
47
+ class FormatBase
48
+ include Flt # make Flt module functions available to instance methods
49
+ extend Flt # make Flt module functions available to class methods
50
+
51
+ def initialize(*args)
52
+ if (args.size == 3 || args.size==4 || args.size==2) &&
53
+ (args.first.kind_of?(Integer) && args[1].kind_of?(Integer))
54
+ sign,significand,exponent,normalize = args
55
+ if normalize.nil?
56
+ if [nil,true,false].include?(exponent)
57
+ normalize = exponent
58
+ exponent = significand
59
+ significand = sign.abs
60
+ sign = sign<0 ? -1 : +1
61
+ end
62
+ end
63
+ @sign,@significand,@exponent = self.class.canonicalized(sign,significand,exponent,normalize)
64
+ else
65
+ v = form_class.nan
66
+ case args.first
67
+ when form_class
68
+ v = args.first
69
+ raise "Too many arguments for FormatBase constructor" if args.size>1
70
+ when Array
71
+ v = args.first
72
+ raise "Too many arguments for FormatBase constructor" if args.size>1
73
+ when FormatBase
74
+ v = args.first.convert_to(form_class)
75
+ raise "Too many arguments for FormatBase constructor" if args.size>1
76
+ when String
77
+ v = form_class.from_text(*args)
78
+ when Bytes
79
+ v = form_class.from_bytes(*args)
80
+ when Bits
81
+ v = form_class.from_bits(*args)
82
+ when Numeric
83
+ v = form_class.from_number(args.first)
84
+ raise "Too many arguments for FormatBase constructor" if args.size>1
85
+ when Symbol
86
+ if args.first.to_s[0..3]!='from'
87
+ args = ["from_#{args.first}".to_sym] + args[1..-1]
88
+ end
89
+ v = form_class.send(*args)
90
+ end
91
+ @sign,@significand,@exponent = v.to_a
92
+ end
93
+ end
94
+ attr_reader :sign, :significand, :exponent
95
+ def to_a
96
+ split
97
+ end
98
+ def split
99
+ return [@sign,@significand,@exponent]
100
+ end
101
+
102
+
103
+ def nan?
104
+ @exponent == :nan
105
+ end
106
+ def zero?
107
+ return @exponent==:zero || @significand==0
108
+ end
109
+ def infinite?
110
+ return @exponent==:infinity
111
+ end
112
+ def subnormal?
113
+ return @exponent==:denormal || (@significand.kind_of?(Integer) && @significand<self.class.minimum_normalized_integral_significand)
114
+ end
115
+ def normal?
116
+ @exponend.kind_of?(Integer) && @significand>=self.class.minimum_normalized_integral_significand
117
+ end
118
+
119
+ include Nio::Formattable
120
+
121
+ # from/to integral_sign_significand_exponent
122
+
123
+ def nio_write_neutral(fmt)
124
+ # this always treats the floating-point values as exact quantities
125
+ case @exponent
126
+ when :zero
127
+ v = 0.0/@sign
128
+ when :infinity
129
+ v = @sign/0.0
130
+ when :nan
131
+ v = 0.0/0.0
132
+ else
133
+ case form_class.radix
134
+ when 10
135
+ v = Flt.DecNum(@sign, @significand, @exponent)
136
+ when 2
137
+ v = Flt.BinNum(@sign, @significand, @exponent)
138
+ else
139
+ v = @significand*form_class.radix_power(@exponent)*@sign
140
+ end
141
+ end
142
+ v.nio_write_neutral(fmt)
143
+ end
144
+ def to_text(fmt=Nio::Fmt.default)
145
+ nio_write(fmt)
146
+ end
147
+ def to_bytes
148
+ form_class.pack(@sign,@significand,@exponent)
149
+ end
150
+ def to_hex(sep_bytes=false)
151
+ if (form_class.total_bits % 8)==0
152
+ to_bytes.to_hex(sep_bytes)
153
+ else
154
+ to_bits.to_hex
155
+ end
156
+ end
157
+ def to(number_class, mode=:approx)
158
+ if number_class==Bytes
159
+ to_bytes
160
+ elsif number_class==String
161
+ mode = Nio::Fmt.default if mode==:approx
162
+ to_text(mode)
163
+ elsif Nio::Fmt===number_class
164
+ to_text(number_class)
165
+ elsif number_class==Array
166
+ split
167
+ elsif Symbol===number_class
168
+ send "to_#{number_class}"
169
+ elsif number_class.is_a?(Flt::Num) && number_class.radix == form_class.radix
170
+ self.to_num
171
+ else # assume number_class.ancestors.include?(Numeric) (number_class < Numeric)
172
+ fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
173
+ v = nio_write(fmt)
174
+ number_class.nio_read(v,fmt)
175
+ end
176
+ end
177
+ def to_bits
178
+ to_bytes.to_bits(form_class.endianness,false,form_class.total_bits)
179
+ end
180
+ # Returns the encoded integral value of a floating point number
181
+ # as a text representation in a given base.
182
+ # Accepts either a Value or a byte String.
183
+ def to_bits_text(base)
184
+ to_bits.to_s(base)
185
+ #i = to_bits
186
+ #fmt = Nio::Fmt.default.base(base,true).mode(:fix,:exact)
187
+ #if [2,4,8,16].include?(base)
188
+ # n = (Math.log(base)/Math.log(2)).round.to_i
189
+ # digits = (form_class.total_bits+n-1)/n
190
+ # fmt.pad0s!(digits)
191
+ #end
192
+ #i.to_i.nio_write(fmt)
193
+ end
194
+
195
+ # Computes the negation of a floating point value (unary minus)
196
+ def minus
197
+ form_class.new(-@sign,@significand,@exponent)
198
+ end
199
+
200
+ # Converts a floating point value to another format
201
+ def convert_to(fpclass)
202
+ fpclass.nio_read(nio_write)
203
+ end
204
+
205
+
206
+ # Computes the next adjacent floating point value.
207
+ # Accepts either a Value or a byte String.
208
+ # Returns a Value.
209
+ # TODO: use Flt
210
+ def next_plus
211
+ s,f,e = self.class.canonicalized(@sign,@significand,@exponent,true)
212
+ return minus.next_minus.minus if s<0 && e!=:zero
213
+ s = -s if e==:zero && s<0
214
+
215
+ if e!=:nan && e!=:infinity
216
+ if f==0
217
+ if form_class.gradual_underflow?
218
+ e = form_class.radix_min_exp(:integral_significand)
219
+ f = 1
220
+ else
221
+ e = form_class.radix_min_exp(:integral_significand)
222
+ f = form_class.minimum_normalized_integral_significand
223
+ end
224
+ else
225
+ f += 1
226
+ end
227
+ if f>=form_class.radix_power(form_class.significand_digits)
228
+ f /= form_class.radix
229
+ if e==:denormal
230
+ e = form_class.radix_min_exp(:integral_significand)
231
+ else
232
+ e += 1
233
+ end
234
+ if e>form_class.radix_max_exp(:integral_significand)
235
+ e = :infinity
236
+ f = 0
237
+ end
238
+ end
239
+ form_class.new s, f, e
240
+ end
241
+ end
242
+
243
+ # Computes the previous adjacent floating point value.
244
+ # Accepts either a Value or a byte String.
245
+ # Returns a Value.
246
+ def next_minus
247
+ s,f,e = self.class.canonicalized(@sign,@significand,@exponent,true)
248
+ return minus.next_plus.minus if s<0
249
+ return self.next_plus.minus if e==:zero
250
+ if e!=:nan
251
+ if e == :infinity
252
+ f = form_class.maximum_integral_significand
253
+ e = form_class.radix_max_exp(:integral_significand)
254
+ else
255
+ f -= 1
256
+ if f<form_class.minimum_normalized_integral_significand
257
+ if e!=:denormal && e>form_class.radix_min_exp(:integral_significand)
258
+ e -= 1
259
+ f *= form_class.radix
260
+ else
261
+ if form_class.gradual_underflow?
262
+ e = :denormal
263
+ else
264
+ e = :zero
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+ form_class.new s, f, e
271
+ end
272
+
273
+ # ulp (unit in the last place) according to the definition proposed by J.M. Muller in
274
+ # "On the definition of ulp(x)" INRIA No. 5504
275
+ def ulp
276
+ sign,sig,exp = @sign,@significand,@exponent
277
+
278
+ mnexp = form_class.radix_min_exp(:integral_significand)
279
+ mxexp = form_class.radix_max_exp(:integral_significand)
280
+ prec = form_class.significand_digits
281
+
282
+ if exp==:nan
283
+ elsif exp==:infinity
284
+ sign,sig,exp = 1,1,mxexp
285
+ elsif exp==:zero || exp <= mnexp
286
+ return form_class.min_value
287
+ else
288
+ exp -= 1 if sig==form_class.minimum_normalized_integral_significand
289
+ sign,sig,exp = 1,1,exp
290
+ end
291
+ form_class.new sign, sig, exp
292
+ end
293
+
294
+ def <=>(other)
295
+ return 1 if nan? || other.nan?
296
+ return 0 if zero? && other.zero?
297
+ this_sign,this_significand,this_exponent = split
298
+ other_sign, other_significand, other_exponent = other.split
299
+ return -1 if other_sign < this_sign
300
+ return 1 if other_sign > this_sign
301
+ return 0 if infinite? && other.infinite?
302
+
303
+ if this_sign<0
304
+ this_significand,other_significand = other_significand,this_significand
305
+ this_exponent,other_exponent = other_exponent,this_exponent
306
+ end
307
+
308
+ if this_exponent==other_exponent
309
+ return this_significand <=> other_significand
310
+ else
311
+ mns = form_class.minimum_normalized_integral_significand
312
+ this_normal = this_significand >= mns
313
+ other_normal = other_significand >= mns
314
+ if this_normal && other_normal
315
+ return this_exponent <=> other_exponent
316
+ else
317
+ min_exp = form_class.radix_min_exp(:integral_significand)
318
+ max_exp = form_class.radix_max_exp(:integral_significand)
319
+
320
+ while this_significand<mns && this_exponent>min_exp
321
+ this_exponent -= 1
322
+ this_significand *= form_class.radix
323
+ end
324
+
325
+ while other_significand<mns && other_exponent>min_exp
326
+ other_exponent -= 1
327
+ other_significand *= form_class.radix
328
+ end
329
+
330
+ if this_exponent==other_exponent
331
+ return this_significand <=> other_significand
332
+ else
333
+ return this_exponent <=> other_exponent
334
+ end
335
+ end
336
+ end
337
+ end
338
+ include Comparable
339
+
340
+ #todo hash cononicalizing first
341
+
342
+
343
+ def fp_format
344
+ form_class
345
+ end
346
+ def form_class
347
+ self.class
348
+ end
349
+
350
+
351
+ # Common parameters for all floating-point formats:
352
+ # [<tt>:bias_mode</tt>] This defines how the significand is interpreted:
353
+ # * <tt>:fractional_significand</tt> The radix point is before the most significant
354
+ # digit of the significand (including a hidden bit if there's one).
355
+ # * <tt>:scientific_significand</tt> The radix point is after the most significant
356
+ # digit of the significand (including a hidden bit if there's one).
357
+ # * <tt>:integral_significand</tt> The significand is assumed to be an integer, i.e.
358
+ # the radix point is after the least significant digit.
359
+ # [<tt>:bias</tt>] Defines the exponent encoding method to be excess notation
360
+ # and defines the bias.
361
+ # [<tt>:endianness</tt>] Defines the byte endianness. One of:
362
+ # * <tt>:little_endian</tt> Least significant bytes come first. (Intel etc.)
363
+ # * <tt>:big_endian</tt> (Network order): most significant bytes come first. (Motorola, SPARC,...)
364
+ # * <tt>:little_big_endian</tt> (Middle endian) Each pair of bytes (16-bit word) has the bytes in
365
+ # little endian order, but the words are stored in big endian order
366
+ # (we assume the number of bytes is even). (PDP-11).
367
+ def self.define(params={})
368
+ @parameters = params
369
+
370
+ @normalized = params[:normalized]
371
+ @normalized = true if @normalized.nil?
372
+ @fields_handler = params[:fields_handler]
373
+
374
+ @exponent_radix = params[:exponent_radix] || radix
375
+
376
+ @zero_encoded_exp = params[:zero_encoded_exp] || 0
377
+ @min_encoded_exp = params[:min_encoded_exp] || 0
378
+ @denormal_encoded_exp = params[:denormal_encoded_exp]
379
+ @gradual_underflow = params[:gradual_underflow] || (@denormal_encoded_exp ? true : false)
380
+ if @gradual_underflow
381
+ @denormal_encoded_exp = 0 if !@denormal_encoded_exp
382
+ if @denormal_encoded_exp>=@min_encoded_exp
383
+ @min_encoded_exp = @denormal_encoded_exp
384
+ # originally, we incremented min_encoded_exp here unconditionally, but
385
+ # now we don't if there's no hidden bit
386
+ # (we assume the minimum exponent can be used for normalized and denormalized numbers)
387
+ # because of this, IEEE_EXTENDED & 128 formats now specify :min_encoded_exp=>1 in it's definitions
388
+ @min_encoded_exp += 1 if @hidden_bit
389
+ end
390
+ end
391
+ # Note that if there's a hidden bit and no gradual underflow, the minimum encoded exponent will only
392
+ # be used for zero unless a parameter :min_encoded_exp (=0) is passed. In this case all numbers with
393
+ # minimun exponent and nonzero encoded significand will have a 1-valued hidden bit. Otherwise
394
+ # the only valid encoded significand with minimun encoded exponent is 0.
395
+ # In case of gradual underflow, the minimum exponent implies a hidden bit value of 0
396
+ @min_encoded_exp += 1 if @min_encoded_exp==@zero_encoded_exp && (@hidden_bit && params[:min_encoded_exp].nil?)
397
+
398
+ @infinite_encoded_exp = params[:infinite_encoded_exp]
399
+ @nan_encoded_exp = params[:nan_encoded_exp]
400
+
401
+ @infinity = params[:infinity] || (@infinite_encoded_exp ? true : false)
402
+ @max_encoded_exp = params[:max_encoded_exp] || @exponent_radix**@fields[:exponent]-1 # maximum regular exponent, encoded
403
+ if @infinity
404
+ @infinite_encoded_exp = @nan_encoded_exp || @max_encoded_exp if !@infinite_encoded_exp
405
+ @max_encoded_exp = @infinite_encoded_exp - 1 if @infinite_encoded_exp.kind_of?(Integer) && @infinite_encoded_exp<=@max_encoded_exp
406
+ end
407
+ @nan = params[:nan] || (@nan_encoded_exp ? true : false)
408
+ if @nan
409
+ @nan_encoded_exp = @infinite_encoded_exp || @max_encoded_exp if !@nan_encoded_exp
410
+ @max_encoded_exp = @nan_encoded_exp - 1 if @nan_encoded_exp.kind_of?(Integer) && @nan_encoded_exp<=@max_encoded_exp
411
+ end
412
+
413
+ @exponent_mode = params[:exponent_mode]
414
+ if @exponent_mode.nil?
415
+ if params[:bias]
416
+ @exponent_mode = :excess
417
+ else
418
+ @exponent_mode = :radix_complement
419
+ end
420
+ end
421
+ @exponent_digits = @fields[:exponent]
422
+
423
+ if @exponent_mode==:excess
424
+ @bias = params[:bias] || (@exponent_radix**(@fields[:exponent]-1)-1)
425
+ @bias_mode = params[:bias_mode] || :scientific_significand
426
+ @min_exp = params[:min_exp]
427
+ @max_exp = params[:max_exp]
428
+ case @bias_mode
429
+ when :integral_significand
430
+ @integral_bias = @bias
431
+ @fractional_bias = @integral_bias-@significand_digits
432
+ @scientific_bias = @fractional_bias+1
433
+ when :fractional_significand
434
+ @fractional_bias = @bias
435
+ @integral_bias = @fractional_bias+@significand_digits
436
+ @scientific_bias = @fractional_bias+1
437
+ @min_exp -= @significand_digits if @min_exp
438
+ @max_exp -= @significand_digits if @max_exp
439
+ when :scientific_significand
440
+ @scientific_bias = @bias
441
+ @fractional_bias = @scientific_bias-1
442
+ @integral_bias = @fractional_bias+@significand_digits
443
+ @min_exp -= @significand_digits-1 if @min_exp
444
+ @max_exp -= @significand_digits-1 if @max_exp
445
+ end
446
+ else
447
+ #@bias_mode = :scientific_significand
448
+ @min_exp = params[:min_exp] || (-(@exponent_radix**@exponent_digits)/2 + 1)
449
+ @max_exp = params[:max_exp] || ((@exponent_radix**@exponent_digits)/2 - 1)
450
+ end
451
+ @endianness = params[:endianness] || :little_endian
452
+
453
+ @min_exp = @min_encoded_exp - @integral_bias if @min_exp.nil?
454
+ @max_exp = @max_encoded_exp - @integral_bias if @max_exp.nil?
455
+
456
+ if @exponent_mode==:excess
457
+ @integral_max_exp = @max_exp
458
+ @integral_min_exp = @min_exp
459
+ @fractional_max_exp = @max_exp+@significand_digits
460
+ @fractional_min_exp = @min_exp+@significand_digits
461
+ @scientific_max_exp = @max_exp+@significand_digits-1
462
+ @scientific_min_exp = @min_exp+@significand_digits-1
463
+ else
464
+ @integral_max_exp = @max_exp - (@significand_digits-1)
465
+ @integral_min_exp = @min_exp - (@significand_digits-1)
466
+ @fractional_max_exp = @max_exp+1
467
+ @fractional_min_exp = @min_exp+1
468
+ @scientific_max_exp = @max_exp
469
+ @scientific_min_exp = @min_exp
470
+ end
471
+
472
+ @round = params[:round] # || :half_even
473
+
474
+ @neg_mode = params[:neg_mode] || :sign_magnitude
475
+
476
+ yield self if block_given?
477
+
478
+ end
479
+
480
+ class <<self
481
+ # define format properties:
482
+ # [+radix+] Numeric base
483
+ # [+significand_digits+] Number of digits in the significand (precision)
484
+ # [+hidden_bit+] Has the format a hidden bit?
485
+ # [+parameters+] Parameters used to define the class
486
+ attr_reader :radix, :significand_digits, :parameters, :hidden_bit
487
+ # attr_accessor
488
+ end
489
+
490
+ # compute a power of the radix (base)
491
+ def self.radix_power(n)
492
+ radix**n
493
+ end
494
+
495
+ # base-10 logarithm of the radix
496
+ def self.radix_log10
497
+ Math.log(radix)/Math.log(10)
498
+ end
499
+ # radix-base logarithm
500
+ def self.radix_log(x)
501
+ Math.log(x)/Math.log(radix)
502
+ end
503
+ # number of decimal digits that can be stored in a floating point value and restored unaltered
504
+ def self.decimal_digits_stored
505
+ ((significand_digits-1)*radix_log10).floor
506
+ end
507
+ # number of decimal digits necessary to unambiguosly define any floating point value
508
+ def self.decimal_digits_necessary
509
+ (significand_digits*radix_log10).ceil+1
510
+ end
511
+
512
+ # Maximum integer such that 10 raised to that power
513
+ # is in the range of the normalised floating point numbers
514
+ def self.decimal_max_exp
515
+ (radix_max_exp(:fractional_significand)*radix_log10+(1-radix_power(-significand_digits))*radix_log10).floor
516
+ #(Math.log((1-radix**(significand_digits))*radix**radix_max_exp(:fractional_significand))/Math.log(10)).floor
517
+ end
518
+ # Minimum negative integer such that 10 raised to that power
519
+ # is in the range of the normalised floating point numbers
520
+ def self.decimal_min_exp
521
+ (radix_min_exp(:fractional_significand)*radix_log10).ceil
522
+ end
523
+ # Stored (integral) value for the minus sign
524
+ def self.minus_sign_value
525
+ (-1) % radix
526
+ end
527
+ # switch between the encodings of minus and plus
528
+ def self.switch_sign_value(v)
529
+ (v==0) ? minus_sign_value : 0
530
+ end
531
+
532
+ def self.sign_to_unit(s)
533
+ s==0 ? +1 : -1 # ((-1)**s)
534
+ end
535
+
536
+ def self.sign_from_unit(u)
537
+ u<0 ? minus_sign_value : 0
538
+ end
539
+
540
+ # Rounding mode use for this floating-point format; can be one of:
541
+ # [<tt>:half_even</tt>] round to nearest with ties toward an even digits
542
+ # [<tt>:half_up</tt>] round to nearest with ties toward infinity (away from zero)
543
+ # [<tt>:half_down</tt>] round to nearest with ties toward zero
544
+ # [<tt>nil</tt>] rounding mode not specified
545
+ def self.rounding_mode
546
+ @round
547
+ end
548
+
549
+ def self.minimum_normalized_integral_significand
550
+ radix_power(significand_digits-1)
551
+ end
552
+ def self.maximum_integral_significand
553
+ radix_power(significand_digits)-1
554
+ end
555
+
556
+ # Maximum exponent
557
+ def self.radix_max_exp(significand_mode = :scientific_significand)
558
+ case significand_mode
559
+ when :integral_significand
560
+ @integral_max_exp
561
+ when :fractional_significand
562
+ @fractional_max_exp
563
+ when :scientific_significand
564
+ @scientific_max_exp
565
+ end
566
+ end
567
+ # Mminimum exponent
568
+ def self.radix_min_exp(significand_mode = :scientific_significand)
569
+ case significand_mode
570
+ when :integral_significand
571
+ @integral_min_exp
572
+ when :fractional_significand
573
+ @fractional_min_exp
574
+ when :scientific_significand
575
+ @scientific_min_exp
576
+ end
577
+ end
578
+
579
+ def self.num_class
580
+ Num[self.radix]
581
+ end
582
+
583
+ def self.context
584
+ num_class::Context.new(
585
+ :precision=>significand_digits,
586
+ :emin=>radix_min_exp(:scientific_significand),
587
+ :emax=>radix_max_exp(:scientific_significand),
588
+ :rounding=>@round || :half_even
589
+ )
590
+ end
591
+
592
+ def to_num
593
+ s,c,e = split
594
+ e = 0 if e == :zero
595
+ form_class.num_class.Num(s,c,e)
596
+ end
597
+
598
+ def self.num(x)
599
+ new(*x.split)
600
+ end
601
+
602
+ # Endianness of the format (:little_endian, :big_endian or :little_big_endian)
603
+ def self.endianness
604
+ @endianness
605
+ end
606
+
607
+ # Does the format support gradual underflow? (denormalized numbers)
608
+ def self.gradual_underflow?
609
+ @gradual_underflow
610
+ end
611
+
612
+ # Exponent bias for excess notation exponent encoding
613
+ # The argument defines the interpretation of the significand and so
614
+ # determines the actual bias value.
615
+ def self.bias(significand_mode = :scientific_significand)
616
+ case significand_mode
617
+ when :integral_significand
618
+ @integral_bias
619
+ when :fractional_significand
620
+ @fractional_bias
621
+ when :scientific_significand
622
+ @scientific_bias
623
+ end
624
+ end
625
+
626
+ def self.canonicalized(s,m,e,normalize=nil)
627
+ #puts "s=#{s} m=#{m} e=#{e}"
628
+ #return [s,m,e]
629
+ normalize = @normalized if normalize.nil?
630
+ min_exp = radix_min_exp(:integral_significand)
631
+ e = min_exp if e==:denormal
632
+ if m.kind_of?(Integer) && m>0 && e.kind_of?(Integer)
633
+ while e<min_exp
634
+ e += 1
635
+ m /= radix # TODO: round
636
+ end
637
+ end
638
+ s,m,e = normalized(s,m,e) if normalize
639
+
640
+ if m==0 && e.kind_of?(Integer)
641
+ e=:zero
642
+ end
643
+ #puts " -> s=#{s} m=#{m} e=#{e}"
644
+ [s,m,e]
645
+ end
646
+
647
+
648
+ protected
649
+
650
+
651
+ def self.normalized(s,m,e)
652
+ if m.kind_of?(Integer) && e.kind_of?(Integer)
653
+ min_exp = radix_min_exp(:integral_significand)
654
+ if m>0
655
+ while m<minimum_normalized_integral_significand && e>min_exp
656
+ e -= 1
657
+ m *= radix
658
+ end
659
+ if @normalized && !@gradual_underflow
660
+ if e<=min_exp && m<minimum_normalized_integral_significand
661
+ m = 0
662
+ e = :zero
663
+ end
664
+ end
665
+ end
666
+ end
667
+ [s,m,e]
668
+ end
669
+
670
+ def self.return_value(s,m,e,normalize=nil)
671
+ self.new s,m,e,normalize
672
+ end
673
+ def self.input_bytes(v)
674
+ if v.kind_of?(FormatBase)
675
+ raise "Invalid f.p. format" if v.fp_format!=self
676
+ v = v.to_bytes
677
+ elsif !v.kind_of?(Bytes)
678
+ v = Bytes.new(v)
679
+ end
680
+ v
681
+ end
682
+
683
+ public
684
+
685
+
686
+ # Greatest finite normalized floating point number in the representation.
687
+ # It can be made negative by passing the sign (a so this would be the smallest
688
+ # finite number).
689
+ def self.max_value(sign=+1)
690
+ s = sign
691
+ m = maximum_integral_significand
692
+ e = radix_max_exp(:integral_significand)
693
+ return_value s,m,e, false
694
+ end
695
+ # Smallest normalized floating point number greater than zero in the representation.
696
+ # It can be made negative by passing the sign.
697
+ def self.min_normalized_value(sign=+1)
698
+ s = sign
699
+ m = minimum_normalized_integral_significand
700
+ e = radix_min_exp(:integral_significand)
701
+ m += 1 if @hidden_bit && (@min_encoded_exp==@zero_encoded_exp)
702
+ return_value s,m,e, true
703
+ end
704
+ # Smallest floating point number greater than zero in the representation, including
705
+ # denormalized values if the representation supports it.
706
+ # It can be made negative by passing the sign.
707
+ def self.min_value(sign=+1)
708
+ if @denormal_encoded_exp
709
+ s = sign
710
+ m = 1
711
+ e = :denormal
712
+ return_value s,m,e, false
713
+ else
714
+ min_normalized_value(sign)
715
+ end
716
+ end
717
+ # This is the difference between 1.0 and the smallest floating-point
718
+ # value greater than 1.0, radix_power(1-significand_precision)
719
+ def self.epsilon(sign=+1)
720
+ s = sign
721
+ #m = 1
722
+ #e = 1-significand_digits
723
+ m = minimum_normalized_integral_significand
724
+ e = 2*(1-significand_digits)
725
+ return_value s,m,e, false
726
+ end
727
+ # The strict epsilon is the smallest value that produces something different from 1.0
728
+ # wehen added to 1.0. It may be smaller than the general epsilon, because
729
+ # of the particular rounding rules used with the floating point format.
730
+ # This is only meaningful when well-defined rules are used for rounding the result
731
+ # of floating-point addition.
732
+ # Note that (in pseudo-code):
733
+ # ((1.0+strict_epsilon)-1.0)==epsilon
734
+ # TODO: use Flt::Num
735
+ def self.strict_epsilon(sign=+1, round=nil)
736
+ round ||= @round
737
+ s = sign
738
+ m = minimum_normalized_integral_significand
739
+ e = 2*(1-significand_digits)
740
+ # assume radix is even
741
+ case @round
742
+ when :down, :floor, :any_rounding, nil
743
+ e = 2*(1-significand_digits)
744
+ m = minimum_normalized_integral_significand
745
+ when :half_even, :half_down
746
+ e = 1-2*significand_digits
747
+ m = 1 + radix_power(significand_digits)/2
748
+ when :half_up
749
+ e = 1-2*significand_digits
750
+ m = radix_power(significand_digits)/2
751
+ when :ceiling, :up, :up05
752
+ return min_value
753
+ end
754
+ return_value sign,m,e
755
+
756
+ end
757
+
758
+ # This is the maximum relative error corresponding to 1/2 ulp:
759
+ # (radix/2)*radix_power(-significand_precision) == epsilon/2
760
+ # This is called "machine epsilon" in [Goldberg]
761
+ # TODO: use Flt::Num
762
+ def self.half_epsilon(sign=+1)
763
+ s = sign
764
+ m = radix/2
765
+ e = -significand_digits
766
+ # normalize:
767
+ m *= minimum_normalized_integral_significand
768
+ e -= significand_digits-1
769
+ return_value s,m,e, false
770
+ end
771
+
772
+ # Floating point representation of zero.
773
+ def self.zero(sign=+1)
774
+ return_value sign, 0, :zero
775
+ end
776
+ # Floating point representation of infinity.
777
+ def self.infinity(sign=+1)
778
+ if @infinite_encoded_exp
779
+ return_value sign, 0, :infinity
780
+ else
781
+ nil
782
+ end
783
+ end
784
+ # Floating point representation of Not-a-Number.
785
+ def self.nan
786
+ if @nan_encoded_exp
787
+ return_value(+1, 0, :nan)
788
+ else
789
+ nil
790
+ end
791
+ end
792
+
793
+ # from methods
794
+
795
+
796
+ def self.nio_read_neutral(neutral)
797
+ if neutral.special?
798
+ case neutral.special
799
+ when :nan
800
+ return nan
801
+ when :inf
802
+ return infinity(neutral.sign=='-' ? -1 : +1)
803
+ end
804
+ end
805
+ if neutral.rep_pos<neutral.digits.length
806
+ nd = neutral.base==10 ? decimal_digits_necessary : (significand_digits*Math.log(radix)/Math.log(fmt.get_base)).ceil+1
807
+ neutral = neutral.round(nd,:sig)
808
+ end
809
+ f = neutral.digits.to_i(neutral.base)
810
+ e = neutral.dec_pos-neutral.digits.length
811
+ case neutral.rounding
812
+ when :even
813
+ rounding = :half_even
814
+ when :inf
815
+ rounding = :half_up
816
+ when :zero
817
+ rounding = :half_down
818
+ when :truncate
819
+ rounding = :down
820
+ end
821
+ s = (neutral.sign=='-') ? -1 : +1
822
+ if neutral.base!=radix
823
+ reader = Flt::Support::Reader.new(:mode=>:fixed)
824
+ s,f,e = reader.read(context, rounding, s, f, e, neutral.base).split
825
+ end
826
+ return_value s,f,e
827
+
828
+ end
829
+
830
+ def self.from(*args)
831
+ new(*args)
832
+ end
833
+
834
+ def self.from_bytes(b)
835
+ return_value(*unpack(b))
836
+ end
837
+
838
+ def self.from_hex(hex)
839
+ from_bytes Bytes.from_hex(hex)
840
+ end
841
+
842
+ def self.from_number(v, mode=:approx)
843
+ if v.is_a?(Flt::Num) && v.num_class.radix==self.radix
844
+ self.num(v)
845
+ else
846
+ fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
847
+ nio_read(v.nio_write(fmt),fmt)
848
+ end
849
+ end
850
+
851
+ def self.from_text(txt, fmt=Nio::Fmt.default) # ?
852
+ nio_read(txt,fmt)
853
+ end
854
+
855
+ def self.join(sign,significand,exponent)
856
+ self.new sign,significand,exponent
857
+ end
858
+
859
+ # Defines a floating-point number from the encoded integral value.
860
+ def self.from_bits(i)
861
+ v = Bytes.from_i(i)
862
+ if v.size<total_bytes
863
+ fill = (0.chr*(total_bytes-v.size))
864
+ if @endianness==:little_endian
865
+ v << fill
866
+ else
867
+ v = Bytes.new(fill) + bytes
868
+ end
869
+ elsif v.size>total_bytes
870
+ raise "Invalid floating point value"
871
+ end
872
+ from_bytes v
873
+ end
874
+
875
+ # Defines a floating-point number from a text representation of the
876
+ # encoded integral value in a given base.
877
+ # Returns a Value.
878
+ def self.from_bits_text(txt,base)
879
+ i = Integer.nio_read(txt,Nio::Fmt.base(base))
880
+ from_bits i
881
+ end
882
+
883
+ # Converts en ancoded floating point number to hash containing
884
+ # the internal fields that define the number.
885
+ # Accepts either a Value or a byte String.
886
+ def self.unpack_fields_hash(v)
887
+ a = unpack_fields(v)
888
+ h = {}
889
+ if @splitted_fields.nil?
890
+ (0...a.size).each do |i|
891
+ h[@field_meaning[i]] = a[i]
892
+ end
893
+ else
894
+
895
+ @fields.each_key do |f|
896
+ splits = @splitted_fields[f]
897
+ if splits
898
+ v = 0
899
+ k = 1
900
+ splits.each do |i|
901
+ v += k*a[i]
902
+ k *= fields_radix**(@field_lengths[i])
903
+ end
904
+ h[f] = v
905
+ else
906
+ h[f] = a[@field_meaning.index(f)]
907
+ end
908
+ end
909
+ end
910
+ h
911
+ end
912
+
913
+ # Produce an encoded floating point value using hash of the internal field values.
914
+ # Returns a Value.
915
+ def self.pack_fields_hash(h)
916
+ if @splitted_fields.nil?
917
+ pack_fields @field_meaning.collect{|f| h[f]}
918
+ else
919
+ flds = [nil]*@field_meaning.size
920
+ @fields.each_key do |f|
921
+ splits = @splitted_fields[f]
922
+ if splits
923
+ v = h[f]
924
+ splits.each do |i|
925
+ k = fields_radix**(@field_lengths[i])
926
+ flds[i] = v % k
927
+ v /= k
928
+ end
929
+ else
930
+ flds[@field_meaning.index(f)] = h[f]
931
+ end
932
+ end
933
+ pack_fields flds
934
+ end
935
+ end
936
+
937
+ # :stopdoc:
938
+ protected
939
+ def self.define_fields(field_definitions)
940
+
941
+ @field_lengths = []
942
+ @field_meaning = []
943
+ @fields = {}
944
+ @splitted_fields = nil
945
+ field_definitions.each_slice(2) do |m,l|
946
+ @field_lengths << l
947
+ @field_meaning << m
948
+ if @fields[m].nil?
949
+ @fields[m] = l
950
+ else
951
+ @splitted_fields ||= {}
952
+ @splitted_fields[m] = [@field_meaning.index(m)]
953
+ @fields[m] += l
954
+ @splitted_fields[m] <<= @field_meaning.size-1
955
+ end
956
+ end
957
+ raise "Invalid format" if @splitted_fields && !@splitted_fields_supported
958
+ end
959
+ def self.handle_fields(fields)
960
+ if @fields_handler
961
+ @fields_handler.call(fields)
962
+ end
963
+ end
964
+
965
+ # s is the sign of f,e
966
+ def self.neg_significand_exponent(s,f,e)
967
+ case @neg_mode
968
+ when :diminished_radix_complement
969
+ if exponent_radix==radix
970
+ f = (radix_power(significand_digits)-1) - f
971
+ e = (radix_power(exponent_digits)-1) - e
972
+ else
973
+ # unsupported case; we could use the exponent radix for
974
+ # the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
975
+ raise "Unsupported format"
976
+ end
977
+ when :radix_complement_significand
978
+ f = ((radix_power(significand_digits)-1) - f + 1) % radix_power(significand_digits)
979
+ when :radix_complement
980
+ if exponent_radix==radix
981
+ if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
982
+ ls,ms = e,f
983
+ ls_digits = exponent_digits
984
+ else
985
+ ls,ms = f,e
986
+ ls_digits = significand_digits
987
+ end
988
+ comb = ls + ms*radix_power(ls_digits)
989
+ comb = ((radix_power(significand_digits)-1) - comb + 1) % radix_power(significand_digits)
990
+ ls = comb % radix_power(ls_digits)
991
+ ms = comb / radix_power(ls_digits)
992
+ if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
993
+ e,f = ls,ms
994
+ else
995
+ e,f = ms,ls
996
+ end
997
+ else
998
+ # unsupported case; we could use the exponent radix for
999
+ # the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
1000
+ raise "Unsupported format"
1001
+ end
1002
+ end
1003
+ [f,e]
1004
+ end
1005
+ def self.exponent_digits
1006
+ @fields[:exponent]
1007
+ end
1008
+ def self.exponent_radix
1009
+ @exponent_radix
1010
+ end
1011
+ # radix of the field sizes, used for splitted fields
1012
+ def self.fields_radix
1013
+ radix
1014
+ end
1015
+
1016
+ def self.decode_exponent(e,mode)
1017
+ case @exponent_mode
1018
+ when :excess
1019
+ case mode
1020
+ when :integral_significand
1021
+ e -= @integral_bias
1022
+ when :fractional_significand
1023
+ e -= @fractional_bias
1024
+ when :scientific_significand
1025
+ e -= @scientific_bias
1026
+ end
1027
+ when :radix_complement
1028
+ n = @fields[:exponent]
1029
+ v = radix_power(n)
1030
+ e = e-v if e >= v/2
1031
+ case mode
1032
+ when :integral_significand
1033
+ e -= (significand_digits-1)
1034
+ when :fractional_significand
1035
+ e += 1
1036
+ when :scientific_significand
1037
+ end
1038
+ end
1039
+ e
1040
+ end
1041
+ def self.encode_exponent(e,mode)
1042
+ case @exponent_mode
1043
+ when :excess
1044
+ case mode
1045
+ when :integral_significand
1046
+ e += @integral_bias
1047
+ when :fractional_significand
1048
+ e += @fractional_bias
1049
+ when :scientific_significand
1050
+ e += @scientific_bias
1051
+ end
1052
+ when :radix_complement
1053
+ case mode
1054
+ when :integral_significand
1055
+ e += (significand_digits-1)
1056
+ when :fractional_significand
1057
+ e -= 1
1058
+ when :scientific_significand
1059
+ end
1060
+ n = @fields[:exponent]
1061
+ v = radix_power(n)
1062
+ e = e+v if e < 0
1063
+ end
1064
+ e
1065
+ end
1066
+ end
1067
+
1068
+ # Base class for decimal floating point formats
1069
+ class DecimalFormatBase < FormatBase
1070
+ # :stopdoc:
1071
+ def self.define(params)
1072
+ @hidden_bit = false
1073
+ super params
1074
+ end
1075
+ def self.radix
1076
+ 10
1077
+ end
1078
+ def self.radix_power(n)
1079
+ 10**n
1080
+ end
1081
+
1082
+ def self.radix_log10
1083
+ 1
1084
+ end
1085
+ def self.radix_log(x)
1086
+ Math.log(x)/Math.log(10)
1087
+ end
1088
+
1089
+ def self.decimal_digits_stored
1090
+ significand_digits
1091
+ end
1092
+ def self.decimal_digits_necessary
1093
+ significand_digits
1094
+ end
1095
+ def self.decimal_max_exp
1096
+ radix_max_exp(:scientific_significand)
1097
+ end
1098
+ def self.decimal_min_exp
1099
+ radix_min_exp(:scientific_significand)
1100
+ end
1101
+ # :startdoc:
1102
+ end
1103
+
1104
+ # BCD (Binary-Coded-Decimal) floating point formats
1105
+ class BCDFormat < DecimalFormatBase
1106
+ # The fields lengths are defined in decimal digits
1107
+ def self.define(params)
1108
+
1109
+ @splitted_fields_supported = false
1110
+ define_fields params[:fields]
1111
+
1112
+ @significand_digits = @fields[:significand]
1113
+ super params
1114
+
1115
+ end
1116
+ # :stopdoc:
1117
+ def self.total_nibbles
1118
+ @field_lengths.inject{|x,y| x+y}
1119
+ end
1120
+ def self.total_bytes
1121
+ (total_nibbles+1)/2
1122
+ end
1123
+ def self.total_bits
1124
+ 4*total_nibbles
1125
+ end
1126
+
1127
+ def self.unpack_fields(v)
1128
+ # bytes have always nibbles in big-endian order
1129
+ v = input_bytes(v).convert_endianness(@endianness,:little_endian).reverse_byte_nibbles
1130
+ nibbles = v.to_hex
1131
+ # now we have a little endian nibble string
1132
+ nibble_fields = []
1133
+ i = 0
1134
+ for l in @field_lengths
1135
+ nibble_fields << nibbles[i,l]
1136
+ i += l
1137
+ end
1138
+ # now we conver the nibble strings to numbers
1139
+ i = -1
1140
+ nibble_fields.collect do |ns|
1141
+ i+=1
1142
+ if bcd_field?(i)
1143
+ if /\A\d+\Z/.match(ns)
1144
+ ns.reverse.to_i
1145
+ else
1146
+ ns.reverse
1147
+ end
1148
+ else
1149
+ ns.reverse.to_i(16)
1150
+ end
1151
+ end
1152
+ end
1153
+ def self.pack_fields(*fields)
1154
+ fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
1155
+ handle_fields fields
1156
+ i = 0
1157
+ nibbles = ""
1158
+ for l in @field_lengths
1159
+ f = fields[i]
1160
+ unless f.kind_of?(String)
1161
+ fmt = bcd_field?(i) ? 'd' : 'X'
1162
+ f = "%0#{l}#{fmt}" % fields[i]
1163
+ end
1164
+ nibbles << f.reverse
1165
+ i += 1
1166
+ end
1167
+ Bytes.from_hex(nibbles).reverse_byte_nibbles.convert_endianness(:little_endian,@endianness)
1168
+ end
1169
+ # this has beed added to allow some fields to contain binary integers rather than bcd
1170
+ def self.bcd_field?(i)
1171
+ true
1172
+ end
1173
+
1174
+ # assume @exponent_mode==:radix_complement
1175
+
1176
+ def self.unpack(v)
1177
+ f = unpack_fields_hash(v)
1178
+ m = f[:significand]
1179
+ e = f[:exponent]
1180
+ s = f[:sign]
1181
+ m,e = neg_significand_exponent(s,m,e) if s%2==1
1182
+ s = sign_to_unit(s)
1183
+ if @infinite_encoded_exp && e==@infinite_encoded_exp
1184
+ # +-infinity
1185
+ e = :infinity
1186
+ elsif @nan_encoded_exp && e==@nan_encoded_exp
1187
+ # NaN
1188
+ e = :nan
1189
+ elsif m==0
1190
+ # +-zero
1191
+ e = :zero
1192
+ else
1193
+ # normalized number
1194
+ e = decode_exponent(e, :integral_significand)
1195
+ end
1196
+ [s,m,e]
1197
+ end
1198
+
1199
+ def self.pack(s,m,e)
1200
+ msb = radix_power(@significand_digits-1)
1201
+ if e==:zero
1202
+ e = @zero_encoded_exp
1203
+ m = 0
1204
+ elsif e==:infinity
1205
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1206
+ m = 0
1207
+ elsif e==:nan
1208
+ e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1209
+ #s = -1 # ?
1210
+ #m = radix_power(@significand_digits-2) if m==0
1211
+ elsif e==:denormal
1212
+ e = @denormal_encoded_exp
1213
+ else
1214
+ # TODO: try to adjust m to keep e in range if out of valid range
1215
+ # TODO: reduce m and adjust e if m too big
1216
+
1217
+ min_exp = radix_min_exp(:integral_significand)
1218
+ if m>0
1219
+ while m<msb && e>min_exp
1220
+ e -= 1
1221
+ m *= radix
1222
+ end
1223
+ end
1224
+ if m<msb && @denormal_encoded_exp
1225
+ e = @denormal_encoded_exp
1226
+ elsif m==0 # => && @denormal_encoded_exp.nil?
1227
+ e = 0
1228
+ else
1229
+ e = encode_exponent(e, :integral_significand)
1230
+ end
1231
+ end
1232
+ s = sign_from_unit(s)
1233
+ m,e = neg_significand_exponent(0,m,e) if s%2==1
1234
+ pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1235
+ end
1236
+ # :startdoc:
1237
+ end
1238
+
1239
+ # DPD (Densely-Packed-Decimal) formats
1240
+ class DPDFormat < DecimalFormatBase
1241
+ # The field that need to be defined (with lenghts given in decimal digits) are
1242
+ # * :sign
1243
+ # * :combination
1244
+ # * :exponent_continuation
1245
+ # * :significand_continuation
1246
+ def self.define(params)
1247
+
1248
+ @splitted_fields_supported = false
1249
+ define_fields params[:fields]
1250
+ @internal_field_lengths = @field_lengths
1251
+ @internal_field_meaning = @field_meaning
1252
+ @internal_fields = @fields
1253
+ raise "Unsupported DPD format" unless @internal_fields[:combination]==5 && @internal_fields[:sign]==1 && [0,4,7].include?(@internal_fields[:significand_continuation]%10)
1254
+
1255
+
1256
+ @exponent_bits = 2 + @internal_fields[:exponent_continuation]
1257
+
1258
+ extra_bits = (@internal_fields[:significand_continuation] % 10)
1259
+ extra_digits = (extra_bits==0) ? 0 : ((extra_bits==4) ? 1 : 2)
1260
+ @significand_digits = 1 + 3*(@internal_fields[:significand_continuation]/10) + extra_digits
1261
+
1262
+ define_fields [:type,1,:sign,1,:exponent,@exponent_bits,:significand,@significand_digits]
1263
+
1264
+ if params[:bias].nil?
1265
+
1266
+ params[:bias_mode] = :scientific_significand
1267
+
1268
+ @exp_limit = 3*(2**@internal_fields[:exponent_continuation])-1
1269
+
1270
+ params[:max_exp] = @exp_limit/2
1271
+ params[:min_exp] = -params[:max_exp]
1272
+ params[:max_exp] += 1 if (@exp_limit%2)==1
1273
+ params[:bias]= -params[:min_exp]
1274
+
1275
+ end
1276
+
1277
+ super params
1278
+
1279
+ end
1280
+
1281
+ # :stopdoc:
1282
+ def self.total_bits
1283
+ @internal_field_lengths.inject{|x,y| x+y}
1284
+ end
1285
+ def self.total_bytes
1286
+ (total_bits+7)/8
1287
+ end
1288
+
1289
+
1290
+ def self.unpack_fields(v)
1291
+ # convert internal binary fields to bcd decoded fields
1292
+ a = input_bytes(v).to_bitfields(@internal_field_lengths,@endianness)
1293
+ h = {}
1294
+ (0...a.size).each do |i|
1295
+ h[@internal_field_meaning[i]] = a[i]
1296
+ end
1297
+
1298
+ i_sign = h[:sign]
1299
+ i_combination = h[:combination]
1300
+ i_exponent_continuation = h[:exponent_continuation]
1301
+ i_significand_continuation = h[:significand_continuation]
1302
+
1303
+
1304
+ type = nil
1305
+ sign = i_sign==0 ? 0 : 9
1306
+
1307
+ a,b,c,d,e = ("%05B"%i_combination).split('').collect{|bit| bit.to_i}
1308
+
1309
+ exp_msb = 0
1310
+ sig_msd = 0
1311
+
1312
+ if a==0 || b==0
1313
+ exp_msb = (a<<1)|b
1314
+ sig_msd = (c<<2)|(d<<1)|e
1315
+ elsif c==0 || d==0
1316
+ exp_msb = (c<<1)|d
1317
+ sig_msd = (1<<3)|e
1318
+ elsif e==0
1319
+ type = :infinity
1320
+ else
1321
+ type = :nan
1322
+ end
1323
+
1324
+
1325
+ hex_sig = sig_msd.to_s
1326
+ hex_sig << dpd_to_hexbcd(i_significand_continuation,@internal_fields[:significand_continuation])
1327
+ significand = hex_sig.to_i
1328
+
1329
+ exponent = i_exponent_continuation | (exp_msb << (@exponent_bits-2))
1330
+ [type,sign,exponent,significand]
1331
+ end
1332
+ def self.pack_fields(*fields)
1333
+ fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
1334
+ handle_fields fields
1335
+ type,sign,exponent,significand = fields
1336
+
1337
+ sig_hex = "%0#{@significand_digits-1}d"%significand
1338
+ sig_cont_bits = 4*(@significand_digits-1)
1339
+ sig_msd = sig_hex[0,1].to_i
1340
+ i_significand_continuation,bits = hexbcd_to_dpd(sig_hex[1..-1])
1341
+
1342
+
1343
+
1344
+ exp_msb = exponent>>(@exponent_bits-2)
1345
+ i_exponent_continuation = exponent&((1<<(@exponent_bits-2))-1)
1346
+
1347
+ i_sign = ((sign==0) ? 0 : 1)
1348
+
1349
+
1350
+ case type
1351
+ when :infinity
1352
+ i_combination = 0x1E
1353
+ when :nan
1354
+ i_combination = 0x1F
1355
+ else
1356
+ if sig_msd&0x8==0
1357
+ i_combination = sig_msd|(exp_msb<<3)
1358
+ else
1359
+ i_combination = sig_msd|(1<<4)|(exp_msb<<1)
1360
+ end
1361
+ end
1362
+ h = {:sign=>i_sign, :combination=>i_combination, :exponent_continuation=>i_exponent_continuation, :significand_continuation=>i_significand_continuation}
1363
+ fields = @internal_field_meaning.collect{|f| h[f]}
1364
+ Bytes.from_bitfields(@internal_field_lengths,fields,@endianness)
1365
+ end
1366
+
1367
+
1368
+ def self.unpack(v)
1369
+ f = unpack_fields_hash(v)
1370
+ m = f[:significand]
1371
+ e = f[:exponent]
1372
+ s = f[:sign]
1373
+ t = f[:type]
1374
+ m,e = neg_significand_exponent(s,m,e) if s%2==1
1375
+ if m==0
1376
+ # +-zero
1377
+ e = :zero
1378
+ elsif t==:infinity
1379
+ # +-inifinity
1380
+ e = :infinity
1381
+ elsif t==:nan
1382
+ # NaN
1383
+ e = :nan
1384
+ else
1385
+ # normalized number
1386
+ e = decode_exponent(e, :integral_significand)
1387
+ end
1388
+ s = sign_to_unit(s)
1389
+ [s,m,e]
1390
+ end
1391
+
1392
+ def self.pack(s,m,e)
1393
+ msb = radix_power(@significand_digits-1)
1394
+ t = nil
1395
+ if e==:zero
1396
+ e = @zero_encoded_exp
1397
+ m = 0
1398
+ elsif e==:infinity
1399
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1400
+ m = 0
1401
+ t = :infinity
1402
+ elsif e==:nan
1403
+ t = :nan
1404
+ e = 0
1405
+ s = 0
1406
+ m = 0
1407
+ elsif e==:denormal
1408
+ e = @denormal_encoded_exp || @zero_encoded_exp
1409
+ else
1410
+ # TODO: try to adjust m to keep e in range if out of valid range
1411
+ # TODO: reduce m and adjust e if m too big
1412
+
1413
+ min_exp = radix_min_exp(:integral_significand)
1414
+ if m>0 && false
1415
+ while m<msb && e>min_exp
1416
+ e -= 1
1417
+ m *= radix
1418
+ end
1419
+ end
1420
+ if m<msb && @denormal_encoded_exp && false
1421
+ e = @denormal_encoded_exp
1422
+ elsif m==0 # => && @denormal_encoded_exp.nil?
1423
+ e = 0
1424
+ else
1425
+ e = encode_exponent(e, :integral_significand)
1426
+ end
1427
+ end
1428
+ s = sign_from_unit(s)
1429
+ m,e = neg_significand_exponent(0,m,e) if s%2==1
1430
+ pack_fields_hash :sign=>s, :significand=>m, :exponent=>e, :type=>t
1431
+ end
1432
+
1433
+ # :startdoc:
1434
+
1435
+
1436
+ end
1437
+
1438
+ # This is a base class for formats that specify the field lengths in bits
1439
+ class FieldsInBitsFormatBase < FormatBase
1440
+ # :stopdoc:
1441
+ def self.fields_radix
1442
+ 2
1443
+ end
1444
+ def self.unpack_fields(v)
1445
+ input_bytes(v).to_bitfields(@field_lengths,@endianness)
1446
+ end
1447
+ def self.pack_fields(*fields)
1448
+ fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
1449
+ handle_fields fields
1450
+ Bytes.from_bitfields(@field_lengths,fields,@endianness)
1451
+ end
1452
+ # :startdoc:
1453
+ end
1454
+
1455
+ # Binary floating point formats
1456
+ class BinaryFormat < FieldsInBitsFormatBase
1457
+ # a hidden bit can be define with :hidden_bit
1458
+ def self.define(params)
1459
+ @hidden_bit = params[:hidden_bit]
1460
+ @hidden_bit = true if @hidden_bit.nil?
1461
+
1462
+ @splitted_fields_supported = true
1463
+ define_fields params[:fields]
1464
+
1465
+ @significand_digits = @fields[:significand] + (@hidden_bit ? 1 : 0)
1466
+ super params
1467
+
1468
+ end
1469
+
1470
+ # :stopdoc:
1471
+
1472
+ def self.radix
1473
+ 2
1474
+ end
1475
+ def self.radix_power(n)
1476
+ if n>=0
1477
+ 1 << n
1478
+ else
1479
+ 2**n
1480
+ end
1481
+ end
1482
+
1483
+ def self.total_bits
1484
+ @field_lengths.inject{|x,y| x+y}
1485
+ end
1486
+ def self.total_bytes
1487
+ (total_bits+7)/8
1488
+ end
1489
+
1490
+ def self.unpack(v)
1491
+ f = unpack_fields_hash(v)
1492
+ m = f[:significand]
1493
+ e = f[:exponent]
1494
+ s = f[:sign]
1495
+ m,e = neg_significand_exponent(s,m,e) if s%2==1
1496
+ if (m==0 && !@hidden_bit) ||
1497
+ (m==0 && (e==@zero_encoded_exp || e==@denormal_encoded_exp)) ||
1498
+ (e==@zero_encoded_exp && @min_encoded_exp>@zero_encoded_exp && !@denormal_encoded_exp)
1499
+ # +-zero
1500
+ e = :zero
1501
+ elsif (e==@denormal_encoded_exp)
1502
+ e = decode_exponent(e, :integral_significand)
1503
+ e += 1 if @denormal_encoded_exp==@zero_encoded_exp
1504
+ elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
1505
+ # +-inifinity
1506
+ e = :infinity
1507
+ elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
1508
+ # NaN
1509
+ e = :nan
1510
+ else
1511
+ # normalized number
1512
+ e = decode_exponent(e, :integral_significand)
1513
+ m |= radix_power(@significand_digits-1) if @hidden_bit
1514
+ end
1515
+ s = sign_to_unit(s)
1516
+ [s,m,e]
1517
+ end
1518
+
1519
+ def self.pack(s,m,e)
1520
+ msb = radix_power(@significand_digits-1)
1521
+
1522
+ if e==:zero
1523
+ e = @zero_encoded_exp || @denormal_encoded_exp
1524
+ m = 0
1525
+ elsif e==:infinity
1526
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1527
+ m = 0
1528
+ elsif e==:nan
1529
+ e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1530
+ s = minus_sign_value # ?
1531
+ m = radix_power(@significand_digits-2) if m==0
1532
+ elsif e==:denormal
1533
+ e = @denormal_encoded_exp
1534
+ else
1535
+ # TODO: try to adjust m to keep e in range if out of valid range
1536
+ # TODO: reduce m and adjust e if m too big
1537
+
1538
+ min_exp = radix_min_exp(:integral_significand)
1539
+ if m>0
1540
+ while m<msb && e>min_exp
1541
+ e -= 1
1542
+ m <<= 1 # m *= radix
1543
+ end
1544
+ end
1545
+ if m<msb && @denormal_encoded_exp
1546
+ e = @denormal_encoded_exp
1547
+ elsif m==0 # => && @denormal_encoded_exp.nil?
1548
+ e = 0
1549
+ else
1550
+ m &= (radix_power(@significand_digits-1)-1) if @hidden_bit
1551
+ e = encode_exponent(e, :integral_significand)
1552
+ end
1553
+ end
1554
+ s = sign_from_unit(s)
1555
+ m,e = neg_significand_exponent(0,m,e) if s%2==1
1556
+ pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1557
+ end
1558
+ # :startdoc:
1559
+
1560
+ end
1561
+
1562
+ # Hexadecimal floating point format
1563
+ class HexadecimalFormat < FieldsInBitsFormatBase
1564
+ def self.define(params)
1565
+ @hidden_bit = false
1566
+ @splitted_fields_supported = true
1567
+ define_fields params[:fields]
1568
+ @significand_digits = @fields[:significand]/4
1569
+ params[:exponent_radix] = 2
1570
+ super params
1571
+ end
1572
+
1573
+ # :stopdoc:
1574
+
1575
+ def self.radix
1576
+ 16
1577
+ end
1578
+ def self.fields_radix
1579
+ exponent_radix
1580
+ end
1581
+
1582
+ def self.total_bits
1583
+ @field_lengths.inject{|x,y| x+y}
1584
+ end
1585
+ def self.total_bytes
1586
+ (total_bits+7)/8
1587
+ end
1588
+
1589
+
1590
+ def self.unpack(v)
1591
+ f = unpack_fields_hash(v)
1592
+ m = f[:significand]
1593
+ e = f[:exponent]
1594
+ s = f[:sign]
1595
+ m,e = neg_significand_exponent(s,m,e) if s%2==1
1596
+ if m==0
1597
+ # +-zero
1598
+ e = :zero
1599
+ elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
1600
+ # +-inifinity
1601
+ e = :infinity
1602
+ elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
1603
+ # NaN
1604
+ e = :nan
1605
+ else
1606
+ # normalized number
1607
+ e = decode_exponent(e, :integral_significand)
1608
+ end
1609
+ s = sign_to_unit(s)
1610
+ [s,m,e]
1611
+ end
1612
+
1613
+ def self.pack(s,m,e)
1614
+ msb = radix_power(@significand_digits-1)
1615
+
1616
+ if e==:zero
1617
+ e = @zero_encoded_exp
1618
+ m = 0
1619
+ elsif e==:infinity
1620
+ e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
1621
+ m = 0
1622
+ elsif e==:nan
1623
+ e = @nan_encoded_exp || radix_power(@fields[:exponent])-1
1624
+ s = minus_sign_value # ?
1625
+ m = radix_power(@significand_digits-2) if m==0
1626
+ elsif e==:denormal
1627
+ e = @denormal_encoded_exp || @zero_encoded_exp
1628
+ else
1629
+ # TODO: try to adjust m to keep e in range if out of valid range
1630
+ # TODO: reduce m and adjust e if m too big
1631
+
1632
+ min_exp = radix_min_exp(:integral_significand)
1633
+ if m>0
1634
+ while m<msb && e>min_exp
1635
+ e -= 1
1636
+ m <<= 4 # m *= radix
1637
+ end
1638
+ end
1639
+ if m<msb && @denormal_encoded_exp
1640
+ e = @denormal_encoded_exp
1641
+ elsif m==0 # => && @denormal_encoded_exp.nil?
1642
+ e = 0
1643
+ else
1644
+ e = encode_exponent(e, :integral_significand)
1645
+ end
1646
+ end
1647
+ s = sign_from_unit(s)
1648
+ m,e = neg_significand_exponent(0,m,e) if s%2==1
1649
+ pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1650
+ end
1651
+
1652
+
1653
+ def self.minus_sign_value
1654
+ (-1) % 2
1655
+ end
1656
+
1657
+ def self.exponent_digits
1658
+ @fields[exponent]/4
1659
+ end
1660
+
1661
+ # :startdoc:
1662
+
1663
+ end
1664
+
1665
+
1666
+ def -@
1667
+ minus
1668
+ end
1669
+ def +(v)
1670
+ # TODO: coercion
1671
+ if v.form_class==form_class
1672
+ form_class.arithmetic do |t|
1673
+ x = to(t,:exact) + v.to(t,:exact)
1674
+ form_class.from_number(x,:exact)
1675
+ end
1676
+ else
1677
+ # TODO
1678
+ end
1679
+ end
1680
+ def /(v)
1681
+ # TODO: coercion
1682
+ if v.form_class==form_class
1683
+ form_class.arithmetic do |t|
1684
+ x = to(t,:exact) / v.to(t,:exact)
1685
+ form_class.from_number(x,:exact)
1686
+ end
1687
+ else
1688
+ # TODO
1689
+ end
1690
+ end
1691
+ def -(v)
1692
+ # TODO: coercion
1693
+ if v.form_class==form_class
1694
+ form_class.arithmetic do |t|
1695
+ x = to(t,:exact) - v.to(t,:exact)
1696
+ form_class.from_number(x,:exact)
1697
+ end
1698
+ else
1699
+ # TODO
1700
+ end
1701
+ end
1702
+ def *(v)
1703
+ # TODO: coercion
1704
+ if v.form_class==form_class
1705
+ form_class.arithmetic do |t|
1706
+ x = to(t,:exact) * v.to(t,:exact)
1707
+ form_class.from_number(x,:exact)
1708
+ end
1709
+ else
1710
+ # TODO
1711
+ end
1712
+ end
1713
+
1714
+ class FormatBase
1715
+ # Type used internally for arithmetic operations.
1716
+ def self.arithmetic_type
1717
+ num_class
1718
+ # Rational
1719
+ end
1720
+ # Set up the arithmetic environment; the arithmetic type is passed to the block.
1721
+ def self.arithmetic
1722
+ at = arithmetic_type
1723
+ if at.ancestors.include?(Flt::Num)
1724
+ at.context(self.context) do
1725
+ yield at
1726
+ end
1727
+ else
1728
+ # Could also use Flt::Decimal with decimal_digits_necessary, decimal_max_exp(:integral_significand), ...
1729
+ yield at
1730
+ end
1731
+ end
1732
+ end
1733
+
1734
+ # Class to define formats such as "double double" by pairing two floating-point
1735
+ # values which define a higher precision value by its sum.
1736
+ # The :half parameter is a format class that defines the type of each part
1737
+ # of the numbers.
1738
+ # The formats defined here have a fixed precision, although these formats
1739
+ # can actually have a variable precision.
1740
+ # For binary formats there's an option to gain one bit of precision
1741
+ # by adjusting the sign of the second number. This is enabled by the
1742
+ # :extra_prec option.
1743
+ # For example, the "double double" format used in PowerPC is this
1744
+ # Flt.define :DoubleDouble, DoubleFormat, :half=>IEEE_binary64, :extra_prec=>true
1745
+ # Although this has a fixed 107 bits precision, the format as used in
1746
+ # the PowerPC can have greater precision for specific values (by having
1747
+ # greater separation between the exponents of both halves)
1748
+ class DoubleFormat < FormatBase
1749
+
1750
+ def self.define(params)
1751
+ @half = params[:half]
1752
+ params = @half.parameters.merge(params)
1753
+ if @half.radix==2
1754
+ @extra_prec = params[:extra_prec]
1755
+ else
1756
+ @extra_prec = false
1757
+ end
1758
+ params[:significand_digits] = 2*@half.significand_digits
1759
+ params[:significand_digits] += 1 if @extra_prec
1760
+ @significand_digits = params[:significand_digits]
1761
+
1762
+ @hidden_bit = params[:hidden_bit] = @half.hidden_bit
1763
+
1764
+ fields1 = []
1765
+ fields2 = []
1766
+ params[:fields].each_slice(2) do |s,v|
1767
+ fields1 << s # (s.to_s+"_1").to_sym
1768
+ fields1 << v
1769
+ fields2 << (s.to_s+"_2").to_sym
1770
+ fields2 << v
1771
+ end
1772
+ params[:fields] = fields1 + fields2
1773
+
1774
+ define_fields params[:fields]
1775
+
1776
+ super params
1777
+ end
1778
+
1779
+ def self.radix
1780
+ @half.radix
1781
+ end
1782
+
1783
+ def self.half
1784
+ @half
1785
+ end
1786
+
1787
+ def self.unpack(v)
1788
+ sz = @half.total_bytes
1789
+ v1 = @half.unpack(v[0...sz])
1790
+ v2 = @half.unpack(v[sz..-1])
1791
+ if v1.last == :nan
1792
+ nan
1793
+ elsif v1.last == :infinity
1794
+ infinity(v1.sign)
1795
+ else
1796
+ v2 = @half.zero.split if @half.new(*v1).subnormal?
1797
+ params = v1 + v2
1798
+ join_fp(*params)
1799
+ end
1800
+ end
1801
+
1802
+ def self.pack(s,m,e)
1803
+ if e.kind_of?(Symbol)
1804
+ f1 = @half.pack(s,m,e)
1805
+ f2 = @half.pack(+1,0,:zero)
1806
+ else
1807
+ s1,m1,e1,s2,m2,e2 = split_fp(s,m,e)
1808
+ f1 = @half.pack(s1,m1,e1)
1809
+ f2 = @half.pack(s2,m2,e2)
1810
+ end
1811
+ f1+f2
1812
+ end
1813
+
1814
+ def split_halfs
1815
+ b = to_bytes
1816
+ sz = form_class.half.total_bytes
1817
+ b1 = b[0...sz]
1818
+ b2 = b[sz..-1]
1819
+ [form_class.half.from_bytes(b1), form_class.half.from_bytes(b2)]
1820
+ end
1821
+
1822
+ def self.join_halfs(h1,h2)
1823
+ self.from_bytes(h1.to_bytes+h2.to_bytes)
1824
+ end
1825
+
1826
+ def self.total_nibbles
1827
+ 2*total_bytes
1828
+ end
1829
+ def self.total_bytes
1830
+ 2*@half.total_bytes
1831
+ end
1832
+ def self.total_bits
1833
+ 8*total_bytes
1834
+ end
1835
+
1836
+ private
1837
+ def self.split_fp(s,m,e)
1838
+ n = @half.significand_digits
1839
+ if @half.radix==2
1840
+ if @extra_prec
1841
+ if (m & (1<<n))==0 # m.to_bits[n] == 0
1842
+ m1 = m >> (n+1) # m/2**(n+1)
1843
+ e1 = e + n + 1
1844
+ s1 = s
1845
+ m2 = m & ((1<<n) - 1) # m%2**n
1846
+ e2 = e
1847
+ s2 = s
1848
+ else
1849
+ m1 = (m >> (n+1)) + 1 # m/2**(n+1) + 1
1850
+ e1 = e + n + 1
1851
+ s1 = s
1852
+ if m1>=(1<<n) # 2**n
1853
+ m1 >>= 1
1854
+ e1 += 1
1855
+ end
1856
+ if m2==0
1857
+ m2 = (1<<(n-1)) # 2**(n-1)
1858
+ e2 = e+1
1859
+ s2 = -s
1860
+ else
1861
+ m2 = -((m & ((1<<n) - 1)) - (1<<n)) # m%2**n - 2**n
1862
+ e2 = e
1863
+ s2 = -s
1864
+ end
1865
+ end
1866
+ else # m has 2*n bits
1867
+ m1 = m >> n
1868
+ e1 = e + n
1869
+ s1 = s
1870
+ m2 = m & ((1<<n) - 1) # m%2**n
1871
+ e2 = e
1872
+ s2 = s
1873
+ end
1874
+ else
1875
+ m1 = m / @half.radix_power(n)
1876
+ e1 = e + n
1877
+ s1 = s
1878
+ m2 = m % @half.radix_power(n)
1879
+ e2 = e
1880
+ s2 = s
1881
+ end
1882
+ [s1,m1,e1,s2,m2,e2]
1883
+ end
1884
+
1885
+ def FormatBase.join_fp(s1,m1,e1,s2,m2,e2)
1886
+ if m2==0 || e2==:zero
1887
+ s = s1
1888
+ m = m1
1889
+ e = e1
1890
+ else
1891
+ m = s1*(m1<<(e1-e2)) + s2*m2
1892
+ e = e2
1893
+ end
1894
+ if m<0
1895
+ s = -1
1896
+ m = -m
1897
+ else
1898
+ s = +1
1899
+ end
1900
+ if m!=0 && e1.kind_of?(Numeric)
1901
+ # normalize
1902
+ nn = significand_digits
1903
+ while m >= (1 << nn)
1904
+ m >>= 1
1905
+ e += 1
1906
+ end
1907
+ while m>0 && m < (1 << (nn-1))
1908
+ m <<= 1
1909
+ e -= 1
1910
+ end
1911
+ end
1912
+ [s,m,e]
1913
+ end
1914
+
1915
+
1916
+ end
1917
+
1918
+
1919
+
1920
+ module_function
1921
+
1922
+ def define(*arguments)
1923
+ raise "Invalid number of arguments for Flt definitions." if arguments.size<2 || arguments.size>3
1924
+ if arguments.first.kind_of?(Class)
1925
+ base,name,parameters = arguments
1926
+ elsif arguments[1].kind_of?(Class)
1927
+ name,base,parameters = arguments
1928
+ else
1929
+ name,parameters = arguments
1930
+ base = parameters[:base] || FormatBase
1931
+ end
1932
+ Flt.const_set name, cls=Class.new(base)
1933
+ cls.define parameters
1934
+ constructor = lambda { |*args| cls.new(*args) }
1935
+ Flt.send :define_method,name,constructor
1936
+ Flt.send :module_function, name
1937
+ yield cls if block_given?
1938
+ end
1939
+
1940
+
1941
+
1942
+ def convert_bytes(bytes,from_format,to_format)
1943
+ from_format.from_bytes(bytes).convert_to(to_format)
1944
+ end
1945
+
1946
+
1947
+
1948
+
1949
+ end
1950
+