float-formats 0.1.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.
- data/History.txt +3 -0
- data/License.txt +20 -0
- data/Manifest.txt +29 -0
- data/README.txt +211 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +17 -0
- data/lib/float-formats.rb +11 -0
- data/lib/float-formats/bytes.rb +304 -0
- data/lib/float-formats/classes.rb +1550 -0
- data/lib/float-formats/formats.rb +580 -0
- data/lib/float-formats/native.rb +169 -0
- data/lib/float-formats/version.rb +9 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/script/txt2html +74 -0
- data/script/txt2html.cmd +1 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/gen_test_data.rb +119 -0
- data/test/test_data.yaml +1716 -0
- data/test/test_float-formats.rb +112 -0
- data/test/test_helper.rb +2 -0
- data/test/test_native-float.rb +25 -0
- metadata +88 -0
@@ -0,0 +1,1550 @@
|
|
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<=@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<=@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.rep_pos<neutral.digits.length
|
416
|
+
nd = fmt.get_base==10 ? decimal_digits_necessary : (significand_digits*Math.log(radix)/Math.log(fmt.get_base)).ceil+1
|
417
|
+
fmt = fmt.mode(:sig,nd)
|
418
|
+
neutral = fmt.nio_read_formatted(fmt.nio_write_formatted(fmt.nio_read_formatted(txt)))
|
419
|
+
end
|
420
|
+
f = neutral.digits.to_i(neutral.base)
|
421
|
+
e = neutral.dec_pos-neutral.digits.length
|
422
|
+
rounding = neutral.rounding
|
423
|
+
if neutral.base==radix
|
424
|
+
x = from_integral_sign_significand_exponent(0,f,e)
|
425
|
+
else
|
426
|
+
x = algM(f,e,rounding,neutral.base)
|
427
|
+
end
|
428
|
+
if neutral.sign=='-'
|
429
|
+
x = neg(x)
|
430
|
+
end
|
431
|
+
x
|
432
|
+
end
|
433
|
+
# Formats an encoded floating point value as a text string (using Nio formats)
|
434
|
+
# Accepts either a Value or a byte String.
|
435
|
+
def to_fmt(v,fmt=Nio::Fmt.default)
|
436
|
+
# this always treats the floating-point values as exact quantities
|
437
|
+
s,m,e = to_integral_sign_significand_exponent(v)
|
438
|
+
case e
|
439
|
+
when :zero
|
440
|
+
v = 0.0/(s==0 ? +1 : -1)
|
441
|
+
when :infinity
|
442
|
+
v = (s==0 ? +1.0 : -1.0)/0.0
|
443
|
+
when :nan
|
444
|
+
v = 0.0/0.0
|
445
|
+
else
|
446
|
+
v = m*radix_power(e)*((-1)**s)
|
447
|
+
end
|
448
|
+
v.nio_write(fmt)
|
449
|
+
end
|
450
|
+
|
451
|
+
# Produce an encoded floating point value using a numeric value.
|
452
|
+
# Returns a Value.
|
453
|
+
def from_number(v, mode=:approx)
|
454
|
+
fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
|
455
|
+
from_fmt(v.nio_write(fmt),fmt)
|
456
|
+
end
|
457
|
+
# Computes the value in a specified numeric class (Float, Integer, Rational, BigDecimal)
|
458
|
+
# of an encoded floating point number.
|
459
|
+
# Accepts either a Value or a byte String.
|
460
|
+
def to_number(v, number_class, mode=:approx)
|
461
|
+
fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
|
462
|
+
v = to_fmt(v,fmt)
|
463
|
+
number_class.nio_read(v,fmt)
|
464
|
+
end
|
465
|
+
|
466
|
+
# Converts an ancoded floating point number to an hexadecimal representation;
|
467
|
+
# bytes are separated if the second argument is true.
|
468
|
+
# Accepts either a Value or a byte String.
|
469
|
+
def to_hex(v,sep_bytes=false)
|
470
|
+
bytes_to_hex(input_bytes(v),sep_bytes)
|
471
|
+
end
|
472
|
+
# Produce an encoded floating point value using an hexadecimal representation.
|
473
|
+
# Returns a Value.
|
474
|
+
def from_hex(hex)
|
475
|
+
return_bytes hex_to_bytes(hex)
|
476
|
+
end
|
477
|
+
|
478
|
+
# Converts an ancoded floating point number to hash containing
|
479
|
+
# the internal fields that define the number.
|
480
|
+
# Accepts either a Value or a byte String.
|
481
|
+
def to_fields_hash(v)
|
482
|
+
a = to_fields(v)
|
483
|
+
h = {}
|
484
|
+
if @splitted_fields.nil?
|
485
|
+
(0...a.size).each do |i|
|
486
|
+
h[@field_meaning[i]] = a[i]
|
487
|
+
end
|
488
|
+
else
|
489
|
+
|
490
|
+
@fields.each_key do |f|
|
491
|
+
splits = @splitted_fields[f]
|
492
|
+
if splits
|
493
|
+
v = 0
|
494
|
+
k = 1
|
495
|
+
splits.each do |i|
|
496
|
+
v += k*a[i]
|
497
|
+
k *= fields_radix**(@field_lengths[i])
|
498
|
+
end
|
499
|
+
h[f] = v
|
500
|
+
else
|
501
|
+
h[f] = a[@field_meaning.index(f)]
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
h
|
506
|
+
end
|
507
|
+
# Produce an encoded floating point value using hash of the internal field values.
|
508
|
+
# Returns a Value.
|
509
|
+
def from_fields_hash(h)
|
510
|
+
if @splitted_fields.nil?
|
511
|
+
from_fields @field_meaning.collect{|f| h[f]}
|
512
|
+
else
|
513
|
+
flds = [nil]*@field_meaning.size
|
514
|
+
@fields.each_key do |f|
|
515
|
+
splits = @splitted_fields[f]
|
516
|
+
if splits
|
517
|
+
v = h[f]
|
518
|
+
splits.each do |i|
|
519
|
+
k = fields_radix**(@field_lengths[i])
|
520
|
+
flds[i] = v % k
|
521
|
+
v /= k
|
522
|
+
end
|
523
|
+
else
|
524
|
+
flds[@field_meaning.index(f)] = h[f]
|
525
|
+
end
|
526
|
+
end
|
527
|
+
from_fields flds
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
# Computes the next adjacent floating point value.
|
532
|
+
# Accepts either a Value or a byte String.
|
533
|
+
# Returns a Value.
|
534
|
+
def next_float(v)
|
535
|
+
s,f,e = to_integral_sign_significand_exponent(v)
|
536
|
+
return neg(prev_float(neg(v))) if s!=0 && e!=:zero
|
537
|
+
s = switch_sign_value(s) if e==:zero && s!=0
|
538
|
+
|
539
|
+
if e!=:nan && e!=:infinity
|
540
|
+
if f==0
|
541
|
+
if @gradual_underflow
|
542
|
+
e = radix_min_exp(:integral_significand)
|
543
|
+
f = 1
|
544
|
+
else
|
545
|
+
e = radix_min_exp(:integral_significand)
|
546
|
+
f = radix_power(@significand_digits-1)
|
547
|
+
end
|
548
|
+
else
|
549
|
+
f += 1
|
550
|
+
end
|
551
|
+
if f>=radix_power(@significand_digits)
|
552
|
+
f /= radix
|
553
|
+
e += 1
|
554
|
+
if e>radix_max_exp(:integral_significand)
|
555
|
+
e = :infinity
|
556
|
+
f = 0
|
557
|
+
end
|
558
|
+
end
|
559
|
+
from_integral_sign_significand_exponent(s,f,e)
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
# Computes the previous adjacent floating point value.
|
564
|
+
# Accepts either a Value or a byte String.
|
565
|
+
# Returns a Value.
|
566
|
+
def prev_float(v)
|
567
|
+
s,f,e = to_integral_sign_significand_exponent(v)
|
568
|
+
return neg(next_float(neg(v))) if s!=0
|
569
|
+
return neg(next_float(v)) if e==:zero
|
570
|
+
if e!=:nan && e!=:infinity
|
571
|
+
f -= 1
|
572
|
+
if f<radix_power(@significand_digits-1)
|
573
|
+
if e>radix_min_exp(:integral_significand)
|
574
|
+
e -= 1
|
575
|
+
f *= radix
|
576
|
+
else
|
577
|
+
if @gradual_underflow
|
578
|
+
e = :denormal
|
579
|
+
else
|
580
|
+
e = :zero
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
from_integral_sign_significand_exponent(s,f,e)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
# Produce an encoded floating point value from the integral value
|
589
|
+
# of the sign, significand and exponent.
|
590
|
+
# Returns a Value.
|
591
|
+
def from_fractional_sign_significand_exponent(sign,fraction,exponent)
|
592
|
+
msb = radix_power(@significand_digits-1)
|
593
|
+
while fraction<msb
|
594
|
+
fraction *= radix
|
595
|
+
exponent -= 1
|
596
|
+
end
|
597
|
+
from_integral_sign_significand_exponent(sign,fraction.to_i,exponent)
|
598
|
+
end
|
599
|
+
# Computes an encoded floating-point value from the integral value
|
600
|
+
# Accepts either a Value or a byte String.
|
601
|
+
def to_fractional_sign_significand_exponent(v,significand_mode=:normalized_significand)
|
602
|
+
s,m,e = to_integral_sign_significand_exponent(v)
|
603
|
+
case significand_mode
|
604
|
+
when :integral_significand
|
605
|
+
when :fractional_significand
|
606
|
+
m = Rational(m,radix_power(@significand_digits))
|
607
|
+
when :normalized_significand
|
608
|
+
m = Rational(m,radix_power(@significand_digits-1))
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
# Returns the encoded value of a floating-point number as an integer
|
613
|
+
# Accepts either a Value or a byte String.
|
614
|
+
def to_bits_integer(v)
|
615
|
+
bytes_to_int(input_bytes(v), @endianness)
|
616
|
+
end
|
617
|
+
# Defines a floating-point number from the encoded integral value.
|
618
|
+
# Returns a Value.
|
619
|
+
def from_bits_integer(i)
|
620
|
+
v = int_to_bytes(i)
|
621
|
+
if v.size<total_bytes
|
622
|
+
fill = (0.chr*(total_bytes-v.size))
|
623
|
+
if @endianness==:little_endian
|
624
|
+
bytes = fill
|
625
|
+
else
|
626
|
+
bytes = fill + bytes
|
627
|
+
end
|
628
|
+
elsif v.size>total_bytes
|
629
|
+
raise "Invalid floating point value"
|
630
|
+
end
|
631
|
+
return_bytes v
|
632
|
+
end
|
633
|
+
# Returns the encoded integral value of a floating point number
|
634
|
+
# as a text representation in a given base.
|
635
|
+
# Accepts either a Value or a byte String.
|
636
|
+
def to_bits_text(v,base)
|
637
|
+
i = to_bits_integer(v)
|
638
|
+
fmt = Nio::Fmt.default.base(base,true).mode(:fix,:exact)
|
639
|
+
if [2,4,8,16].include?(base)
|
640
|
+
n = (Math.log(base)/Math.log(2)).round.to_i
|
641
|
+
digits = (total_bits+n-1)/n
|
642
|
+
fmt.pad0s!(digits)
|
643
|
+
end
|
644
|
+
i.nio_write(fmt)
|
645
|
+
end
|
646
|
+
# Defines a floating-point number from a text representation of the
|
647
|
+
# encoded integral value in a given base.
|
648
|
+
# Returns a Value.
|
649
|
+
def from_bits_text(txt,base)
|
650
|
+
i = Integer.nio_read(txt,Nio::Fmt.base(base))
|
651
|
+
from_bits_integer i
|
652
|
+
end
|
653
|
+
|
654
|
+
# Computes the negation of a floating point value
|
655
|
+
# Accepts either a Value or a byte String.
|
656
|
+
# Returns a Value.
|
657
|
+
def neg(v)
|
658
|
+
s,f,e = to_integral_sign_significand_exponent(v)
|
659
|
+
s = switch_sign_value(s)
|
660
|
+
from_integral_sign_significand_exponent(s,f,e)
|
661
|
+
end
|
662
|
+
|
663
|
+
# Converts a floating point value to another format
|
664
|
+
def convert_to(v,fpclass)
|
665
|
+
fpclass.from_fmt(to_fmt(v))
|
666
|
+
end
|
667
|
+
|
668
|
+
# :stopdoc:
|
669
|
+
protected
|
670
|
+
def define_fields(field_definitions)
|
671
|
+
|
672
|
+
@field_lengths = []
|
673
|
+
@field_meaning = []
|
674
|
+
@fields = {}
|
675
|
+
@splitted_fields = nil
|
676
|
+
field_definitions.enum_slice(2).each do |m,l|
|
677
|
+
@field_lengths << l
|
678
|
+
@field_meaning << m
|
679
|
+
if @fields[m].nil?
|
680
|
+
@fields[m] = l
|
681
|
+
else
|
682
|
+
@splitted_fields ||= {}
|
683
|
+
@splitted_fields[m] = [@field_meaning.index(m)]
|
684
|
+
@fields[m] += l
|
685
|
+
@splitted_fields[m] <<= @field_meaning.size-1
|
686
|
+
end
|
687
|
+
end
|
688
|
+
raise "Invalid format" if @splitted_fields && !@splitted_fields_supported
|
689
|
+
end
|
690
|
+
def handle_fields(fields)
|
691
|
+
if @fields_handler
|
692
|
+
@fields_handler.call(fields)
|
693
|
+
end
|
694
|
+
end
|
695
|
+
|
696
|
+
# s is the sign of f,e
|
697
|
+
def neg_significand_exponent(s,f,e)
|
698
|
+
case @neg_mode
|
699
|
+
when :diminished_radix_complement
|
700
|
+
if exponent_radix==radix
|
701
|
+
f = (radix_power(significand_digits)-1) - f
|
702
|
+
e = (radix_power(exponent_digits)-1) - e
|
703
|
+
else
|
704
|
+
# unsupported case; we could use the exponent radix for
|
705
|
+
# the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
|
706
|
+
raise "Unsupported format"
|
707
|
+
end
|
708
|
+
when :radix_complement_significand
|
709
|
+
f = ((radix_power(significand_digits)-1) - f + 1) % radix_power(significand_digits)
|
710
|
+
when :radix_complement
|
711
|
+
if exponent_radix==radix
|
712
|
+
if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
|
713
|
+
ls,ms = e,f
|
714
|
+
ls_digits = exponent_digits
|
715
|
+
else
|
716
|
+
ls,ms = f,e
|
717
|
+
ls_digits = significand_digits
|
718
|
+
end
|
719
|
+
comb = ls + ms*radix_power(ls_digits)
|
720
|
+
comb = ((radix_power(significand_digits)-1) - comb + 1) % radix_power(significand_digits)
|
721
|
+
ls = comb % radix_power(ls_digits)
|
722
|
+
ms = comb / radix_power(ls_digits)
|
723
|
+
if @field_meaning.index(:exponent) < @field_meaning.index(:significand)
|
724
|
+
e,f = ls,ms
|
725
|
+
else
|
726
|
+
e,f = ms,ls
|
727
|
+
end
|
728
|
+
else
|
729
|
+
# unsupported case; we could use the exponent radix for
|
730
|
+
# the complement (so for hexadecimal significand/binary exponent we would use binary which is OK)
|
731
|
+
raise "Unsupported format"
|
732
|
+
end
|
733
|
+
end
|
734
|
+
[f,e]
|
735
|
+
end
|
736
|
+
def exponent_digits
|
737
|
+
@fields[:exponent]
|
738
|
+
end
|
739
|
+
def exponent_radix
|
740
|
+
@exponent_radix
|
741
|
+
end
|
742
|
+
# radix of the field sizes, used for splitted fields
|
743
|
+
def fields_radix
|
744
|
+
radix
|
745
|
+
end
|
746
|
+
|
747
|
+
def decode_exponent(e,mode)
|
748
|
+
case @exponent_mode
|
749
|
+
when :excess
|
750
|
+
case mode
|
751
|
+
when :integral_significand
|
752
|
+
e -= @integral_bias
|
753
|
+
when :fractional_significand
|
754
|
+
e -= @fractional_bias
|
755
|
+
when :normalized_significand
|
756
|
+
e -= @normalized_bias
|
757
|
+
end
|
758
|
+
when :radix_complement
|
759
|
+
n = @fields[:exponent]
|
760
|
+
v = radix_power(n)
|
761
|
+
e = e-v if e >= v/2
|
762
|
+
case mode
|
763
|
+
when :integral_significand
|
764
|
+
e -= (significand_digits-1)
|
765
|
+
when :fractional_significand
|
766
|
+
e += 1
|
767
|
+
when :normalized_significand
|
768
|
+
end
|
769
|
+
end
|
770
|
+
e
|
771
|
+
end
|
772
|
+
def encode_exponent(e,mode)
|
773
|
+
case @exponent_mode
|
774
|
+
when :excess
|
775
|
+
case mode
|
776
|
+
when :integral_significand
|
777
|
+
e += @integral_bias
|
778
|
+
when :fractional_significand
|
779
|
+
e += @fractional_bias
|
780
|
+
when :normalized_significand
|
781
|
+
e += @normalized_bias
|
782
|
+
end
|
783
|
+
when :radix_complement
|
784
|
+
case mode
|
785
|
+
when :integral_significand
|
786
|
+
e += (significand_digits-1)
|
787
|
+
when :fractional_significand
|
788
|
+
e -= 1
|
789
|
+
when :normalized_significand
|
790
|
+
end
|
791
|
+
n = @fields[:exponent]
|
792
|
+
v = radix_power(n)
|
793
|
+
e = e+v if e < 0
|
794
|
+
end
|
795
|
+
e
|
796
|
+
end
|
797
|
+
|
798
|
+
# these are functions from Nio::Clinger, generalized for arbitrary floating point formats
|
799
|
+
def ratio_float(u,v,k,round_mode)
|
800
|
+
q = u.div v
|
801
|
+
r = u-q*v
|
802
|
+
v_r = v-r
|
803
|
+
z = from_integral_sign_significand_exponent(0,q,k)
|
804
|
+
if r<v_r
|
805
|
+
z
|
806
|
+
elsif r>v_r
|
807
|
+
z = next_float(z)
|
808
|
+
elsif (round_mode==:even && q.even?) || (round_mode==:zero)
|
809
|
+
z
|
810
|
+
else
|
811
|
+
z = next_float(z)
|
812
|
+
end
|
813
|
+
end
|
814
|
+
|
815
|
+
def algM(f,e,round_mode,eb=10)
|
816
|
+
|
817
|
+
if e<0
|
818
|
+
u,v,k = f,eb**(-e),0
|
819
|
+
else
|
820
|
+
u,v,k = f*(eb**e),1,0
|
821
|
+
end
|
822
|
+
|
823
|
+
n = significand_digits
|
824
|
+
min_e = radix_min_exp(:integral_significand)
|
825
|
+
max_e = radix_max_exp(:integral_significand)
|
826
|
+
|
827
|
+
rp_n = radix_power(n)
|
828
|
+
rp_n_1 = radix_power(n-1)
|
829
|
+
r = radix
|
830
|
+
|
831
|
+
loop do
|
832
|
+
x = u.div(v) # bottleneck
|
833
|
+
# overflow if k>=max_e
|
834
|
+
if (x>=rp_n_1 && x<rp_n) || k==min_e || k==max_e
|
835
|
+
return ratio_float(u,v,k,round_mode)
|
836
|
+
elsif x<rp_n_1
|
837
|
+
u *= r
|
838
|
+
k -= 1
|
839
|
+
elsif x>=rp_n
|
840
|
+
v *= r
|
841
|
+
k += 1
|
842
|
+
end
|
843
|
+
end
|
844
|
+
|
845
|
+
end
|
846
|
+
# :startdoc:
|
847
|
+
end
|
848
|
+
|
849
|
+
# Base class for decimal floating point formats
|
850
|
+
class DecimalFormatBase < FormatBase
|
851
|
+
# :stopdoc:
|
852
|
+
def initialize(params)
|
853
|
+
@hidden_bit = false
|
854
|
+
super params
|
855
|
+
end
|
856
|
+
def radix
|
857
|
+
10
|
858
|
+
end
|
859
|
+
def radix_power(n)
|
860
|
+
10**n
|
861
|
+
end
|
862
|
+
|
863
|
+
def radix_log10
|
864
|
+
1
|
865
|
+
end
|
866
|
+
def radix_log(x)
|
867
|
+
Math.log(x)/Math.log(10)
|
868
|
+
end
|
869
|
+
|
870
|
+
def decimal_digits_stored
|
871
|
+
significand_digits
|
872
|
+
end
|
873
|
+
def decimal_digits_necessary
|
874
|
+
significand_digits
|
875
|
+
end
|
876
|
+
def decimal_max_exp
|
877
|
+
radix_max_exp(:normalized_significand)
|
878
|
+
end
|
879
|
+
def decimal_min_exp
|
880
|
+
radix_min_exp(:normalized_significand)
|
881
|
+
end
|
882
|
+
|
883
|
+
def to_fmt(v,fmt=Nio::Fmt.default)
|
884
|
+
# this always treats the floating-point values as exact quantities
|
885
|
+
s,m,e = to_integral_sign_significand_exponent(v)
|
886
|
+
case e
|
887
|
+
when :zero
|
888
|
+
v = 0.0/(s==0 ? +1 : -1)
|
889
|
+
when :infinity
|
890
|
+
v = (s==0 ? +1.0 : -1.0)/0.0
|
891
|
+
when :nan
|
892
|
+
v = 0.0/0.0
|
893
|
+
else
|
894
|
+
sign = s==0 ? '' : '-'
|
895
|
+
v = BigDecimal("#{sign}#{m}E#{e}")
|
896
|
+
end
|
897
|
+
v.nio_write(fmt)
|
898
|
+
end
|
899
|
+
# :startdoc:
|
900
|
+
end
|
901
|
+
|
902
|
+
# BCD (Binary-Coded-Decimal) floating point formats
|
903
|
+
class BCDFormat < DecimalFormatBase
|
904
|
+
# The fields lengths are defined in decimal digits
|
905
|
+
def initialize(params)
|
906
|
+
|
907
|
+
@splitted_fields_supported = false
|
908
|
+
define_fields params[:fields]
|
909
|
+
|
910
|
+
@significand_digits = @fields[:significand]
|
911
|
+
super params
|
912
|
+
|
913
|
+
end
|
914
|
+
# :stopdoc:
|
915
|
+
def total_nibbles
|
916
|
+
@field_lengths.inject{|x,y| x+y}
|
917
|
+
end
|
918
|
+
def total_bytes
|
919
|
+
(total_nibbles+1)/2
|
920
|
+
end
|
921
|
+
def total_bits
|
922
|
+
4*total_nibbles
|
923
|
+
end
|
924
|
+
|
925
|
+
def to_fields(v)
|
926
|
+
# bytes have always nibbles in big-endian order
|
927
|
+
v = reverse_byte_nibbles(convert_endianness(input_bytes(v),@endianness,:little_endian))
|
928
|
+
nibbles = bytes_to_hex(v)
|
929
|
+
# now we have a little endian nibble string
|
930
|
+
nibble_fields = []
|
931
|
+
i = 0
|
932
|
+
for l in @field_lengths
|
933
|
+
nibble_fields << nibbles[i,l]
|
934
|
+
i += l
|
935
|
+
end
|
936
|
+
# now we conver the nibble strings to numbers
|
937
|
+
i = -1
|
938
|
+
nibble_fields.collect{|ns| i+=1;bcd_field?(i) ? ns.reverse.to_i : ns.reverse.to_i(16)}
|
939
|
+
end
|
940
|
+
def from_fields(*fields)
|
941
|
+
fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
|
942
|
+
handle_fields fields
|
943
|
+
i = 0
|
944
|
+
nibbles = ""
|
945
|
+
for l in @field_lengths
|
946
|
+
fmt = bcd_field?(i) ? 'd' : 'X'
|
947
|
+
nibbles << ("%0#{l}#{fmt}" % fields[i]).reverse
|
948
|
+
i += 1
|
949
|
+
end
|
950
|
+
v = hex_to_bytes(nibbles)
|
951
|
+
v = convert_endianness(reverse_byte_nibbles(v),:little_endian,@endianness)
|
952
|
+
return_bytes v
|
953
|
+
end
|
954
|
+
# this has beed added to allow some fields to contain binary integers rather than bcd
|
955
|
+
def bcd_field?(i)
|
956
|
+
true
|
957
|
+
end
|
958
|
+
|
959
|
+
# assume @exponent_mode==:radix_complement
|
960
|
+
|
961
|
+
def to_integral_sign_significand_exponent(v)
|
962
|
+
f = to_fields_hash(v)
|
963
|
+
m = f[:significand]
|
964
|
+
e = f[:exponent]
|
965
|
+
s = f[:sign]
|
966
|
+
m,e = neg_significand_exponent(s,m,e) if s%2==1
|
967
|
+
if m==0
|
968
|
+
# +-zero
|
969
|
+
e = :zero
|
970
|
+
elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
|
971
|
+
# +-inifinity
|
972
|
+
e = :infinity
|
973
|
+
elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
|
974
|
+
# NaN
|
975
|
+
e = :nan
|
976
|
+
else
|
977
|
+
# normalized number
|
978
|
+
e = decode_exponent(e, :integral_significand)
|
979
|
+
end
|
980
|
+
[s,m,e]
|
981
|
+
end
|
982
|
+
|
983
|
+
def from_integral_sign_significand_exponent(s,m,e)
|
984
|
+
msb = radix_power(@significand_digits-1)
|
985
|
+
if e==:zero
|
986
|
+
e = @zero_encoded_exp
|
987
|
+
m = 0
|
988
|
+
elsif e==:infinity
|
989
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
990
|
+
m = 0
|
991
|
+
elsif e==:nan
|
992
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
993
|
+
s = minus_sign_value # ?
|
994
|
+
m = radix_power(@significand_digits-2) if m==0
|
995
|
+
elsif e==:denormal
|
996
|
+
e = @denormal_encoded_exp
|
997
|
+
else
|
998
|
+
# to do: try to adjust m to keep e in range if out of valid range
|
999
|
+
# to do: reduce m and adjust e if m too big
|
1000
|
+
|
1001
|
+
min_exp = radix_min_exp(:integral_significand)
|
1002
|
+
if m>0
|
1003
|
+
while m<msb && e>min_exp
|
1004
|
+
e -= 1
|
1005
|
+
m *= radix
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
if m<msb && @denormal_encoded_exp
|
1009
|
+
e = @denormal_encoded_exp
|
1010
|
+
elsif m==0 # => && @denormal_encoded_exp.nil?
|
1011
|
+
e = 0
|
1012
|
+
else
|
1013
|
+
e = encode_exponent(e, :integral_significand)
|
1014
|
+
end
|
1015
|
+
end
|
1016
|
+
m,e = neg_significand_exponent(0,m,e) if s%2==1
|
1017
|
+
from_fields_hash :sign=>s, :significand=>m, :exponent=>e
|
1018
|
+
end
|
1019
|
+
# :startdoc:
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
# DPD (Densely-Packed-Decimal) formats
|
1023
|
+
class DPDFormat < DecimalFormatBase
|
1024
|
+
# The field that need to be defined (with lenghts given in decimal digits) are
|
1025
|
+
# * :sign
|
1026
|
+
# * :combination
|
1027
|
+
# * :exponent_continuation
|
1028
|
+
# * :significand_continuation
|
1029
|
+
def initialize(params)
|
1030
|
+
|
1031
|
+
@splitted_fields_supported = false
|
1032
|
+
define_fields params[:fields]
|
1033
|
+
@internal_field_lengths = @field_lengths
|
1034
|
+
@internal_field_meaning = @field_meaning
|
1035
|
+
@internal_fields = @fields
|
1036
|
+
raise "Unsupported DPD format" unless @internal_fields[:combination]==5 && @internal_fields[:sign]==1 && [0,4,7].include?(@internal_fields[:significand_continuation]%10)
|
1037
|
+
|
1038
|
+
|
1039
|
+
@exponent_bits = 2 + @internal_fields[:exponent_continuation]
|
1040
|
+
|
1041
|
+
extra_bits = (@internal_fields[:significand_continuation] % 10)
|
1042
|
+
extra_digits = (extra_bits==0) ? 0 : ((extra_bits==4) ? 1 : 2)
|
1043
|
+
@significand_digits = 1 + 3*(@internal_fields[:significand_continuation]/10) + extra_digits
|
1044
|
+
|
1045
|
+
define_fields [:type,1,:sign,1,:exponent,@exponent_bits,:significand,@significand_digits]
|
1046
|
+
|
1047
|
+
if params[:bias].nil?
|
1048
|
+
|
1049
|
+
params[:bias_mode] = :normalized_significand
|
1050
|
+
|
1051
|
+
@exp_limit = 3*(2**@internal_fields[:exponent_continuation])-1
|
1052
|
+
|
1053
|
+
params[:max_exp] = @exp_limit/2
|
1054
|
+
params[:min_exp] = -params[:max_exp]
|
1055
|
+
params[:max_exp] += 1 if (@exp_limit%2)==1
|
1056
|
+
params[:bias]= -params[:min_exp]
|
1057
|
+
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
super params
|
1061
|
+
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
# :stopdoc:
|
1065
|
+
def total_bits
|
1066
|
+
@internal_field_lengths.inject{|x,y| x+y}
|
1067
|
+
end
|
1068
|
+
def total_bytes
|
1069
|
+
(total_bits+7)/8
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
|
1073
|
+
def to_fields(v)
|
1074
|
+
# convert internal binary fields to bcd decoded fields
|
1075
|
+
a = get_bitfields(input_bytes(v),@internal_field_lengths,@endianness)
|
1076
|
+
h = {}
|
1077
|
+
(0...a.size).each do |i|
|
1078
|
+
h[@internal_field_meaning[i]] = a[i]
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
i_sign = h[:sign]
|
1082
|
+
i_combination = h[:combination]
|
1083
|
+
i_exponent_continuation = h[:exponent_continuation]
|
1084
|
+
i_significand_continuation = h[:significand_continuation]
|
1085
|
+
|
1086
|
+
|
1087
|
+
type = nil
|
1088
|
+
sign = i_sign==0 ? 0 : 9
|
1089
|
+
|
1090
|
+
a,b,c,d,e = ("%05B"%i_combination).split('').collect{|bit| bit.to_i}
|
1091
|
+
|
1092
|
+
exp_msb = 0
|
1093
|
+
sig_msd = 0
|
1094
|
+
|
1095
|
+
if a==0 || b==0
|
1096
|
+
exp_msb = (a<<1)|b
|
1097
|
+
sig_msd = (c<<2)|(d<<1)|e
|
1098
|
+
elsif c==0 || d==0
|
1099
|
+
exp_msb = (c<<1)|d
|
1100
|
+
sig_msd = (1<<3)|e
|
1101
|
+
elsif e==0
|
1102
|
+
type = :infinity
|
1103
|
+
else
|
1104
|
+
type = :nan
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
|
1108
|
+
hex_sig = sig_msd.to_s
|
1109
|
+
hex_sig << dpd_to_hexbcd(i_significand_continuation,@internal_fields[:significand_continuation])
|
1110
|
+
significand = hex_sig.to_i
|
1111
|
+
|
1112
|
+
exponent = i_exponent_continuation | (exp_msb << (@exponent_bits-2))
|
1113
|
+
[type,sign,exponent,significand]
|
1114
|
+
end
|
1115
|
+
def from_fields(*fields)
|
1116
|
+
fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
|
1117
|
+
handle_fields fields
|
1118
|
+
type,sign,exponent,significand = fields
|
1119
|
+
|
1120
|
+
sig_hex = "%0#{@significand_digits-1}d"%significand
|
1121
|
+
sig_cont_bits = 4*(@significand_digits-1)
|
1122
|
+
sig_msd = sig_hex[0,1].to_i
|
1123
|
+
i_significand_continuation,bits = hexbcd_to_dpd(sig_hex[1..-1])
|
1124
|
+
|
1125
|
+
|
1126
|
+
|
1127
|
+
exp_msb = exponent>>(@exponent_bits-2)
|
1128
|
+
i_exponent_continuation = exponent&((1<<(@exponent_bits-2))-1)
|
1129
|
+
|
1130
|
+
i_sign = ((sign==0) ? 0 : 1)
|
1131
|
+
|
1132
|
+
|
1133
|
+
case type
|
1134
|
+
when :infinity
|
1135
|
+
i_combination = 0x1E
|
1136
|
+
when :nan
|
1137
|
+
i_combination = 0x1F
|
1138
|
+
else
|
1139
|
+
if sig_msd&0x8==0
|
1140
|
+
i_combination = sig_msd|(exp_msb<<3)
|
1141
|
+
else
|
1142
|
+
i_combination = sig_msd|(1<<4)|(exp_msb<<1)
|
1143
|
+
end
|
1144
|
+
end
|
1145
|
+
h = {:sign=>i_sign, :combination=>i_combination, :exponent_continuation=>i_exponent_continuation, :significand_continuation=>i_significand_continuation}
|
1146
|
+
fields = @internal_field_meaning.collect{|f| h[f]}
|
1147
|
+
return_bytes set_bitfields(@internal_field_lengths,fields,@endianness)
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
|
1151
|
+
def to_integral_sign_significand_exponent(v)
|
1152
|
+
f = to_fields_hash(v)
|
1153
|
+
m = f[:significand]
|
1154
|
+
e = f[:exponent]
|
1155
|
+
s = f[:sign]
|
1156
|
+
t = f[:type]
|
1157
|
+
m,e = neg_significand_exponent(s,m,e) if s%2==1
|
1158
|
+
if m==0
|
1159
|
+
# +-zero
|
1160
|
+
e = :zero
|
1161
|
+
elsif t==:infinity
|
1162
|
+
# +-inifinity
|
1163
|
+
e = :infinity
|
1164
|
+
elsif t==:nan
|
1165
|
+
# NaN
|
1166
|
+
e = :nan
|
1167
|
+
else
|
1168
|
+
# normalized number
|
1169
|
+
e = decode_exponent(e, :integral_significand)
|
1170
|
+
end
|
1171
|
+
[s,m,e]
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
def from_integral_sign_significand_exponent(s,m,e)
|
1175
|
+
msb = radix_power(@significand_digits-1)
|
1176
|
+
#puts "DEC FROM #{s} #{m} #{e}"
|
1177
|
+
t = nil
|
1178
|
+
if e==:zero
|
1179
|
+
e = @zero_encoded_exp
|
1180
|
+
m = 0
|
1181
|
+
elsif e==:infinity
|
1182
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
1183
|
+
m = 0
|
1184
|
+
t = :infinity
|
1185
|
+
elsif e==:nan
|
1186
|
+
t = :nan
|
1187
|
+
e = 0
|
1188
|
+
s = 0
|
1189
|
+
m = 0
|
1190
|
+
elsif e==:denormal
|
1191
|
+
e = @denormal_encoded_exp || @zero_encoded_exp
|
1192
|
+
else
|
1193
|
+
# to do: try to adjust m to keep e in range if out of valid range
|
1194
|
+
# to do: reduce m and adjust e if m too big
|
1195
|
+
|
1196
|
+
min_exp = radix_min_exp(:integral_significand)
|
1197
|
+
if m>0 && false
|
1198
|
+
while m<msb && e>min_exp
|
1199
|
+
e -= 1
|
1200
|
+
m *= radix
|
1201
|
+
end
|
1202
|
+
end
|
1203
|
+
if m<msb && @denormal_encoded_exp && false
|
1204
|
+
e = @denormal_encoded_exp
|
1205
|
+
elsif m==0 # => && @denormal_encoded_exp.nil?
|
1206
|
+
e = 0
|
1207
|
+
else
|
1208
|
+
e = encode_exponent(e, :integral_significand)
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
m,e = neg_significand_exponent(0,m,e) if s%2==1
|
1212
|
+
from_fields_hash :sign=>s, :significand=>m, :exponent=>e, :type=>t
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
# :startdoc:
|
1216
|
+
|
1217
|
+
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
# This is a base class for formats that specify the field lengths in bits
|
1221
|
+
class FieldsInBitsFormatBase < FormatBase
|
1222
|
+
# :stopdoc:
|
1223
|
+
def fields_radix
|
1224
|
+
2
|
1225
|
+
end
|
1226
|
+
def to_fields(v)
|
1227
|
+
get_bitfields(input_bytes(v),@field_lengths,@endianness)
|
1228
|
+
end
|
1229
|
+
def from_fields(*fields)
|
1230
|
+
fields = fields[0] if fields.size==1 and fields[0].kind_of?(Array)
|
1231
|
+
handle_fields fields
|
1232
|
+
return_bytes set_bitfields(@field_lengths,fields,@endianness)
|
1233
|
+
end
|
1234
|
+
# :startdoc:
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
# Binary floating point formats
|
1238
|
+
class BinaryFormat < FieldsInBitsFormatBase
|
1239
|
+
# a hidden bit can be define with :hidden_bit
|
1240
|
+
def initialize(params)
|
1241
|
+
@hidden_bit = params[:hidden_bit]
|
1242
|
+
@hidden_bit = true if @hidden_bit.nil?
|
1243
|
+
|
1244
|
+
@splitted_fields_supported = true
|
1245
|
+
define_fields params[:fields]
|
1246
|
+
|
1247
|
+
@significand_digits = @fields[:significand] + (@hidden_bit ? 1 : 0)
|
1248
|
+
super params
|
1249
|
+
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
# :stopdoc:
|
1253
|
+
|
1254
|
+
def radix
|
1255
|
+
2
|
1256
|
+
end
|
1257
|
+
def radix_power(n)
|
1258
|
+
if n>=0
|
1259
|
+
1 << n
|
1260
|
+
else
|
1261
|
+
2**n
|
1262
|
+
end
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
def total_bits
|
1266
|
+
@field_lengths.inject{|x,y| x+y}
|
1267
|
+
end
|
1268
|
+
def total_bytes
|
1269
|
+
(total_bits+7)/8
|
1270
|
+
end
|
1271
|
+
|
1272
|
+
def to_integral_sign_significand_exponent(v)
|
1273
|
+
f = to_fields_hash(v)
|
1274
|
+
m = f[:significand]
|
1275
|
+
e = f[:exponent]
|
1276
|
+
s = f[:sign]
|
1277
|
+
m,e = neg_significand_exponent(s,m,e) if s%2==1
|
1278
|
+
if (m==0 && !@hidden_bit) ||
|
1279
|
+
(m==0 && (e==@zero_encoded_exp || e==@denormal_encoded_exp)) ||
|
1280
|
+
(e==@zero_encoded_exp && @min_encoded_exp>@zero_encoded_exp && !@denormal_encoded_exp)
|
1281
|
+
# +-zero
|
1282
|
+
e = :zero
|
1283
|
+
elsif (e==@denormal_encoded_exp)
|
1284
|
+
e = decode_exponent(e, :integral_significand)
|
1285
|
+
e += 1 if @denormal_encoded_exp==@zero_encoded_exp
|
1286
|
+
elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
|
1287
|
+
# +-inifinity
|
1288
|
+
e = :infinity
|
1289
|
+
elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
|
1290
|
+
# NaN
|
1291
|
+
e = :nan
|
1292
|
+
else
|
1293
|
+
# normalized number
|
1294
|
+
e = decode_exponent(e, :integral_significand)
|
1295
|
+
m |= radix_power(@significand_digits-1) if @hidden_bit
|
1296
|
+
end
|
1297
|
+
[s,m,e]
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
def from_integral_sign_significand_exponent(s,m,e)
|
1301
|
+
msb = radix_power(@significand_digits-1)
|
1302
|
+
|
1303
|
+
if e==:zero
|
1304
|
+
e = @zero_encoded_exp || @denormal_encoded_exp
|
1305
|
+
m = 0
|
1306
|
+
elsif e==:infinity
|
1307
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
1308
|
+
m = 0
|
1309
|
+
elsif e==:nan
|
1310
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
1311
|
+
s = minus_sign_value # ?
|
1312
|
+
m = radix_power(@significand_digits-2) if m==0
|
1313
|
+
elsif e==:denormal
|
1314
|
+
e = @denormal_encoded_exp
|
1315
|
+
else
|
1316
|
+
# to do: try to adjust m to keep e in range if out of valid range
|
1317
|
+
# to do: reduce m and adjust e if m too big
|
1318
|
+
|
1319
|
+
min_exp = radix_min_exp(:integral_significand)
|
1320
|
+
if m>0
|
1321
|
+
while m<msb && e>min_exp
|
1322
|
+
e -= 1
|
1323
|
+
m <<= 1 # m *= radix
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
if m<msb && @denormal_encoded_exp
|
1327
|
+
e = @denormal_encoded_exp
|
1328
|
+
elsif m==0 # => && @denormal_encoded_exp.nil?
|
1329
|
+
e = 0
|
1330
|
+
else
|
1331
|
+
m &= (radix_power(@significand_digits-1)-1) if @hidden_bit
|
1332
|
+
e = encode_exponent(e, :integral_significand)
|
1333
|
+
end
|
1334
|
+
end
|
1335
|
+
m,e = neg_significand_exponent(0,m,e) if s%2==1
|
1336
|
+
from_fields_hash :sign=>s, :significand=>m, :exponent=>e
|
1337
|
+
end
|
1338
|
+
# :startdoc:
|
1339
|
+
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
# Hexadecimal floating point format
|
1343
|
+
class HexadecimalFormat < FieldsInBitsFormatBase
|
1344
|
+
def initialize(params)
|
1345
|
+
@hidden_bit = false
|
1346
|
+
@splitted_fields_supported = true
|
1347
|
+
define_fields params[:fields]
|
1348
|
+
@significand_digits = @fields[:significand]/4
|
1349
|
+
params[:exponent_radix] = 2
|
1350
|
+
super params
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
# :stopdoc:
|
1354
|
+
|
1355
|
+
def radix
|
1356
|
+
16
|
1357
|
+
end
|
1358
|
+
def fields_radix
|
1359
|
+
exponent_radix
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
def total_bits
|
1363
|
+
@field_lengths.inject{|x,y| x+y}
|
1364
|
+
end
|
1365
|
+
def total_bytes
|
1366
|
+
(total_bits+7)/8
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
|
1370
|
+
def to_integral_sign_significand_exponent(v)
|
1371
|
+
f = to_fields_hash(v)
|
1372
|
+
m = f[:significand]
|
1373
|
+
e = f[:exponent]
|
1374
|
+
s = f[:sign]
|
1375
|
+
m,e = neg_significand_exponent(s,m,e) if s%2==1
|
1376
|
+
if m==0
|
1377
|
+
# +-zero
|
1378
|
+
e = :zero
|
1379
|
+
elsif @infinite_encoded_exp && e==@infinite_encoded_exp && m==0
|
1380
|
+
# +-inifinity
|
1381
|
+
e = :infinity
|
1382
|
+
elsif @nan_encoded_exp && e==@nan_encoded_exp && m!=0
|
1383
|
+
# NaN
|
1384
|
+
e = :nan
|
1385
|
+
else
|
1386
|
+
# normalized number
|
1387
|
+
e = decode_exponent(e, :integral_significand)
|
1388
|
+
end
|
1389
|
+
[s,m,e]
|
1390
|
+
end
|
1391
|
+
|
1392
|
+
def from_integral_sign_significand_exponent(s,m,e)
|
1393
|
+
msb = radix_power(@significand_digits-1)
|
1394
|
+
|
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
|
+
elsif e==:nan
|
1402
|
+
e = @infinite_encoded_exp || radix_power(@fields[:exponent])-1
|
1403
|
+
s = minus_sign_value # ?
|
1404
|
+
m = radix_power(@significand_digits-2) if m==0
|
1405
|
+
elsif e==:denormal
|
1406
|
+
e = @denormal_encoded_exp || @zero_encoded_exp
|
1407
|
+
else
|
1408
|
+
# to do: try to adjust m to keep e in range if out of valid range
|
1409
|
+
# to do: reduce m and adjust e if m too big
|
1410
|
+
|
1411
|
+
min_exp = radix_min_exp(:integral_significand)
|
1412
|
+
if m>0
|
1413
|
+
while m<msb && e>min_exp
|
1414
|
+
e -= 1
|
1415
|
+
m <<= 4 # m *= radix
|
1416
|
+
end
|
1417
|
+
end
|
1418
|
+
if m<msb && @denormal_encoded_exp
|
1419
|
+
e = @denormal_encoded_exp
|
1420
|
+
elsif m==0 # => && @denormal_encoded_exp.nil?
|
1421
|
+
e = 0
|
1422
|
+
else
|
1423
|
+
e = encode_exponent(e, :integral_significand)
|
1424
|
+
end
|
1425
|
+
end
|
1426
|
+
m,e = neg_significand_exponent(0,m,e) if s%2==1
|
1427
|
+
from_fields_hash :sign=>s, :significand=>m, :exponent=>e
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
|
1431
|
+
def minus_sign_value
|
1432
|
+
(-1) % 2
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
def exponent_digits
|
1436
|
+
@fields[exponent]/4
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
# :startdoc:
|
1440
|
+
|
1441
|
+
end
|
1442
|
+
|
1443
|
+
|
1444
|
+
# A class to handle a floating-point representation (bytes) and its format class in a single object.
|
1445
|
+
# This eases the definition and manipulation of floating-point values:
|
1446
|
+
#
|
1447
|
+
# v = FltPnt::Value.from_fmt(FltPnt::IEEE_DOUBLE, '1.1')
|
1448
|
+
# # or:
|
1449
|
+
# v = FltPnt::IEEE_DOUBLE.from_fmt('1.1')
|
1450
|
+
# puts v.to_fields_hash.inspect # -> {:sign=>0, :significand=>450359962737050, :exponent=>1023}
|
1451
|
+
# puts v.next.to_hex(true) # -> 9B 99 99 99 99 99 F1 3F
|
1452
|
+
# w = v.convert_to(FltPnt::IEEE_SINGLE)
|
1453
|
+
# puts w.next.to_hex(true) # -> CE CC 8C 3F
|
1454
|
+
#
|
1455
|
+
class Value
|
1456
|
+
def initialize(fptype,value)
|
1457
|
+
@fptype = fptype
|
1458
|
+
@value = value
|
1459
|
+
end
|
1460
|
+
def self.from_fmt(fptype,txt,fmt=Nio::Fmt.default)
|
1461
|
+
self.new fptype, fptype.from_fmt(txt,fmt)
|
1462
|
+
end
|
1463
|
+
def self.from_hex(fptype,hx)
|
1464
|
+
self.new fptype, fptype.from_hex(hx)
|
1465
|
+
end
|
1466
|
+
def self.from_fields(fptype, *fields)
|
1467
|
+
self.new fptype, fptype.from_fields(*fields)
|
1468
|
+
end
|
1469
|
+
def self.from_fields_hash(fptype, fields)
|
1470
|
+
self.new fptype, fptype.from_fields_hash(fields)
|
1471
|
+
end
|
1472
|
+
def self.from_integral_sign_significand_exponent(fptype,s,m,e)
|
1473
|
+
self.new fptype, fptype.from_integral_sign_significand_exponent(s,m,e)
|
1474
|
+
end
|
1475
|
+
def self.from_fractional_sign_significand_exponent(fptype,sign,fraction,exponent)
|
1476
|
+
self.new fptype, fptype.from_fractional_sign_significand_exponent(sign,fraction,exponent)
|
1477
|
+
end
|
1478
|
+
def self.from_number(fptype,v,mode=:approx)
|
1479
|
+
self.new fptype, fptype.from_number(v,mode)
|
1480
|
+
end
|
1481
|
+
def self.from_bits_integer(i)
|
1482
|
+
self.new fptype, fptype.from_bits_integer(i)
|
1483
|
+
end
|
1484
|
+
def self.from_bits_text(txt,base)
|
1485
|
+
self.new fptype, fptype.from_bits_text(txt,base)
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
def to_fmt(fmt=Nio::Fmt.default)
|
1489
|
+
@fptype.to_fmt(@value,fmt)
|
1490
|
+
end
|
1491
|
+
def to_hex(sep_bytes=false)
|
1492
|
+
@fptype.to_hex(@value,sep_bytes)
|
1493
|
+
end
|
1494
|
+
def to_fields
|
1495
|
+
@fptype.to_fields(@value)
|
1496
|
+
end
|
1497
|
+
def to_fields_hash
|
1498
|
+
@fptype.to_fields_hash(@value)
|
1499
|
+
end
|
1500
|
+
def to_integral_sign_significand_exponent
|
1501
|
+
@fptype.to_integral_sign_significand_exponent(@value)
|
1502
|
+
end
|
1503
|
+
def to_fractional_sign_significand_exponent(significand_mode=:normalized_significand)
|
1504
|
+
@fptype.to_fractional_sign_significand_exponent(@value, significand_mode)
|
1505
|
+
end
|
1506
|
+
def to_number(number_class, mode=:approx)
|
1507
|
+
@fptype.to_number(@value, number_class, mode)
|
1508
|
+
end
|
1509
|
+
def to_bits_integer
|
1510
|
+
@fptype.to_bits_integer @value
|
1511
|
+
end
|
1512
|
+
def to_bits_text(base)
|
1513
|
+
@fptype.to_bits_text @value, base
|
1514
|
+
end
|
1515
|
+
|
1516
|
+
def convert_to(fptype2)
|
1517
|
+
self.class.new fptype2, fptype2.from_fmt(to_fmt)
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
def next
|
1521
|
+
self.class.new(@fptype, @fptype.next_float(@value))
|
1522
|
+
end
|
1523
|
+
def prev
|
1524
|
+
self.class.new(@fptype, @fptype.prev_float(@value))
|
1525
|
+
end
|
1526
|
+
|
1527
|
+
def fp_format
|
1528
|
+
@fptype
|
1529
|
+
end
|
1530
|
+
def bytes
|
1531
|
+
@value
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
def ==(obj); test_equal(obj); end
|
1535
|
+
def eql?(obj); test_equal(obj); end
|
1536
|
+
def ===(obj); test_equal(obj); end
|
1537
|
+
|
1538
|
+
private
|
1539
|
+
def test_equal(v)
|
1540
|
+
@fptype==v.fp_format && @value==v.bytes
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
|
1547
|
+
|
1548
|
+
|
1549
|
+
end
|
1550
|
+
|