float-formats 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,273 +1,145 @@
1
- #Float-Formats -- Native Ruby Float support tools
2
- #
3
- # Float::RADIX : b = Radix of exponent representation,2
4
- #
5
- # Float::MANT_DIG : p = bits (base-RADIX digits) in the significand
6
- #
7
- #
8
- # Float::DIG : q = Number of decimal digits such that any floating-point number with q
9
- # decimal digits can be rounded into a floating-point number with p radix b
10
- # digits and back again without change to the q decimal digits,
11
- # q = p * log10(b) if b is a power of 10
12
- # q = floor((p - 1) * log10(b)) otherwise
13
- #
14
- # Float::MIN_EXP : emin = Minimum int x such that Float::RADIX**(x-1) is a normalized float
15
- #
16
- # Float::MIN_10_EXP : Minimum negative integer such that 10 raised to that power is in the
17
- # range of normalized floating-point numbers,
18
- # ceil(log10(b) * (emin - 1))
19
- #
20
- # Float::MAX_EXP : emax = Maximum int x such that Float::RADIX**(x-1) is a representable float
21
- #
22
- # Float::MAX_10_EXP : Maximum integer such that 10 raised to that power is in the range of
23
- # representable finite floating-point numbers,
24
- # floor(log10((1 - b**-p) * b**emax))
25
- #
26
- # Float::MAX : Maximum representable finite floating-point number
27
- # (1 - b**-p) * b**emax
28
- #
29
- # Float::EPSILON : The difference between 1 and the least value greater than 1 that is
30
- # representable in the given floating point type
31
- # b**(1-p)
32
- #
33
- # Float::MIN : Minimum normalized positive floating-point number
34
- # b**(emin - 1).
35
- #
36
- # Float::ROUNDS : Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown.
37
- #
38
- # defined by Nio:
39
- # Float::DECIMAL_DIG : Number of decimal digits, n, such that any floating-point number can be rounded
40
- # to a floating-point number with n decimal digits and back again without
41
- # change to the value,
42
- # pmax * log10(b) if b is a power of 10
43
- # ceil(1 + pmax * log10(b)) otherwise
44
- #
45
- # Note that this uses the "fractional significand" interpretation
46
-
47
- require 'nio'
48
- require 'nio/sugar'
49
-
50
- require 'float-formats/bytes.rb'
51
-
52
- class Float
53
- # Compute the adjacent floating point values: largest value not larger that
54
- # this and smallest not smaller.
55
- def neighbours
56
- f,e = Math.frexp(self)
57
- e = Float::MIN_EXP if f==0
58
- e = [Float::MIN_EXP,e].max
59
- dx = Math.ldexp(1,e-Float::MANT_DIG) #Math.ldexp(Math.ldexp(1.0,-Float::MANT_DIG),e)
60
-
61
- min_f = 0.5 #0.5==Math.ldexp(2**(bits-1),-Float::MANT_DIG)
62
- max_f = 1.0 - Math.ldexp(1,-Float::MANT_DIG)
63
-
64
- if f==max_f
65
- high = self + dx*2
66
- elsif f==-min_f && e!=Float::MIN_EXP
67
- high = self + dx/2
68
- else
69
- high = self + dx
70
- end
71
- if e==Float::MIN_EXP || f!=min_f
72
- low = self - dx
73
- elsif f==-max_f
74
- high = self - dx*2
75
- else
76
- low = self - dx/2
77
- end
78
- [low, high]
79
- end
80
-
81
- # Previous floating point value
82
- def prev
83
- neighbours[0]
84
- end
85
-
86
- # Next floating point value; e.g. 1.0.next == 1.0+Float::EPSILON
87
- def next
88
- neighbours[1]
89
- end
90
-
91
- # Minimum normalized number == MAX_D.next
92
- MIN_N = Math.ldexp(0.5,Float::MIN_EXP) # == nxt(MAX_D) == Float::MIN
93
-
94
- # Maximum denormal number == MIN_N.prev
95
- MAX_D = Math.ldexp(Math.ldexp(1,Float::MANT_DIG-1)-1,Float::MIN_EXP-Float::MANT_DIG)
96
-
97
- # Minimum non zero positive denormal number == 0.0.next
98
- MIN_D = Math.ldexp(1,Float::MIN_EXP-Float::MANT_DIG);
99
-
100
- # Maximum significand == Math.ldexp(Math.ldexp(1,Float::MANT_DIG)-1,-Float::MANT_DIG)
101
- MAX_F = Math.frexp(Float::MAX)[0] == Math.ldexp(Math.ldexp(1,Float::MANT_DIG)-1,-Float::MANT_DIG)
102
-
103
- # ulp (unit in the last place) according to the definition proposed by J.M. Muller in
104
- # "On the definition of ulp(x)" INRIA No. 5504
105
- def ulp
106
- return self if nan?
107
- x = abs
108
- if x < Math.ldexp(1,MIN_EXP) # x < RADIX*MIN_N
109
- res = Math.ldexp(1,MIN_EXP-MANT_DIG) # res = MIN_D
110
- elsif x > Math.ldexp(1-Math.ldexp(1,-MANT_DIG),MAX_EXP) # x > MAX
111
- res = Math.ldexp(1,MAX_EXP-MANT_DIG) # res = MAX - MAX.prev
112
- else
113
- f,e = Math.frexp(x)
114
- if f==Math.ldexp(1,-1)
115
- res = Math.ldexp(1,e-MANT_DIG-1)
116
- else
117
- res = Math.ldexp(1,e-MANT_DIG)
118
- end
119
- end
120
- res
121
- end
122
-
123
-
124
- end
125
-
126
-
127
- module FltPnt
128
-
129
- module_function
130
-
131
- # shortest decimal unambiguous reprentation
132
- def float_shortest_dec(x)
133
- x.nio_write(Nio::Fmt.prec(:exact))
134
- end
135
-
136
- # decimal representation showing all significant digits
137
- def float_significant_dec(x)
138
- x.nio_write(Nio::Fmt.prec(:exact).show_all_digits(true))
139
- end
140
-
141
- # complete exact decimal representation
142
- def float_dec(x)
143
- x.nio_write(Nio::Fmt.prec(:exact).approx_mode(:exact))
144
- end
145
-
146
- # binary representation
147
- def float_bin(x)
148
- x.nio_write(Nio::Fmt.mode(:sci,:exact).base(2))
149
- end
150
-
151
- # decompose a float into a signed integer significand and exponent (base Float::RADIX)
152
- def float_to_integral_significand_exponent(x)
153
- s,e = Math.frexp(x)
154
- [Math.ldexp(s,Float::MANT_DIG).to_i,e-Float::MANT_DIG]
155
- end
156
-
157
- # compose float from significand and exponent
158
- def float_from_integral_significand_exponent(s,e)
159
- Math.ldexp(s,e)
160
- end
161
-
162
- def float_to_integral_sign_significand_exponent(x)
163
- if x==0.0
164
- sign = (1/x<0) ? -1 : +1
165
- else
166
- sign = x<0 ? -1 : +1
167
- end
168
- x = -x if sign<0
169
- s,e = Math.frexp(x)
170
- [sign,Math.ldexp(s,Float::MANT_DIG).to_i,e-Float::MANT_DIG]
171
- end
172
-
173
- def float_from_integral_sign_significand_exponent(sgn,s,e)
174
- f = Math.ldexp(s,e)
175
- f = -f if sgn<0
176
- f
177
- end
178
-
179
- # convert a float to C99's hexadecimal notation
180
- def hex_from_float(v)
181
- if Float::RADIX==2
182
- sgn,s,e = float_to_integral_sign_significand_exponent(v)
183
- else
184
- txt = v.nio_write(Fmt.base(2).sep('.')).upcase
185
- p = txt.index('E')
186
- exp = 0
187
- if p
188
- exp = rep[p+1..-1].to_i
189
- txt = rep[0...p]
190
- end
191
- p = txt.index('.')
192
- if p
193
- exp -= (txt.size-p-1)
194
- txt.tr!('.','')
195
- end
196
- s = txt.to_i(2)
197
- e = exp
198
- end
199
- "0x#{sgn<0 ? '-' : ''}#{s.to_s(16)}p#{e}"
200
- end
201
-
202
- # convert a string formatted in C99's hexadecimal notation to a float
203
- def hex_to_float(txt)
204
- txt = txt.strip.upcase
205
- txt = txt[2..-1] if txt[0,2]=='0X'
206
- p = txt.index('P')
207
- if p
208
- exp = txt[p+1..-1].to_i
209
- txt = txt[0...p]
210
- else
211
- exp = 0
212
- end
213
- p = txt.index('.')
214
- if p
215
- exp -= (txt.size-p-1)*4
216
- txt.tr!('.','')
217
- end
218
- if Float::RADIX==2
219
- v = txt.to_i(16)
220
- if v==0 && txt.include?('-')
221
- sign = -1
222
- elsif v<0
223
- sign = -1
224
- v = -v
225
- else
226
- sign = +1
227
- end
228
- float_from_integral_sign_significand_exponent(sign,v,exp)
229
- else
230
- (txt.to_i(16)*(2**exp)).to_f
231
- end
232
- end
233
-
234
- # ===== IEEE types =====================================================================================
235
-
236
- # generate a SGL value stored in a byte string given a decimal value formatted as text
237
- def sgl_from_text(txt, little_endian=true)
238
- code = little_endian ? 'e':'g'
239
- [txt].pack(code)
240
- end
241
-
242
- # generate a SGL value stored in a byte string given a Float value
243
- def sgl_from_float(val, little_endian=true)
244
- code = little_endian ? 'e':'g'
245
- [val].pack(code)
246
- end
247
-
248
- # convert a SGL value stored in a byte string to a Float value
249
- def sgl_to_float(sgl, littel_endian=true)
250
- code = little_endian ? 'e':'g'
251
- sgl.unpack(code)[0]
252
- end
253
-
254
-
255
- # generate a DBL value stored in a byte string given a decimal value formatted as text
256
- def dbl_from_text(txt, little_endian=true)
257
- code = little_endian ? 'E':'G'
258
- [txt].pack(code)
259
- end
260
-
261
- # generate a DBL value stored in a byte string given a Float value
262
- def dbl_from_float(val, little_endian=true)
263
- code = little_endian ? 'E':'G'
264
- [val].pack(code)
265
- end
266
-
267
- # convert a DBL value stored in a byte string to a Float value
268
- def dbl_to_float(sgl, little_endian=true)
269
- code = little_endian ? 'E':'G'
270
- sgl.unpack(code)[0]
271
- end
272
-
1
+ #Float-Formats -- Native Ruby Float support tools
2
+
3
+ require 'nio'
4
+ require 'nio/sugar'
5
+ require 'flt'
6
+ require 'flt/float'
7
+ require 'float-formats/bytes'
8
+
9
+ module Flt
10
+
11
+ module_function
12
+
13
+ # shortest decimal unambiguous reprentation
14
+ def float_shortest_dec(x)
15
+ x.nio_write(Nio::Fmt.prec(:exact))
16
+ end
17
+
18
+ # decimal representation showing all significant digits
19
+ def float_significant_dec(x)
20
+ x.nio_write(Nio::Fmt.prec(:exact).show_all_digits(true))
21
+ end
22
+
23
+ # complete exact decimal representation
24
+ def float_dec(x)
25
+ x.nio_write(Nio::Fmt.prec(:exact).approx_mode(:exact))
26
+ end
27
+
28
+ # binary representation
29
+ def float_bin(x)
30
+ x.nio_write(Nio::Fmt.mode(:sci,:exact).base(2))
31
+ end
32
+
33
+ # decompose a float into a signed integer significand and exponent (base Float::RADIX)
34
+ def float_to_integral_significand_exponent(x)
35
+ Float.context.to_int_scale(x)
36
+ end
37
+
38
+ # compose float from significand and exponent
39
+ def float_from_integral_significand_exponent(s,e)
40
+ Float.context.Num(s,e)
41
+ end
42
+
43
+ def float_to_integral_sign_significand_exponent(x)
44
+ Float.context.split(x)
45
+ end
46
+
47
+ def float_from_integral_sign_significand_exponent(sgn,s,e)
48
+ Float.context.Num(sgn,s,e)
49
+ end
50
+
51
+ # convert a float to C99's hexadecimal notation
52
+ def hex_from_float(v)
53
+ if Float::RADIX==2
54
+ sgn,s,e = float_to_integral_sign_significand_exponent(v)
55
+ else
56
+ txt = v.nio_write(Fmt.base(2).sep('.')).upcase
57
+ p = txt.index('E')
58
+ exp = 0
59
+ if p
60
+ exp = rep[p+1..-1].to_i
61
+ txt = rep[0...p]
62
+ end
63
+ p = txt.index('.')
64
+ if p
65
+ exp -= (txt.size-p-1)
66
+ txt.tr!('.','')
67
+ end
68
+ s = txt.to_i(2)
69
+ e = exp
70
+ end
71
+ "0x#{sgn<0 ? '-' : ''}#{s.to_s(16)}p#{e}"
72
+ end
73
+
74
+ # convert a string formatted in C99's hexadecimal notation to a float
75
+ def hex_to_float(txt)
76
+ txt = txt.strip.upcase
77
+ txt = txt[2..-1] if txt[0,2]=='0X'
78
+ p = txt.index('P')
79
+ if p
80
+ exp = txt[p+1..-1].to_i
81
+ txt = txt[0...p]
82
+ else
83
+ exp = 0
84
+ end
85
+ p = txt.index('.')
86
+ if p
87
+ exp -= (txt.size-p-1)*4
88
+ txt.tr!('.','')
89
+ end
90
+ if Float::RADIX==2
91
+ v = txt.to_i(16)
92
+ if v==0 && txt.include?('-')
93
+ sign = -1
94
+ elsif v<0
95
+ sign = -1
96
+ v = -v
97
+ else
98
+ sign = +1
99
+ end
100
+ float_from_integral_sign_significand_exponent(sign,v,exp)
101
+ else
102
+ (txt.to_i(16)*(2**exp)).to_f
103
+ end
104
+ end
105
+
106
+ # ===== IEEE types =====================================================================================
107
+
108
+ # generate a SGL value stored in a byte string given a decimal value formatted as text
109
+ def sgl_from_text(txt, little_endian=true)
110
+ code = little_endian ? 'e':'g'
111
+ [txt].pack(code)
112
+ end
113
+
114
+ # generate a SGL value stored in a byte string given a Float value
115
+ def sgl_from_float(val, little_endian=true)
116
+ code = little_endian ? 'e':'g'
117
+ [val].pack(code)
118
+ end
119
+
120
+ # convert a SGL value stored in a byte string to a Float value
121
+ def sgl_to_float(sgl, littel_endian=true)
122
+ code = little_endian ? 'e':'g'
123
+ sgl.unpack(code)[0]
124
+ end
125
+
126
+
127
+ # generate a DBL value stored in a byte string given a decimal value formatted as text
128
+ def dbl_from_text(txt, little_endian=true)
129
+ code = little_endian ? 'E':'G'
130
+ [txt].pack(code)
131
+ end
132
+
133
+ # generate a DBL value stored in a byte string given a Float value
134
+ def dbl_from_float(val, little_endian=true)
135
+ code = little_endian ? 'E':'G'
136
+ [val].pack(code)
137
+ end
138
+
139
+ # convert a DBL value stored in a byte string to a Float value
140
+ def dbl_to_float(sgl, little_endian=true)
141
+ code = little_endian ? 'E':'G'
142
+ sgl.unpack(code)[0]
143
+ end
144
+
273
145
  end
@@ -1,8 +1,8 @@
1
- module FltPnt
2
- module VERSION #:nodoc:
1
+ module Flt
2
+ module FORMATS_VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
5
- TINY = 1
4
+ MINOR = 2
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/tasks/ann.rake ADDED
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF