numerals 0.2.0 → 0.2.1

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: 0e87d9faabf0392f12d84d026d85d480aa67d32c
4
- data.tar.gz: 67b89570a8c97ae4abe727c730bdc77099ca70d0
3
+ metadata.gz: c2db2456e26dc108b6ffc0e72616b58c94c00eee
4
+ data.tar.gz: 4150c883baaa50b85c7f9f7619b5bde35ec5ff9e
5
5
  SHA512:
6
- metadata.gz: 3c3b97ef87dcda6dec5dce9a8d8449da8b8da3c5faab0664ab4563dfb32f4770b9295271454c6e9c2efbec2be3b72843cf12c6f2d48395e36c7474b8d6be886c
7
- data.tar.gz: 6ff01ddb162578b80b30596adfd38be3fb992509b8ff7aa32018b98815dae4e2449770313728647e9b8af0110e6a0cd4078edc1f4d01754a91a3205ceb7cd93a
6
+ metadata.gz: 755fe267a26a4091942e522f32e335cc5d17adfcd3d24a671a09d251927d40bdf7a2fc8f508f27272de8b1dd310ac160d7bf256079d7c9b44df34bb542724661
7
+ data.tar.gz: e1d04a258486962b14b0c5c1065d017a20ea09bcb15d551579a55f0db3f0a206ebe7b800ce065ca7e9ca0aff832ecb2a0d357b4390228ed7caa5931b684e4d5c
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  Numerals
2
2
  ========
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/numerals.svg)](http://badge.fury.io/rb/numerals)
5
+ [![Build Status](https://travis-ci.org/jgoizueta/numerals.svg)](https://travis-ci.org/jgoizueta/numerals)
6
+
4
7
  The Numerals module provides formatted input/output for numeric types.
5
8
 
6
9
  ## Use
data/Rakefile CHANGED
@@ -17,3 +17,5 @@ Rake::RDocTask.new do |rdoc|
17
17
  rdoc.rdoc_files.include('README*')
18
18
  rdoc.rdoc_files.include('lib/**/*.rb')
19
19
  end
20
+
21
+ task :default => :test
@@ -11,4 +11,3 @@ require 'numerals/conversions/rational'
11
11
  require 'numerals/conversions/bigdecimal'
12
12
  require 'numerals/conversions/flt'
13
13
  require 'numerals/format'
14
- # require 'numerals/formatting/options'
@@ -1,98 +1,102 @@
1
- module Numerals::Conversions
1
+ module Numerals
2
2
 
3
- class <<self
4
- def [](type, options = nil)
5
- if type.respond_to?(:numerals_conversion)
6
- type.numerals_conversion(options || {})
3
+ module Conversions
4
+
5
+ class <<self
6
+ def [](type, options = nil)
7
+ if type.respond_to?(:numerals_conversion)
8
+ type.numerals_conversion(options || {})
9
+ end
7
10
  end
8
- end
9
11
 
10
- def order_of_magnitude(number, options={})
11
- self[number.class, options[:type_options]].order_of_magnitude(number, options)
12
- end
12
+ def order_of_magnitude(number, options={})
13
+ self[number.class, options[:type_options]].order_of_magnitude(number, options)
14
+ end
13
15
 
14
- def number_of_digits(number, options={})
15
- self[number.class, options[:type_options]].number_of_digits(number, options)
16
- end
16
+ def number_of_digits(number, options={})
17
+ self[number.class, options[:type_options]].number_of_digits(number, options)
18
+ end
17
19
 
18
- # Convert Numeral to Number
19
- #
20
- # read numeral, options={}
21
- #
22
- # If the input numeral is approximate and the destination type
23
- # allows for arbitrary precision, then the destination context
24
- # precision will be ignored and the precision of the input will be
25
- # preserved. The :simplify option affects this case by generating
26
- # only the mininimun number of digits needed.
27
- #
28
- # The :exact option will prevent this behaviour and always treat
29
- # input as exact.
30
- #
31
- # Valid output options:
32
- #
33
- # * :type class of the output number
34
- # * :context context (in the case of Flt::Num, Float) for the output
35
- # * :simplify (for approximate input numeral/arbitrary precision type only)
36
- # * :exact treat input numeral as if exact
37
- #
38
- def read(numeral, options={})
39
- selector = options[:context] || options[:type]
40
- exact_input = options[:exact]
41
- approximate_simplified = options[:simplify]
42
- conversions = self[selector, options[:type_options]]
43
- conversions.read(numeral, exact_input, approximate_simplified)
44
- end
20
+ # Convert Numeral to Number
21
+ #
22
+ # read numeral, options={}
23
+ #
24
+ # If the input numeral is approximate and the destination type
25
+ # allows for arbitrary precision, then the destination context
26
+ # precision will be ignored and the precision of the input will be
27
+ # preserved. The :simplify option affects this case by generating
28
+ # only the mininimun number of digits needed.
29
+ #
30
+ # The :exact option will prevent this behaviour and always treat
31
+ # input as exact.
32
+ #
33
+ # Valid output options:
34
+ #
35
+ # * :type class of the output number
36
+ # * :context context (in the case of Flt::Num, Float) for the output
37
+ # * :simplify (for approximate input numeral/arbitrary precision type only)
38
+ # * :exact treat input numeral as if exact
39
+ #
40
+ def read(numeral, options={})
41
+ selector = options[:context] || options[:type]
42
+ exact_input = options[:exact]
43
+ approximate_simplified = options[:simplify]
44
+ conversions = self[selector, options[:type_options]]
45
+ conversions.read(numeral, exact_input, approximate_simplified)
46
+ end
45
47
 
46
- # Convert Number to Numeral
47
- #
48
- # write number, options={}
49
- #
50
- # Valid options:
51
- #
52
- # * :rounding (a Rounding) (which defines output base as well)
53
- # * :exact (exact input indicator)
54
- #
55
- # Approximate mode:
56
- #
57
- # If the input is treated as an approximation
58
- # (which is the case for types such as Flt::Num, Float,...
59
- # unless the :exact option is true) then no 'spurious' digits
60
- # will be shown (digits that can take any value and the numeral
61
- # still would convert to the original number if rounded to the same precision)
62
- #
63
- # In approximate mode, if rounding is simplifying? (:short), the shortest representation
64
- # which rounds back to the origina number with the same precision is used.
65
- # If rounding is :free and the output base is the same as the number
66
- # internal radix, the exact precision (trailing zeros) of the number
67
- # is represented.
68
- #
69
- # Exact mode:
70
- #
71
- # Is used for 'exact' types (such as Integer, Rational) or when the :exact
72
- # option is defined to be true.
73
- #
74
- # The number is treated as an exact value, and converted according to
75
- # Rounding. (in this case the :free and :short precision roundings are
76
- # equivalent)
77
- #
78
- def write(number, options = {})
79
- output_rounding = Rounding[options[:rounding] || Rounding[]]
80
- conversion = self[number.class, options[:type_options]]
81
- exact_input = conversion.exact?(number, options)
82
- conversion.write(number, exact_input, output_rounding)
83
- end
48
+ # Convert Number to Numeral
49
+ #
50
+ # write number, options={}
51
+ #
52
+ # Valid options:
53
+ #
54
+ # * :rounding (a Rounding) (which defines output base as well)
55
+ # * :exact (exact input indicator)
56
+ #
57
+ # Approximate mode:
58
+ #
59
+ # If the input is treated as an approximation
60
+ # (which is the case for types such as Flt::Num, Float,...
61
+ # unless the :exact option is true) then no 'spurious' digits
62
+ # will be shown (digits that can take any value and the numeral
63
+ # still would convert to the original number if rounded to the same precision)
64
+ #
65
+ # In approximate mode, if rounding is simplifying? (:short), the shortest representation
66
+ # which rounds back to the origina number with the same precision is used.
67
+ # If rounding is :free and the output base is the same as the number
68
+ # internal radix, the exact precision (trailing zeros) of the number
69
+ # is represented.
70
+ #
71
+ # Exact mode:
72
+ #
73
+ # Is used for 'exact' types (such as Integer, Rational) or when the :exact
74
+ # option is defined to be true.
75
+ #
76
+ # The number is treated as an exact value, and converted according to
77
+ # Rounding. (in this case the :free and :short precision roundings are
78
+ # equivalent)
79
+ #
80
+ def write(number, options = {})
81
+ output_rounding = Rounding[options[:rounding] || Rounding[]]
82
+ conversion = self[number.class, options[:type_options]]
83
+ exact_input = conversion.exact?(number, options)
84
+ conversion.write(number, exact_input, output_rounding)
85
+ end
84
86
 
85
- def exact?(number, options = {})
86
- self[number.class, options[:type_options]].exact?(number, options)
87
- end
87
+ def exact?(number, options = {})
88
+ self[number.class, options[:type_options]].exact?(number, options)
89
+ end
88
90
 
89
- private
91
+ private
90
92
 
91
- def extract_mode_from_args!(args)
92
- if [:fixed, :free, :exact, :approximate].include?(args.first)
93
- args.shift
93
+ def extract_mode_from_args!(args)
94
+ if [:fixed, :free, :exact, :approximate].include?(args.first)
95
+ args.shift
96
+ end
94
97
  end
95
98
  end
99
+
96
100
  end
97
101
 
98
102
  end
@@ -1,40 +1,44 @@
1
1
  require 'numerals/conversions'
2
2
  require 'flt'
3
3
 
4
- # Base class for Conversions of type with context
5
- class Numerals::ContextConversion
4
+ module Numerals
6
5
 
7
- def initialize(context_or_type, options={})
8
- if Class === context_or_type && context_or_type.respond_to?(:context)
9
- @type = context_or_type
10
- @context = @type.context
11
- elsif context_or_type.respond_to?(:num_class)
12
- @context = context_or_type
13
- @type = @context.num_class
14
- else
15
- raise "Invalid Conversion definition"
6
+ # Base class for Conversions of type with context
7
+ class ContextConversion
8
+
9
+ def initialize(context_or_type, options={})
10
+ if Class === context_or_type && context_or_type.respond_to?(:context)
11
+ @type = context_or_type
12
+ @context = @type.context
13
+ elsif context_or_type.respond_to?(:num_class)
14
+ @context = context_or_type
15
+ @type = @context.num_class
16
+ else
17
+ raise "Invalid Conversion definition"
18
+ end
19
+ self.input_rounding = options[:input_rounding]
16
20
  end
17
- self.input_rounding = options[:input_rounding]
18
- end
19
21
 
20
- attr_reader :context, :type, :input_rounding
22
+ attr_reader :context, :type, :input_rounding
21
23
 
22
- def input_rounding=(rounding)
23
- if rounding
24
- if rounding == :context
25
- @input_rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix]
26
- else
27
- rounding = Rounding[base: @context.radix].set!(rounding)
28
- if rounding.base == @context.radix
29
- @input_rounding = rounding
24
+ def input_rounding=(rounding)
25
+ if rounding
26
+ if rounding == :context
27
+ @input_rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix]
30
28
  else
31
- # The rounding precision is not meaningful for the destination type on input
32
- @input_rounding = Rounding[rounding.mode, base: @context.radix]
29
+ rounding = Rounding[base: @context.radix].set!(rounding)
30
+ if rounding.base == @context.radix
31
+ @input_rounding = rounding
32
+ else
33
+ # The rounding precision is not meaningful for the destination type on input
34
+ @input_rounding = Rounding[rounding.mode, base: @context.radix]
35
+ end
33
36
  end
37
+ else
38
+ @input_rounding = nil
34
39
  end
35
- else
36
- @input_rounding = nil
37
40
  end
41
+
38
42
  end
39
43
 
40
44
  end
@@ -1,233 +1,237 @@
1
1
  require 'numerals/conversions/context_conversion'
2
2
 
3
- class Numerals::FltConversion < Numerals::ContextConversion
4
-
5
- # Options:
6
- #
7
- # * :input_rounding (optional, a non-exact Rounding or rounding mode)
8
- # which is used when input is approximate as the assumed rounding
9
- # mode which would be used so that the result numeral rounds back
10
- # to the input number. :context can be used to use the
11
- # numeric context as input rounding.
12
- # input_rounding is also used to round input ...
13
- #
14
- def initialize(context_or_type, options={})
15
- super
16
- end
17
-
18
- def order_of_magnitude(value, options={})
19
- base = options[:base] || 10 # value.num_class.radix
20
- if value.class.radix == base
21
- value.adjusted_exponent + 1
22
- else
23
- value.abs.log(base).floor + 1
3
+ module Numerals
4
+
5
+ class FltConversion < ContextConversion
6
+
7
+ # Options:
8
+ #
9
+ # * :input_rounding (optional, a non-exact Rounding or rounding mode)
10
+ # which is used when input is approximate as the assumed rounding
11
+ # mode which would be used so that the result numeral rounds back
12
+ # to the input number. :context can be used to use the
13
+ # numeric context as input rounding.
14
+ # input_rounding is also used to round input ...
15
+ #
16
+ def initialize(context_or_type, options={})
17
+ super
24
18
  end
25
- end
26
19
 
27
- def number_of_digits(value, options={})
28
- base = options[:base] || 10
29
- if base == @context.radix
30
- value.number_of_digits
31
- else
32
- x.class.context[precision: value.number_of_digits].necessary_digits(base)
20
+ def order_of_magnitude(value, options={})
21
+ base = options[:base] || 10 # value.num_class.radix
22
+ if value.class.radix == base
23
+ value.adjusted_exponent + 1
24
+ else
25
+ value.abs.log(base).floor + 1
26
+ end
33
27
  end
34
- end
35
-
36
- def exact?(value, options={})
37
- options[:exact]
38
- end
39
28
 
40
- # mode is either :exact or :approximate
41
- def number_to_numeral(number, mode, rounding)
42
- if number.special? # @context.special?(number)
43
- special_num_to_numeral(number)
44
- else
45
- if mode == :exact
46
- exact_num_to_numeral number, rounding
47
- else # mode == :approximate
48
- approximate_num_to_numeral(number, rounding)
29
+ def number_of_digits(value, options={})
30
+ base = options[:base] || 10
31
+ if base == @context.radix
32
+ value.number_of_digits
33
+ else
34
+ x.class.context[precision: value.number_of_digits].necessary_digits(base)
49
35
  end
50
36
  end
51
- end
52
37
 
53
- def numeral_to_number(numeral, mode)
54
- if numeral.special?
55
- special_numeral_to_num numeral
56
- elsif mode == :fixed
57
- fixed_numeral_to_num numeral
58
- else # mode == :free
59
- free_numeral_to_num numeral
38
+ def exact?(value, options={})
39
+ options[:exact]
60
40
  end
61
- end
62
-
63
- def write(number, exact_input, output_rounding)
64
- output_base = output_rounding.base
65
- input_base = @context.radix
66
41
 
67
- if number.special? # @context.special?(number)
68
- special_num_to_numeral number
69
- elsif exact_input
70
- if output_base == input_base && output_rounding.free?
71
- # akin to number.format(base: output_base, simplified: true)
72
- general_num_to_numeral number, output_rounding, false
42
+ # mode is either :exact or :approximate
43
+ def number_to_numeral(number, mode, rounding)
44
+ if number.special? # @context.special?(number)
45
+ special_num_to_numeral(number)
73
46
  else
74
- # akin to number.format(base: output_base, exact: true)
75
- exact_num_to_numeral number, output_rounding
47
+ if mode == :exact
48
+ exact_num_to_numeral number, rounding
49
+ else # mode == :approximate
50
+ approximate_num_to_numeral(number, rounding)
51
+ end
76
52
  end
77
- else
78
- if output_base == input_base && output_rounding.preserving?
79
- # akin to number.format(base: output_base)
80
- Numeral.from_coefficient_scale(
81
- number.sign*number.coefficient, number.integral_exponent,
82
- approximate: true, base: output_base
83
- )
84
- elsif output_rounding.simplifying?
85
- # akin to number.forma(base: output_base, simplify: true)
86
- general_num_to_numeral number, output_rounding, false
53
+ end
54
+
55
+ def numeral_to_number(numeral, mode)
56
+ if numeral.special?
57
+ special_numeral_to_num numeral
58
+ elsif mode == :fixed
59
+ fixed_numeral_to_num numeral
60
+ else # mode == :free
61
+ free_numeral_to_num numeral
62
+ end
63
+ end
64
+
65
+ def write(number, exact_input, output_rounding)
66
+ output_base = output_rounding.base
67
+ input_base = @context.radix
68
+
69
+ if number.special? # @context.special?(number)
70
+ special_num_to_numeral number
71
+ elsif exact_input
72
+ if output_base == input_base && output_rounding.free?
73
+ # akin to number.format(base: output_base, simplified: true)
74
+ general_num_to_numeral number, output_rounding, false
75
+ else
76
+ # akin to number.format(base: output_base, exact: true)
77
+ exact_num_to_numeral number, output_rounding
78
+ end
87
79
  else
88
- # akin to number.forma(base: output_base, all_digits: true)
89
- general_num_to_numeral number, output_rounding, true
80
+ if output_base == input_base && output_rounding.preserving?
81
+ # akin to number.format(base: output_base)
82
+ Numeral.from_coefficient_scale(
83
+ number.sign*number.coefficient, number.integral_exponent,
84
+ approximate: true, base: output_base
85
+ )
86
+ elsif output_rounding.simplifying?
87
+ # akin to number.forma(base: output_base, simplify: true)
88
+ general_num_to_numeral number, output_rounding, false
89
+ else
90
+ # akin to number.forma(base: output_base, all_digits: true)
91
+ general_num_to_numeral number, output_rounding, true
92
+ end
90
93
  end
91
94
  end
92
- end
93
95
 
94
- def read(numeral, exact_input, approximate_simplified)
95
- if numeral.special?
96
- special_numeral_to_num numeral
97
- elsif numeral.approximate? && !exact_input
98
- if approximate_simplified
99
- # akin to @context.Num(numeral_text, :short)
100
- short_numeral_to_num numeral
96
+ def read(numeral, exact_input, approximate_simplified)
97
+ if numeral.special?
98
+ special_numeral_to_num numeral
99
+ elsif numeral.approximate? && !exact_input
100
+ if approximate_simplified
101
+ # akin to @context.Num(numeral_text, :short)
102
+ short_numeral_to_num numeral
103
+ else
104
+ # akin to @context.Num(numeral_text, :free)
105
+ free_numeral_to_num numeral
106
+ end
101
107
  else
102
- # akin to @context.Num(numeral_text, :free)
103
- free_numeral_to_num numeral
108
+ # akin to @context.Num(numeral_text, :fixed)
109
+ fixed_numeral_to_num numeral
104
110
  end
105
- else
106
- # akin to @context.Num(numeral_text, :fixed)
107
- fixed_numeral_to_num numeral
108
111
  end
109
- end
110
112
 
111
- private
113
+ private
112
114
 
113
- def special_num_to_numeral(x)
114
- if x.nan?
115
- Numeral.nan
116
- elsif x.infinite?
117
- Numeral.infinity @context.sign(x)
115
+ def special_num_to_numeral(x)
116
+ if x.nan?
117
+ Numeral.nan
118
+ elsif x.infinite?
119
+ Numeral.infinity @context.sign(x)
120
+ end
118
121
  end
119
- end
120
122
 
121
- def exact_num_to_numeral(number, rounding)
122
- quotient = number.to_r
123
- numeral = Numerals::Numeral.from_quotient(quotient, base: rounding.base)
124
- unless rounding.free?
125
- numeral = rounding.round(numeral)
123
+ def exact_num_to_numeral(number, rounding)
124
+ quotient = number.to_r
125
+ numeral = Numerals::Numeral.from_quotient(quotient, base: rounding.base)
126
+ unless rounding.free?
127
+ numeral = rounding.round(numeral)
128
+ end
129
+ numeral
126
130
  end
127
- numeral
128
- end
129
131
 
130
- def approximate_num_to_numeral(number, rounding)
131
- all_digits = !rounding.free?
132
- general_num_to_numeral(number, rounding, all_digits)
133
- end
132
+ def approximate_num_to_numeral(number, rounding)
133
+ all_digits = !rounding.free?
134
+ general_num_to_numeral(number, rounding, all_digits)
135
+ end
134
136
 
135
- def general_num_to_numeral(x, rounding, all_digits)
136
- sign, coefficient, exponent = x.split # @context.split(x)
137
- precision = x.number_of_digits
138
- output_base = rounding.base
137
+ def general_num_to_numeral(x, rounding, all_digits)
138
+ sign, coefficient, exponent = x.split # @context.split(x)
139
+ precision = x.number_of_digits
140
+ output_base = rounding.base
139
141
 
140
- # here rounding_mode is not the output rounding mode, but the rounding mode used for input
141
- rounding_mode = (@input_rounding || rounding).mode
142
+ # here rounding_mode is not the output rounding mode, but the rounding mode used for input
143
+ rounding_mode = (@input_rounding || rounding).mode
142
144
 
143
- formatter = Flt::Support::Formatter.new(
144
- @context.radix, @context.etiny, output_base, raise_on_repeat: false
145
- )
146
- formatter.format(
147
- x, coefficient, exponent, rounding_mode, precision, all_digits
148
- )
145
+ formatter = Flt::Support::Formatter.new(
146
+ @context.radix, @context.etiny, output_base, raise_on_repeat: false
147
+ )
148
+ formatter.format(
149
+ x, coefficient, exponent, rounding_mode, precision, all_digits
150
+ )
149
151
 
150
- dec_pos, digits = formatter.digits
151
- rep_pos = formatter.repeat
152
+ dec_pos, digits = formatter.digits
153
+ rep_pos = formatter.repeat
152
154
 
153
- normalization = :approximate
155
+ normalization = :approximate
154
156
 
155
- numeral = Numerals::Numeral[digits, sign: sign, point: dec_pos, rep_pos: formatter.repeat, base: output_base, normalize: normalization]
157
+ numeral = Numerals::Numeral[digits, sign: sign, point: dec_pos, rep_pos: formatter.repeat, base: output_base, normalize: normalization]
156
158
 
157
- numeral = rounding.round(numeral, round_up: formatter.round_up)
159
+ numeral = rounding.round(numeral, round_up: formatter.round_up)
158
160
 
159
- numeral
160
- end
161
-
162
- def special_numeral_to_num(numeral)
163
- case numeral.special
164
- when :nan
165
- @context.nan
166
- when :inf
167
- @context.infinity numeral.sign
161
+ numeral
168
162
  end
169
- end
170
163
 
171
- def fixed_numeral_to_num(numeral)
172
- # consider:
173
- # return exact_numeral_to_num(numeral) if numeral.exact?
174
- if numeral.base == @context.radix
175
- unless @context.exact?
176
- rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix]
177
- numeral = rounding.round(numeral)
164
+ def special_numeral_to_num(numeral)
165
+ case numeral.special
166
+ when :nan
167
+ @context.nan
168
+ when :inf
169
+ @context.infinity numeral.sign
178
170
  end
