float-formats 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a2762f17e4a4d466ccfd26ecfa5e4bfc5f72a4de
4
- data.tar.gz: 725f2276a8d2352a480738f6b80347afdee5429e
3
+ metadata.gz: e5c6ebefc05d57a1271453eb0ba460e7f6fa9e9d
4
+ data.tar.gz: 0bb606a66d28fa34cdf03984c72acf0ecdbb4ce3
5
5
  SHA512:
6
- metadata.gz: 934167b2462593a9dc91a848b01eabdee00043f63fb92aefa4d265c635aa07efd2b67e53b2d1fc5b7f5efb7365ca079f1d93731acd5d01cadf9de4b5c4973b35
7
- data.tar.gz: 811b80dd4a9fb97cf88913a0f480087e71dc4d4ff6bb9a4b6ee032cf5bf56219495fe7249b185caad9af54e4cf1241cfa41ba369364678ba7072643892d36501
6
+ metadata.gz: dd8490cef4b2aacb6bb06b7fb5e349acf954055499f2bc52000c126a4095163dca2be630d7f27b60b5426e4e43772d1eae6f099423eead7ecf8b257afc59b23e
7
+ data.tar.gz: 62ce956a3757fb4719e7cf0572ff4698af641275396ba6b5a5f2d95db641e90e35148adc7499dbe0b8bccd157a682585075efab7a561cf708a4c1e9c9b6c3b7e
@@ -1,3 +1,8 @@
1
+ == 0.3.0 2015-04-05
2
+
3
+ * Nio dependency replaced by Numerals
4
+ * Ruby 1.8 compatibility dropped
5
+
1
6
  == 0.2.1 2015-03-31
2
7
 
3
8
  * Compatibility issues with Ruby 1.9/2
data/README.md CHANGED
@@ -210,9 +210,9 @@ the first bit, which will be hidden:
210
210
 
211
211
  Flt.define(
212
212
  :MY_FP, BinaryFormat,
213
- :fields=>[:significand,22,:exponent,9,:sign,1],
214
- :bias=>127, :bias_mode=>:scientific_significand,
215
- :hidden_bit=>true
213
+ fields: [:significand,22,:exponent,9,:sign,1],
214
+ bias: 127, bias_mode: :scientific_significand,
215
+ hidden_bit: true
216
216
  )
217
217
 
218
218
  Now we can encode values in this format, decode values, convet to other
@@ -18,9 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency 'flt', ">= 1.1.2"
22
- spec.add_dependency 'nio', ">= 0.2.4"
21
+ spec.add_dependency 'flt', ">= 1.4.7"
22
+ spec.add_dependency 'numerals', ">= 0.3.0"
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.6"
25
25
  spec.add_development_dependency "rake"
26
+ spec.add_development_dependency 'nio', ">= 0.2.4"
27
+
28
+ spec.required_ruby_version = '>= 1.9.3'
26
29
  end
@@ -1,7 +1,6 @@
1
1
  # Float-Formats
2
2
  # Support for binary data representations
3
- require 'nio'
4
- require 'nio/sugar'
3
+ require 'numerals'
5
4
 
6
5
  require 'enumerator'
7
6
  require 'delegate'
@@ -10,8 +9,8 @@ module Flt
10
9
 
11
10
  class Bits
12
11
  # Define a bit string given the number of bits and
13
- # optinally the initial value (as an integer).
14
- def initialize(num_bits,v=0)
12
+ # optionally the initial value (as an integer).
13
+ def initialize(num_bits, v=0)
15
14
  @n = num_bits
16
15
  @v = v
17
16
  end
@@ -20,10 +19,9 @@ class Bits
20
19
  def to_s(base=2)
21
20
  n = Bits.power_of_two(base)
22
21
  if n
23
- fmt = Nio::Fmt.default.base(base,true).mode(:fix,:exact)
24
22
  digits = (size+n-1)/n
25
- fmt.pad0s!(digits)
26
- @v.nio_write(fmt)
23
+ #{ }"%0#{digits}d" % @v.to_s(base)
24
+ Numerals::Format[:fix, base: base].set_leading_zeros(digits).write(@v)
27
25
  else
28
26
  @v.to_s(base)
29
27
  end
@@ -48,7 +46,7 @@ class Bits
48
46
  end
49
47
 
50
48
  # produce bit string from an integer
51
- def self.from_i(v,len=nil)
49
+ def self.from_i(v, len=nil)
52
50
  len ||= (Math.log(v)/Math.log(2)).ceil # v.to_s(2).size
53
51
  Bits.new(len,v)
54
52
  end
@@ -112,9 +110,8 @@ class Bytes < DelegateClass(String)
112
110
  @bytes = bytes.pack("C*")
113
111
  else
114
112
  @bytes = bytes.to_str
