float-formats 0.2.1 → 0.3.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.
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)