179
- same_base_numeral_to_num numeral
180
- else
181
- if numeral.repeating? # numeral.exact?
182
- exact_numeral_to_num(numeral)
171
+ end
172
+
173
+ def fixed_numeral_to_num(numeral)
174
+ # consider:
175
+ # return exact_numeral_to_num(numeral) if numeral.exact?
176
+ if numeral.base == @context.radix
177
+ unless @context.exact?
178
+ rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix]
179
+ numeral = rounding.round(numeral)
180
+ end
181
+ same_base_numeral_to_num numeral
183
182
  else
184
- general_numeral_to_num numeral, :fixed
183
+ if numeral.repeating? # numeral.exact?
184
+ exact_numeral_to_num(numeral)
185
+ else
186
+ general_numeral_to_num numeral, :fixed
187
+ end
185
188
  end
186
189
  end
187
- end
188
-
189
- def same_base_numeral_to_num(numeral)
190
- sign, coefficient, scale = numeral.split
191
- @context.Num sign, coefficient, scale
192
- end
193
-
194
- def exact_numeral_to_num(numeral)
195
- @context.Num Rational(*numeral.to_quotient), :fixed
196
- end
197
190
 
198
- def free_numeral_to_num(numeral)
199
- if numeral.base == @context.radix
200
- same_base_numeral_to_num numeral
201
- else
202
- general_numeral_to_num numeral, :free
191
+ def same_base_numeral_to_num(numeral)
192
+ sign, coefficient, scale = numeral.split
193
+ @context.Num sign, coefficient, scale
203
194
  end