115
- @bytes.force_encoding("BINARY") if @bytes.respond_to?(:force_encoding)
116
113
  end
117
- @bytes.force_encoding(Encoding::BINARY) if RUBY_VERSION>="1.9.0"
114
+ @bytes.force_encoding("BINARY") if @bytes.respond_to?(:force_encoding)
118
115
  super @bytes
119
116
  end
120
117
 
@@ -35,9 +35,8 @@
35
35
  # * minimum encoded exponent reserved for zero (nonzero significands are not used with it)
36
36
  # * special all zeros representation: minimun encoded exponent is a regular exponent except for 0
37
37
 
38
- require 'nio'
39
- require 'nio/sugar'
40
38
  require 'flt'
39
+ require 'numerals'
41
40
  require 'enumerator'
42
41
  require 'float-formats/bytes.rb'
43
42
 
@@ -91,59 +90,46 @@ class FormatBase
91
90
  @sign,@significand,@exponent = v.to_a
92
91
  end
93
92
  end
93
+
94
94
  attr_reader :sign, :significand, :exponent
95
+
95
96
  def to_a
96
97
  split
97
98
  end
99
+
98
100
  def split
99
101
  return [@sign,@significand,@exponent]
100
102
  end
101
103
 
102
-
103
104
  def nan?
104
105
  @exponent == :nan
105
106
  end
107
+
106
108
  def zero?
107
109
  return @exponent==:zero || @significand==0
108
110
  end
111
+
109
112
  def infinite?
110
113
  return @exponent==:infinity
111
114
  end
115
+
112
116
  def subnormal?
113
117
  return @exponent==:denormal || (@significand.kind_of?(Integer) && @significand<self.class.minimum_normalized_integral_significand)
114
118
  end
119
+
115
120
  def normal?
116
121
  @exponend.kind_of?(Integer) && @significand>=self.class.minimum_normalized_integral_significand
117
122
  end
118
123
 
119
- include Nio::Formattable
120
-
121
124
  # from/to integral_sign_significand_exponent
122
125
 
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
126
+ def to_text(fmt = Numerals::Format[])
127
+ if infinite?
128
+ fmt = fmt[symbols: [show_plus: true]]
141
129
  end
142
- v.nio_write_neutral(fmt)
143
- end
144
- def to_text(fmt=Nio::Fmt.default)
145
- nio_write(fmt)
130
+ fmt.write(self)
146
131
  end
132
+
147
133
  def to_bytes
148
134
  form_class.pack(@sign,@significand,@exponent)
149
135
  end
@@ -154,24 +140,29 @@ class FormatBase
154
140
  to_bits.to_hex
155
141
  end
156
142
  end
157
- def to(number_class, mode=:approx)
158
- if number_class==Bytes
143
+ def to(number_class, mode = :approx)
144
+ if number_class == Bytes
159
145
  to_bytes
160
- elsif number_class==String
161
- mode = Nio::Fmt.default if mode==:approx
146
+ elsif number_class == String
147
+ mode = Numerals::Format[] if mode == :approx
162
148
  to_text(mode)
163
- elsif Nio::Fmt===number_class
149
+ elsif Numerals::Format === number_class
164
150
  to_text(number_class)
165
- elsif number_class==Array
151
+ elsif number_class == Array
166
152
  split
167
- elsif Symbol===number_class
153
+ elsif Symbol === number_class
168
154
  send "to_#{number_class}"
169
155
  elsif number_class.is_a?(Flt::Num) && number_class.radix == form_class.radix
170
156
  self.to_num
157
+ elsif number_class.is_a?(FormatBase)
158
+ number_class.from_number(self, mode)
171
159
  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)
160
+ options = {
161
+ type: number_class,
162
+ exact_input: (mode != :approx),
163
+ output_mode: :fixed
164
+ }
165
+ Numerals::Conversions.convert(self, options)
175
166
  end
176
167
  end
177
168
  def to_bits
@@ -183,13 +174,13 @@ class FormatBase
183
174
  def to_bits_text(base)
184
175
  to_bits.to_s(base)
185
176
  #i = to_bits
186
- #fmt = Nio::Fmt.default.base(base,true).mode(:fix,:exact)
177
+ #fmt = Numerals::Format[base: base]
187
178
  #if [2,4,8,16].include?(base)
188
179
  # n = (Math.log(base)/Math.log(2)).round.to_i
189
180
  # digits = (form_class.total_bits+n-1)/n
190
- # fmt.pad0s!(digits)
181
+ # fmt.set_trailing_zeros!(digits)
191
182
  #end
192
- #i.to_i.nio_write(fmt)
183
+ #fmt.writ(i.to_i)
193
184
  end
194
185
 
195
186
  # Computes the negation of a floating point value (unary minus)
@@ -198,11 +189,10 @@ class FormatBase
198
189
  end
199
190
 