204
- end
205
195
 
206
- def short_numeral_to_num(numeral)
207
- general_numeral_to_num numeral, :short
208
- end
196
+ def exact_numeral_to_num(numeral)
197
+ @context.Num Rational(*numeral.to_quotient), :fixed
198
+ end
209
199
 
210
- def general_numeral_to_num(numeral, mode)
211
- sign, coefficient, scale = numeral.split
212
- reader = Flt::Support::Reader.new(mode: mode)
213
- if @input_rounding
214
- rounding_mode = @input_rounding.mode
215
- else
216
- rounding_Mode = @context.rounding
200
+ def free_numeral_to_num(numeral)
201
+ if numeral.base == @context.radix
202
+ same_base_numeral_to_num numeral
203
+ else
204
+ general_numeral_to_num numeral, :free
205
+ end
217
206
  end
218
- reader.read(@context, rounding_mode, sign, coefficient, scale, numeral.base).tap do
219
- # @exact = reader.exact?
207
+
208
+ def short_numeral_to_num(numeral)
209
+ general_numeral_to_num numeral, :short
220
210
  end
221
- end
222
211
 
223
- end
212
+ def general_numeral_to_num(numeral, mode)
213
+ sign, coefficient, scale = numeral.split
214
+ reader = Flt::Support::Reader.new(mode: mode)
215
+ if @input_rounding
216
+ rounding_mode = @input_rounding.mode
217
+ else
218
+ rounding_Mode = @context.rounding
219
+ end
220
+ reader.read(@context, rounding_mode, sign, coefficient, scale, numeral.base).tap do
221
+ # @exact = reader.exact?
222
+ end
223
+ end
224
224
 