200
191
  # Converts a floating point value to another format
201
- def convert_to(fpclass)
202
- fpclass.nio_read(nio_write)
192
+ def convert_to(fpclass, options = {})
193
+ Numerals::Conversions.convert(self, options.merge(type: fpclass))
203
194
  end
204
195
 
205
-
206
196
  # Computes the next adjacent floating point value.
207
197
  # Accepts either a Value or a byte String.
208
198
  # Returns a Value.
@@ -384,7 +374,7 @@ class FormatBase
384
374
  # originally, we incremented min_encoded_exp here unconditionally, but
385
375
  # now we don't if there's no hidden bit
386
376
  # (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
377
+ # because of this, IEEE_EXTENDED & 128 formats now specify min_encoded_exp: 1 in it's definitions
388
378
  @min_encoded_exp += 1 if @hidden_bit
389
379
  end
390
380
  end
@@ -580,23 +570,60 @@ class FormatBase
580
570
  Num[self.radix]
581
571
  end
582
572
 
573
+ def self.numerals_conversion(options = {})
574
+ FltFmtConversion.new(self, options)
575
+ end
576
+
583
577
  def self.context
584
578
  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
579
+ precision: significand_digits,
580
+ emin: radix_min_exp(:scientific_significand),
581
+ emax: radix_max_exp(:scientific_significand),
582
+ rounding:@round || :half_even
589
583
  )
590
584
  end
591
585
 
592
586
  def to_num
593
- s,c,e = split
594
- e = 0 if e == :zero
595
- form_class.num_class.Num(s,c,e)
587
+ s, c, e = split
588
+ case e
589
+ when :zero
590
+ e = 0
591
+ when :infinity
592
+ e = :inf
593
+ when :nan
594
+ e = :nan
595
+ end
596
+ form_class.num_class.Num(s, c, e)
596
597
  end
597
598
 
599
+ # def to_num
600
+ # # num_class = Flt::Num[form_class.radix]
601
+ # num_class = self.class.num_class
602
+ # case @exponent
603
+ # when :zero
604
+ # num_class.zero(@sign)
605
+ # when :infinity
606
+ # num_class.infinity(@sign)
607
+ # when :nan
608
+ # num_class.nan
609
+ # else
610
+ # num_class.new(@sign, @significand, @exponent)
611
+ # end
612
+ # end
613
+
598
614
  def self.num(x)
599
- new(*x.split)
615
+ s, c, e = x.split
616
+ if x.zero?
617
+ e = :zero
618
+ else
619
+ case e
620
+ when :inf
621
+ e = :infinity
622
+ when :nan
623
+ e = :nan
624
+ end
625
+ end
626
+ new([s, c, e])
600
627
  end
601
628
 
602
629
  # Endianness of the format (:little_endian, :big_endian or :little_big_endian)
@@ -792,41 +819,6 @@ class FormatBase
792
819
 
793
820
  # from methods
794
821
 
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
822
  def self.from(*args)
831
823
  new(*args)
832
824
  end
@@ -839,17 +831,27 @@ class FormatBase
839
831
  from_bytes Bytes.from_hex(hex)
840
832
  end
841
833
 
842
- def self.from_number(v, mode=:approx)
834
+ def self.from_number(v, mode = :approx)
843
835
  if v.is_a?(Flt::Num) && v.num_class.radix==self.radix
844
836
  self.num(v)
845
837
  else
846
- fmt = mode==:approx ? Nio::Fmt::CONV_FMT : Nio::Fmt::CONV_FMT_STRICT
847
- nio_read(v.nio_write(fmt),fmt)
838
+ options = {
839
+ type: self,
840
+ exact_input: (mode != :approx),
841
+ output_mode: @normalized ? :fixed : :short
842
+ }
843
+ Numerals::Conversions.convert(v, options)
848
844
  end
849
845
  end
850
846
 
851
- def self.from_text(txt, fmt=Nio::Fmt.default) # ?
852
- nio_read(txt,fmt)
847
+ def self.from_text(txt, *args)
848
+ if @normalized
849
+ fmt = Numerals::Format[exact_input: true]
850
+ else
851
+ fmt = Numerals::Format[:short, exact_input: false]
852
+ end
853
+ fmt = fmt[*args]
854
+ fmt.read(txt, type: self)
853
855
  end
854
856
 
855
857
  def self.join(sign,significand,exponent)
@@ -875,8 +877,8 @@ class FormatBase
875
877
  # Defines a floating-point number from a text representation of the
876
878
  # encoded integral value in a given base.
877
879
  # Returns a Value.
878
- def self.from_bits_text(txt,base)
879
- i = Integer.nio_read(txt,Nio::Fmt.base(base))
880
+ def self.from_bits_text(txt, base)
881
+ i = Numerals::Format[].read(txt, type: Integer, base: base)
880
882
  from_bits i
881
883
  end
882
884
 
@@ -934,6 +936,48 @@ class FormatBase
934
936
  end
935
937
  end
936
938
 
939
+ class FltFmtConversion
940
+
941
+ def initialize(form_class, options={})
942
+ @form_class = form_class
943
+ @input_rounding = options[:input_rounding]
944
+ end
945
+
946
+ def type
947
+ @form_class
948
+ end
949
+
950
+ def order_of_magnitude(value, options={})
951
+ num_conversions.order_of_maginitude(value.to_num, options)
952
+ end
953
+
954
+ def number_of_digits(value, options={})
955
+ num_conversions.number_of_digits(value.to_num, options)
956
+ end
957
+
958
+ def exact?(value, options={})
959
+ options[:exact]
960
+ end
961
+
962
+ def write(number, exact_input, output_rounding)
963
+ # assert_equal @form_class, number.class
964
+ num_conversions.write(number.to_num, exact_input, output_rounding)
965
+ end
966
+
967
+ def read(numeral, exact_input, approximate_simplified)
968
+ num = num_conversions.read(numeral, exact_input, approximate_simplified)
969
+ num = num.normalize(@form_class.context) if exact_input
970
+ @form_class.num(num)
971
+ end
972
+
973
+ private
974
+
975
+ def num_conversions
976
+ Numerals::Conversions[@form_class.context, input_rounding: @input_rounding]
977
+ end
978
+
979
+ end
980
+
937
981
  # :stopdoc:
938
982
  protected
939
983
  def self.define_fields(field_definitions)
@@ -1231,7 +1275,7 @@ class BCDFormat < DecimalFormatBase
1231
1275
  end
1232
1276
  s = sign_from_unit(s)
1233
1277
  m,e = neg_significand_exponent(0,m,e) if s%2==1
1234
- pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1278
+ pack_fields_hash sign: s, significand: m, exponent: e
1235
1279
  end
1236
1280
  # :startdoc:
1237
1281
  end
@@ -1359,7 +1403,7 @@ class DPDFormat < DecimalFormatBase
1359
1403
  i_combination = sig_msd|(1<<4)|(exp_msb<<1)
1360
1404
  end
1361
1405
  end
1362
- h = {:sign=>i_sign, :combination=>i_combination, :exponent_continuation=>i_exponent_continuation, :significand_continuation=>i_significand_continuation}
1406
+ h = {sign: i_sign, combination: i_combination, exponent_continuation: i_exponent_continuation, significand_continuation: i_significand_continuation}
1363
1407
  fields = @internal_field_meaning.collect{|f| h[f]}
1364
1408
  Bytes.from_bitfields(@internal_field_lengths,fields,@endianness)
1365
1409
  end
@@ -1427,7 +1471,7 @@ class DPDFormat < DecimalFormatBase
1427
1471
  end
1428
1472
  s = sign_from_unit(s)
1429
1473
  m,e = neg_significand_exponent(0,m,e) if s%2==1
1430
- pack_fields_hash :sign=>s, :significand=>m, :exponent=>e, :type=>t
1474
+ pack_fields_hash sign: s, significand: m, exponent: e, type: t
1431
1475
  end
1432
1476
 
1433
1477
  # :startdoc:
@@ -1553,7 +1597,7 @@ class BinaryFormat < FieldsInBitsFormatBase
1553
1597
  end
1554
1598
  s = sign_from_unit(s)
1555
1599
  m,e = neg_significand_exponent(0,m,e) if s%2==1
1556
- pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1600
+ pack_fields_hash sign: s, significand: m, exponent: e
1557
1601
  end
1558
1602
  # :startdoc:
1559
1603
 
@@ -1646,7 +1690,7 @@ class HexadecimalFormat < FieldsInBitsFormatBase
1646
1690
  end
1647
1691
  s = sign_from_unit(s)
1648
1692
  m,e = neg_significand_exponent(0,m,e) if s%2==1
1649
- pack_fields_hash :sign=>s, :significand=>m, :exponent=>e
1693
+ pack_fields_hash sign: s, significand: m, exponent: e
1650
1694
  end
1651
1695
 
1652
1696
 
@@ -1741,7 +1785,7 @@ end
1741
1785
  # by adjusting the sign of the second number. This is enabled by the
1742
1786
  # :extra_prec option.
1743
1787
  # For example, the "double double" format used in PowerPC is this
1744
- # Flt.define :DoubleDouble, DoubleFormat, :half=>IEEE_binary64, :extra_prec=>true
1788
+ # Flt.define :DoubleDouble, DoubleFormat, half: IEEE_binary64, extra_prec: true
1745
1789
  # Although this has a fixed 107 bits precision, the format as used in
1746
1790
  # the PowerPC can have greater precision for specific values (by having
1747
1791
  # greater separation between the exponents of both halves)