225
- def (Flt::Num).numerals_conversion(options = {})
226
- Numerals::FltConversion.new(self, options)
227
- end
225
+ end
228
226
 
229
- class Flt::Num::ContextBase
230
- def numerals_conversion(options = {})
227
+ def (Flt::Num).numerals_conversion(options = {})
231
228
  Numerals::FltConversion.new(self, options)
232
229
  end
230
+
231
+ class Flt::Num::ContextBase
232
+ def numerals_conversion(options = {})
233
+ Numerals::FltConversion.new(self, options)
234
+ end
235
+ end
236
+
233
237
  end
@@ -144,9 +144,9 @@ module Numerals
144
144
  end
145
145
 
146
146
  # Convert base digits to scaled base digits
147
- def self.ugrouped_digits(digits, base, base_scale)
147
+ def self.ungrouped_digits(digits, base, base_scale)
148
148
  digits.flat_map { |d|
149
- group = Numeral::Digits[base: base]
149
+ group = Digits[base: base]
150
150
  group.value = d
151
151
  ungrouped = group.digits_array
152
152
  if ungrouped.size < base_scale
@@ -104,7 +104,7 @@ module Numerals
104
104
 
105
105
  if @mode.base_scale > 1
106
106
  # De-scale the significand base
107
- digits = Format::BaseScaler.ugrouped_digits(digits, base, @mode.base_scale)
107
+ digits = Format::BaseScaler.ungrouped_digits(digits, base, @mode.base_scale)
108
108
  point *= @mode.base_scale
109
109
  repeat *= @mode.base_scale if repeat
110
110
  end
@@ -34,7 +34,7 @@ module Numerals
34
34
  else
35
35
  # show base suffix as a subscript
36
36
  subscript = format.symbols.base_suffix || base.to_s
37
- º output << "<sub>#{subscript}</sub>"
37
+ output << "<sub>#{subscript}</sub>"
38
38
  end
39
39
  end
40
40
  if text_parts.exponent_value != 0 || format.mode.mode == :scientific
@@ -1,3 +1,3 @@
1
1
  module Numerals
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestBaseScaler < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def digits_string(part, base)
9
10
  part.map{|d| d.to_s(base)}.join
10
11
  end
@@ -2,10 +2,10 @@ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
4
  require 'flt/bigdecimal'
5
- include Numerals
6
5
 
7
6
  class TestBigConversions < Test::Unit::TestCase # < Minitest::Test
8
7
 
8
+ include Numerals
9
9
 
10
10
  def test_write_special
11
11
  context = BigDecimal.context
@@ -2,11 +2,12 @@
2
2
 
3
3
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
4
4
  require 'test/unit'
5
- include Numerals
6
5
  require 'yaml'
7
6
 
8
7
  class TestDigitsDefinition < Test::Unit::TestCase
9
8
 
9
+ include Numerals
10
+
10
11
  DEFAULT_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
11
12
  MAX_TEST_BASE = DEFAULT_DIGITS.size
12
13
 
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestExpSetter < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def check_setter(numeral, n=nil)
9
10
  adjust = Format::ExpSetter[numeral]
10
11
  adjust.integer_part_size = n if n
@@ -1,10 +1,10 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestFloatConversions < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
8
 
9
9
  def test_write_special
10
10
  assert_equal Numeral.nan, Conversions.write(Float.context.nan)
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestFltConversions < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_write_special_binary
9
10
  context = Flt::BinNum.context = Flt::BinNum::FloatContext
10
11
  type = Flt::BinNum
@@ -1,9 +1,10 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
- include Numerals
3
2
  require 'yaml'
4
3
 
5
4
  class TestFormat < Test::Unit::TestCase # < Minitest::Test
6
5
 
6
+ include Numerals
7
+
7
8
  def test_mutated_copy
8
9
  f1 = Format[Rounding[precision: 3, base: 2]]
9
10
 
@@ -1,9 +1,10 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
- include Numerals
3
2
  require 'yaml'
4
3
 
5
4
  class TestFormatInput < Test::Unit::TestCase # < Minitest::Test
6
5
 
6
+ include Numerals
7
+
7
8
  def assert_same_flt(x, y)
8
9
  assert_equal x.class, y.class, x.to_s
9
10
  assert_equal x.split, y.split, x.to_s
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals/rounding'
4
- include Numerals
5
4
 
6
5
  class TestFormatMode < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_format_mode_constructor
9
10
  mode = Format::Mode[:scientific]
10
11
  assert mode.scientific?
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
- include Numerals
3
2
  require 'yaml'
4
3
  require 'tempfile'
5
4
 
6
5
  class TestFormatOutput < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_write_float_dec
9
10
  assert_equal '1', Format[rounding: :short].write(1.0)
10
11
  assert_equal '1', Format[].write(1.0)
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestIntegerConversions < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_read_special
9
10
  assert_raise(ZeroDivisionError){ Conversions.read(Numeral.nan, type: Integer) }
10
11
  assert_raise(ZeroDivisionError){ Conversions.read(Numeral.infinity, type: Integer) }
@@ -1,9 +1,10 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
- include Numerals
3
2
  require 'yaml'
4
3
 
5
4
  class TestNumeral < Test::Unit::TestCase # < Minitest::Test
6
5
 
6
+ include Numerals
7
+
7
8
  def test_numeral_reference_constructors
8
9
  # We'll use this forms as reference for comparisons:
9
10
  # Numeral[digits, base: ..., point: ... , repeat: ...]
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
+
3
+ class TestQualified < Test::Unit::TestCase # < Minitest::Test
4
+
5
+ def test_qualified_use
6
+ assert_equal '1', Numerals::Format[].write(1.0)
7
+ assert_equal '1.00', Numerals::Format[Numerals::Rounding[precision: 3]].write(1.0)
8
+ assert_equal '1.000', Numerals::Format[Numerals::Rounding[places: 3]].write(1.0)
9
+ assert_equal '1234567.1234', Numerals::Format[rounding: :short].write(1234567.1234)
10
+ assert_equal '1234567.123', Numerals::Format[Numerals::Rounding[places: 3]].write(1234567.1234)
11
+ end
12
+
13
+ end
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestRationalConversions < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_read_special
9
10
  assert_raise(ZeroDivisionError){ Conversions.read(Numeral.nan, type: Rational) }
10
11
  assert_raise(ZeroDivisionError){ Conversions.read(Numeral.infinity, type: Rational) }
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals'
4
- include Numerals
5
4
 
6
5
  class TestRepeatDetector < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_repeat_detector
9
10
 
10
11
  assert_equal(
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals/rounding'
4
- include Numerals
5
4
 
6
5
  class TestRounding < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_rounding
9
10
  r = Rounding[:half_even, places: 0]
10
11
  assert_equal Numeral[1,0,0, point: 3, normalize: :approximate], r.round(Numeral[1,0,0,5, point: 3])
@@ -1,10 +1,11 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
2
2
 
3
3
  require 'numerals/rounding'
4
- include Numerals
5
4
 
6
5
  class TestSymbols < Test::Unit::TestCase # < Minitest::Test
7
6
 
7
+ include Numerals
8
+
8
9
  def test_symbols
9
10
  s = Format::Symbols[show_plus: false]
10
11
  s2 = s[uppercase: true]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: numerals
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Goizueta
@@ -123,6 +123,7 @@ files:
123
123
  - test/test_format_output.rb
124
124
  - test/test_integer_conversions.rb
125
125
  - test/test_numeral.rb
126
+ - test/test_qualified.rb
126
127
  - test/test_rational_conversions.rb
127
128
  - test/test_repeat_detector.rb
128
129
  - test/test_rounding.rb
@@ -166,6 +167,7 @@ test_files:
166
167
  - test/test_format_output.rb
167
168
  - test/test_integer_conversions.rb
168
169
  - test/test_numeral.rb
170
+ - test/test_qualified.rb
169
171
  - test/test_rational_conversions.rb
170
172
  - test/test_repeat_detector.rb
171
173
  - test/test_rounding.rb