numerals 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +149 -5
- data/lib/numerals/conversions/bigdecimal.rb +209 -9
- data/lib/numerals/conversions/context_conversion.rb +40 -0
- data/lib/numerals/conversions/float.rb +106 -71
- data/lib/numerals/conversions/flt.rb +115 -44
- data/lib/numerals/conversions/integer.rb +32 -3
- data/lib/numerals/conversions/rational.rb +27 -3
- data/lib/numerals/conversions.rb +74 -33
- data/lib/numerals/digits.rb +8 -5
- data/lib/numerals/format/base_scaler.rb +160 -0
- data/lib/numerals/format/exp_setter.rb +218 -0
- data/lib/numerals/format/format.rb +257 -0
- data/lib/numerals/format/input.rb +140 -0
- data/lib/numerals/format/mode.rb +157 -0
- data/lib/numerals/format/notation.rb +51 -0
- data/lib/numerals/format/notations/html.rb +53 -0
- data/lib/numerals/format/notations/latex.rb +48 -0
- data/lib/numerals/format/notations/text.rb +141 -0
- data/lib/numerals/format/output.rb +167 -0
- data/lib/numerals/format/symbols.rb +565 -0
- data/lib/numerals/format/text_parts.rb +35 -0
- data/lib/numerals/format.rb +25 -0
- data/lib/numerals/formatting_aspect.rb +36 -0
- data/lib/numerals/numeral.rb +34 -21
- data/lib/numerals/repeat_detector.rb +99 -0
- data/lib/numerals/rounding.rb +340 -181
- data/lib/numerals/version.rb +1 -1
- data/lib/numerals.rb +4 -2
- data/numerals.gemspec +1 -1
- data/test/test_base_scaler.rb +189 -0
- data/test/test_big_conversions.rb +105 -0
- data/test/test_digits_definition.rb +23 -28
- data/test/test_exp_setter.rb +732 -0
- data/test/test_float_conversions.rb +48 -30
- data/test/test_flt_conversions.rb +476 -80
- data/test/test_format.rb +124 -0
- data/test/test_format_input.rb +226 -0
- data/test/test_format_mode.rb +124 -0
- data/test/test_format_output.rb +789 -0
- data/test/test_integer_conversions.rb +22 -22
- data/test/test_numeral.rb +35 -0
- data/test/test_rational_conversions.rb +28 -28
- data/test/test_repeat_detector.rb +72 -0
- data/test/test_rounding.rb +158 -0
- data/test/test_symbols.rb +32 -0
- metadata +38 -5
- data/lib/numerals/formatting/digits_definition.rb +0 -75
@@ -1,20 +1,16 @@
|
|
1
|
-
require 'numerals/conversions'
|
2
|
-
require 'flt/float'
|
1
|
+
require 'numerals/conversions/context_conversion'
|
3
2
|
|
4
|
-
class Numerals::FloatConversion
|
3
|
+
class Numerals::FloatConversion < Numerals::ContextConversion
|
5
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
|
11
|
+
#
|
6
12
|
def initialize(options={})
|
7
|
-
|
8
|
-
@context = @type.context
|
9
|
-
options = { use_native_float: true }.merge(options)
|
10
|
-
@use_native_float = options[:use_native_float]
|
11
|
-
# @rounding_mode if used for :free numeral to number conversion
|
12
|
-
# and should be the implied rounding mode of the invers conversion
|
13
|
-
# (number to numeral);
|
14
|
-
# TODO: it should be possible to assign it for higher level
|
15
|
-
# formatting handling.
|
16
|
-
@rounding_mode = @context.rounding
|
17
|
-
@honor_rounding = true
|
13
|
+
super Float, options
|
18
14
|
end
|
19
15
|
|
20
16
|
def order_of_magnitude(value, options={})
|
@@ -26,6 +22,19 @@ class Numerals::FloatConversion
|
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
25
|
+
def number_of_digits(value, options={})
|
26
|
+
base = options[:base] || 10
|
27
|
+
if base == @context.radix
|
28
|
+
@context.precision
|
29
|
+
else
|
30
|
+
@context.necessary_digits(base)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def exact?(value, options={})
|
35
|
+
options[:exact]
|
36
|
+
end
|
37
|
+
|
29
38
|
# mode is either :exact or :approximate
|
30
39
|
def number_to_numeral(number, mode, rounding)
|
31
40
|
if @context.special?(number)
|
@@ -49,70 +58,87 @@ class Numerals::FloatConversion
|
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
61
|
+
def write(number, exact_input, output_rounding)
|
62
|
+
output_base = output_rounding.base
|
63
|
+
input_base = @context.radix
|
64
|
+
|
65
|
+
if @context.special?(number)
|
66
|
+
special_float_to_numeral number
|
67
|
+
elsif exact_input
|
68
|
+
if output_base == input_base && output_rounding.free?
|
69
|
+
# akin to number.format(base: output_base, simplified: true)
|
70
|
+
general_float_to_numeral number, output_rounding, false
|
71
|
+
else
|
72
|
+
# akin to number.format(base: output_base, exact: true)
|
73
|
+
exact_float_to_numeral number, output_rounding
|
74
|
+
end
|
75
|
+
else
|
76
|
+
if output_base == input_base && output_rounding.preserving?
|
77
|
+
# akin to number.format(base: output_base)
|
78
|
+
sign, coefficient, exp = @context.split(number)
|
79
|
+
Numerals::Numeral.from_coefficient_scale(
|
80
|
+
sign*coefficient, exp,
|
81
|
+
approximate: true, base: output_base
|
82
|
+
)
|
83
|
+
elsif output_rounding.simplifying?
|
84
|
+
# akin to number.forma(base: output_base, simplify: true)
|
85
|
+
general_float_to_numeral number, output_rounding, false
|
86
|
+
else
|
87
|
+
# akin to number.forma(base: output_base, all_digits: true)
|
88
|
+
general_float_to_numeral number, output_rounding, true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def read(numeral, exact_input, approximate_simplified)
|
94
|
+
if numeral.special?
|
95
|
+
special_numeral_to_float numeral
|
96
|
+
# elsif numeral.approximate? && !exact_input
|
97
|
+
# if approximate_simplified
|
98
|
+
# # akin to @context.Num(numeral_text, :short)
|
99
|
+
# short_numeral_to_float numeral
|
100
|
+
# else
|
101
|
+
# # akin to @context.Num(numeral_text, :free)
|
102
|
+
# free_numeral_to_float numeral
|
103
|
+
# end
|
104
|
+
else
|
105
|
+
# akin to @context.Num(numeral_text, :fixed)
|
106
|
+
fixed_numeral_to_float numeral
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
52
110
|
private
|
53
111
|
|
54
112
|
def special_float_to_numeral(x)
|
55
113
|
if x.nan?
|
56
|
-
Numeral.nan
|
114
|
+
Numerals::Numeral.nan
|
57
115
|
elsif x.infinite?
|
58
|
-
Numeral.infinity @context.sign(x)
|
116
|
+
Numerals::Numeral.infinity @context.sign(x)
|
59
117
|
end
|
60
118
|
end
|
61
119
|
|
62
120
|
def exact_float_to_numeral(number, rounding)
|
63
121
|
quotient = number.to_r
|
64
|
-
numeral = Numeral.from_quotient(quotient, base: rounding.base)
|
65
|
-
unless rounding.
|
122
|
+
numeral = Numerals::Numeral.from_quotient(quotient, base: rounding.base)
|
123
|
+
unless rounding.free?
|
66
124
|
numeral = rounding.round(numeral)
|
67
125
|
end
|
68
126
|
numeral
|
69
127
|
end
|
70
128
|
|
71
129
|
def approximate_float_to_numeral(number, rounding)
|
72
|
-
all_digits = !rounding.
|
130
|
+
all_digits = !rounding.free?
|
73
131
|
general_float_to_numeral(number, rounding, all_digits)
|
74
132
|
end
|
75
133
|
|
76
|
-
# def fixed_float_to_numeral(number, rounding)
|
77
|
-
# # adjust to rounding.precision
|
78
|
-
# if rounding.exact?
|
79
|
-
# # if simplify
|
80
|
-
# # number = @context.rationalize(simplify)
|
81
|
-
# # end
|
82
|
-
# exact_float_to_numeral number, rounding.base
|
83
|
-
# else
|
84
|
-
# if rounding.base == 10 && @use_native_float
|
85
|
-
# native_float_to_numeral number, rounding
|
86
|
-
# else
|
87
|
-
# general_float_to_numeral number, rounding, true
|
88
|
-
# end
|
89
|
-
# end
|
90
|
-
# end
|
91
|
-
|
92
|
-
# def free_float_to_numeral(number, rounding)
|
93
|
-
# # free mode ignores output precision (rounding) and
|
94
|
-
# # produces the result based only on the number precision
|
95
|
-
# rounding = Rounding[:exact, base: rounding.base]
|
96
|
-
# general_float_to_numeral number, rounding, false
|
97
|
-
# end
|
98
|
-
|
99
|
-
def native_float_to_numeral(number, rounding)
|
100
|
-
need_to_round = (rounding.mode != @context.rounding)
|
101
|
-
n = need_to_round ? Float::DECIMAL_DIG : rounding.precision
|
102
|
-
txt = format("%.*e", n - 1, number)
|
103
|
-
numeral = text_to_numeral(txt, normalize: :approximate) # C-Locale text to numeral...
|
104
|
-
numeral = rounding.round(numeral) if need_to_round
|
105
|
-
numeral
|
106
|
-
end
|
107
|
-
|
108
134
|
def general_float_to_numeral(x, rounding, all_digits)
|
109
|
-
sign, coefficient, exponent =
|
110
|
-
precision =
|
135
|
+
sign, coefficient, exponent = @context.split(x)
|
136
|
+
precision = @context.precision
|
111
137
|
output_base = rounding.base
|
112
138
|
|
113
|
-
# here rounding_mode
|
114
|
-
|
115
|
-
|
139
|
+
# here rounding_mode is not the output rounding mode, but the rounding mode used for input
|
140
|
+
rounding_mode = (@input_rounding || rounding).mode
|
141
|
+
|
116
142
|
formatter = Flt::Support::Formatter.new(
|
117
143
|
@context.radix, @context.etiny, output_base, raise_on_repeat: false
|
118
144
|
)
|
@@ -122,10 +148,14 @@ class Numerals::FloatConversion
|
|
122
148
|
|
123
149
|
dec_pos, digits = formatter.digits
|
124
150
|
rep_pos = formatter.repeat
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
151
|
+
|
152
|
+
normalization = :approximate
|
153
|
+
|
154
|
+
numeral = Numerals::Numeral[digits, sign: sign, point: dec_pos, rep_pos: rep_pos, base: output_base,
|
155
|
+
normalize: normalization]
|
156
|
+
|
157
|
+
numeral = rounding.round(numeral, round_up: formatter.round_up)
|
158
|
+
|
129
159
|
numeral
|
130
160
|
end
|
131
161
|
|
@@ -139,8 +169,7 @@ class Numerals::FloatConversion
|
|
139
169
|
end
|
140
170
|
|
141
171
|
def fixed_numeral_to_float(numeral)
|
142
|
-
|
143
|
-
# return exact_numeral_to_float(numeral) if numeral.exact?
|
172
|
+
return exact_numeral_to_float(numeral) if numeral.exact?
|
144
173
|
if numeral.base == @context.radix
|
145
174
|
same_base_numeral_to_float numeral
|
146
175
|
else
|
@@ -148,9 +177,9 @@ class Numerals::FloatConversion
|
|
148
177
|
# to a numeral preserving its value.
|
149
178
|
representable_digits = @context.representable_digits(numeral.base)
|
150
179
|
k = numeral.scale
|
151
|
-
if !@
|
180
|
+
if !@input_rounding && numeral.digits.size <= representable_digits && k.abs <= representable_digits
|
152
181
|
representable_numeral_to_float numeral
|
153
|
-
elsif !@
|
182
|
+
elsif !@input_rounding && (k > 0 && numeral.point < 2*representable_digits)
|
154
183
|
near_representable_numeral_to_float numeral
|
155
184
|
elsif numeral.base.modulo(@context.radix) == 0
|
156
185
|
conmensurable_base_numeral_to_float numeral
|
@@ -172,6 +201,12 @@ class Numerals::FloatConversion
|
|
172
201
|
general_numeral_to_float numeral, :free
|
173
202
|
end
|
174
203
|
|
204
|
+
def short_numeral_to_float(numeral)
|
205
|
+
# raise "Invalid Conversion" # Float does not support short (arbitrary precision)
|
206
|
+
# fixed_numeral_to_float numeral
|
207
|
+
general_numeral_to_float numeral, :short
|
208
|
+
end
|
209
|
+
|
175
210
|
def same_base_numeral_to_float(numeral)
|
176
211
|
sign, coefficient, scale = numeral.split
|
177
212
|
@context.Num(sign, coefficient, scale)
|
@@ -203,10 +238,10 @@ class Numerals::FloatConversion
|
|
203
238
|
def general_numeral_to_float(numeral, mode)
|
204
239
|
sign, coefficient, scale = numeral.split
|
205
240
|
reader = Flt::Support::Reader.new(mode: mode)
|
206
|
-
if
|
207
|
-
rounding_mode = @
|
241
|
+
if @input_rounding
|
242
|
+
rounding_mode = @input_rounding.mode
|
208
243
|
else
|
209
|
-
|
244
|
+
rounding_Mode = @context.rounding
|
210
245
|
end
|
211
246
|
reader.read(@context, rounding_mode, sign, coefficient, scale, numeral.base).tap do
|
212
247
|
# @exact = reader.exact?
|
@@ -215,12 +250,12 @@ class Numerals::FloatConversion
|
|
215
250
|
|
216
251
|
end
|
217
252
|
|
218
|
-
def Float.numerals_conversion
|
219
|
-
Numerals::FloatConversion.new
|
253
|
+
def Float.numerals_conversion(options = {})
|
254
|
+
Numerals::FloatConversion.new(options)
|
220
255
|
end
|
221
256
|
|
222
257
|
class <<Float.context
|
223
|
-
def numerals_conversion
|
224
|
-
Numerals::FloatConversion.new
|
258
|
+
def numerals_conversion(options = {})
|
259
|
+
Numerals::FloatConversion.new(options)
|
225
260
|
end
|
226
261
|
end
|
@@ -1,28 +1,20 @@
|
|
1
|
-
require 'numerals/conversions'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# @rounding_mode if used for :free numeral to number conversion
|
17
|
-
# and should be the implied rounding mode of the invers conversion
|
18
|
-
# (number to numeral);
|
19
|
-
# TODO: it should be possible to assign it for higher level
|
20
|
-
# formatting handling.
|
21
|
-
@rounding_mode = @context.rounding
|
1
|
+
require 'numerals/conversions/context_conversion'
|
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
|
22
16
|
end
|
23
17
|
|
24
|
-
attr_reader :context, :type
|
25
|
-
|
26
18
|
def order_of_magnitude(value, options={})
|
27
19
|
base = options[:base] || 10 # value.num_class.radix
|
28
20
|
if value.class.radix == base
|
@@ -32,6 +24,19 @@ class Numerals::FltConversion
|
|
32
24
|
end
|
33
25
|
end
|
34
26
|
|
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)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def exact?(value, options={})
|
37
|
+
options[:exact]
|
38
|
+
end
|
39
|
+
|
35
40
|
# mode is either :exact or :approximate
|
36
41
|
def number_to_numeral(number, mode, rounding)
|
37
42
|
if number.special? # @context.special?(number)
|
@@ -55,6 +60,54 @@ class Numerals::FltConversion
|
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
63
|
+
def write(number, exact_input, output_rounding)
|
64
|
+
output_base = output_rounding.base
|
65
|
+
input_base = @context.radix
|
66
|
+
|
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
|
73
|
+
else
|
74
|
+
# akin to number.format(base: output_base, exact: true)
|
75
|
+
exact_num_to_numeral number, output_rounding
|
76
|
+
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
|
87
|
+
else
|
88
|
+
# akin to number.forma(base: output_base, all_digits: true)
|
89
|
+
general_num_to_numeral number, output_rounding, true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
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
|
101
|
+
else
|
102
|
+
# akin to @context.Num(numeral_text, :free)
|
103
|
+
free_numeral_to_num numeral
|
104
|
+
end
|
105
|
+
else
|
106
|
+
# akin to @context.Num(numeral_text, :fixed)
|
107
|
+
fixed_numeral_to_num numeral
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
58
111
|
private
|
59
112
|
|
60
113
|
def special_num_to_numeral(x)
|
@@ -67,26 +120,26 @@ class Numerals::FltConversion
|
|
67
120
|
|
68
121
|
def exact_num_to_numeral(number, rounding)
|
69
122
|
quotient = number.to_r
|
70
|
-
numeral = Numeral.from_quotient(quotient, base: rounding.base)
|
71
|
-
unless rounding.
|
123
|
+
numeral = Numerals::Numeral.from_quotient(quotient, base: rounding.base)
|
124
|
+
unless rounding.free?
|
72
125
|
numeral = rounding.round(numeral)
|
73
126
|
end
|
74
127
|
numeral
|
75
128
|
end
|
76
129
|
|
77
130
|
def approximate_num_to_numeral(number, rounding)
|
78
|
-
all_digits = !rounding.
|
131
|
+
all_digits = !rounding.free?
|
79
132
|
general_num_to_numeral(number, rounding, all_digits)
|
80
133
|
end
|
81
134
|
|
82
135
|
def general_num_to_numeral(x, rounding, all_digits)
|
83
|
-
sign, coefficient, exponent = x.split
|
136
|
+
sign, coefficient, exponent = x.split # @context.split(x)
|
84
137
|
precision = x.number_of_digits
|
85
138
|
output_base = rounding.base
|
86
139
|
|
87
|
-
# here rounding_mode
|
88
|
-
|
89
|
-
|
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
|
+
|
90
143
|
formatter = Flt::Support::Formatter.new(
|
91
144
|
@context.radix, @context.etiny, output_base, raise_on_repeat: false
|
92
145
|
)
|
@@ -96,10 +149,13 @@ class Numerals::FltConversion
|
|
96
149
|
|
97
150
|
dec_pos, digits = formatter.digits
|
98
151
|
rep_pos = formatter.repeat
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
152
|
+
|
153
|
+
normalization = :approximate
|
154
|
+
|
155
|
+
numeral = Numerals::Numeral[digits, sign: sign, point: dec_pos, rep_pos: formatter.repeat, base: output_base, normalize: normalization]
|
156
|
+
|
157
|
+
numeral = rounding.round(numeral, round_up: formatter.round_up)
|
158
|
+
|
103
159
|
numeral
|
104
160
|
end
|
105
161
|
|
@@ -116,10 +172,17 @@ class Numerals::FltConversion
|
|
116
172
|
# consider:
|
117
173
|
# return exact_numeral_to_num(numeral) if numeral.exact?
|
118
174
|
if numeral.base == @context.radix
|
119
|
-
|
175
|
+
unless @context.exact?
|
176
|
+
rounding = Rounding[@context.rounding, precision: @context.precision, base: @context.radix]
|
177
|
+
numeral = rounding.round(numeral)
|
178
|
+
end
|
120
179
|
same_base_numeral_to_num numeral
|
121
180
|
else
|
122
|
-
|
181
|
+
if numeral.repeating? # numeral.exact?
|
182
|
+
exact_numeral_to_num(numeral)
|
183
|
+
else
|
184
|
+
general_numeral_to_num numeral, :fixed
|
185
|
+
end
|
123
186
|
end
|
124
187
|
end
|
125
188
|
|
@@ -133,16 +196,24 @@ class Numerals::FltConversion
|
|
133
196
|
end
|
134
197
|
|
135
198
|
def free_numeral_to_num(numeral)
|
136
|
-
|
199
|
+
if numeral.base == @context.radix
|
200
|
+
same_base_numeral_to_num numeral
|
201
|
+
else
|
202
|
+
general_numeral_to_num numeral, :free
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def short_numeral_to_num(numeral)
|
207
|
+
general_numeral_to_num numeral, :short
|
137
208
|
end
|
138
209
|
|
139
210
|
def general_numeral_to_num(numeral, mode)
|
140
211
|
sign, coefficient, scale = numeral.split
|
141
212
|
reader = Flt::Support::Reader.new(mode: mode)
|
142
|
-
if
|
143
|
-
rounding_mode = @
|
213
|
+
if @input_rounding
|
214
|
+
rounding_mode = @input_rounding.mode
|
144
215
|
else
|
145
|
-
|
216
|
+
rounding_Mode = @context.rounding
|
146
217
|
end
|
147
218
|
reader.read(@context, rounding_mode, sign, coefficient, scale, numeral.base).tap do
|
148
219
|
# @exact = reader.exact?
|
@@ -151,12 +222,12 @@ class Numerals::FltConversion
|
|
151
222
|
|
152
223
|
end
|
153
224
|
|
154
|
-
def (Flt::Num).numerals_conversion
|
155
|
-
Numerals::FltConversion.new(self)
|
225
|
+
def (Flt::Num).numerals_conversion(options = {})
|
226
|
+
Numerals::FltConversion.new(self, options)
|
156
227
|
end
|
157
228
|
|
158
229
|
class Flt::Num::ContextBase
|
159
|
-
def numerals_conversion
|
160
|
-
Numerals::FltConversion.new(self)
|
230
|
+
def numerals_conversion(options = {})
|
231
|
+
Numerals::FltConversion.new(self, options)
|
161
232
|
end
|
162
233
|
end
|
@@ -8,6 +8,10 @@ class Numerals::IntegerConversion
|
|
8
8
|
class InvalidConversion < RuntimeError
|
9
9
|
end
|
10
10
|
|
11
|
+
def type
|
12
|
+
Integer
|
13
|
+
end
|
14
|
+
|
11
15
|
def order_of_magnitude(value, options={})
|
12
16
|
base = options[:base] || 10
|
13
17
|
if base == 2 && value.respond_to?(:bit_length)
|
@@ -17,10 +21,19 @@ class Numerals::IntegerConversion
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
24
|
+
def number_of_digits(value, options={})
|
25
|
+
# order_of_magnitude(value, options)
|
26
|
+
0 # this is needed only for non-exact values
|
27
|
+
end
|
28
|
+
|
29
|
+
def exact?(value, options={})
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
20
33
|
def number_to_numeral(number, mode, rounding)
|
21
34
|
# Rational.numerals_conversion Rational(number), mode, rounding
|
22
|
-
numeral = Numeral.from_quotient(number, 1)
|
23
|
-
numeral = rounding.round(numeral) unless rounding.
|
35
|
+
numeral = Numerals::Numeral.from_quotient(number, 1)
|
36
|
+
numeral = rounding.round(numeral) # unless rounding.free?
|
24
37
|
numeral
|
25
38
|
end
|
26
39
|
|
@@ -32,8 +45,24 @@ class Numerals::IntegerConversion
|
|
32
45
|
rational.numerator
|
33
46
|
end
|
34
47
|
|
48
|
+
def write(number, exact_input, output_rounding)
|
49
|
+
output_base = output_rounding.base
|
50
|
+
numeral = Numerals::Numeral.from_quotient(number, 1, base: output_base)
|
51
|
+
numeral = output_rounding.round(numeral) # unless output_rounding.free?
|
52
|
+
numeral
|
53
|
+
end
|
54
|
+
|
55
|
+
def read(numeral, exact_input, approximate_simplified)
|
56
|
+
rational = Rational.numerals_conversion.read numeral, exact_input, approximate_simplified
|
57
|
+
if rational.denominator != 1
|
58
|
+
raise InvalidConversion, "Invalid numeral to rational conversion"
|
59
|
+
end
|
60
|
+
rational.numerator
|
61
|
+
end
|
62
|
+
|
63
|
+
|
35
64
|
end
|
36
65
|
|
37
|
-
def Integer.numerals_conversion
|
66
|
+
def Integer.numerals_conversion(options = {})
|
38
67
|
Numerals::IntegerConversion.instance
|
39
68
|
end
|
@@ -5,6 +5,10 @@ class Numerals::RationalConversion
|
|
5
5
|
|
6
6
|
include Singleton
|
7
7
|
|
8
|
+
def type
|
9
|
+
Rational
|
10
|
+
end
|
11
|
+
|
8
12
|
def order_of_magnitude(value, options={})
|
9
13
|
base = options[:base] || 10
|
10
14
|
if base == 10
|
@@ -14,10 +18,18 @@ class Numerals::RationalConversion
|
|
14
18
|
end
|
15
19
|
end
|
16
20
|
|
21
|
+
def number_of_digits(value, options={})
|
22
|
+
return 0 # this is needed only for non-exact values
|
23
|
+
end
|
24
|
+
|
25
|
+
def exact?(value, options={})
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
17
29
|
def number_to_numeral(number, mode, rounding)
|
18
30
|
q = [number.numerator, number.denominator]
|
19
|
-
numeral = Numeral.from_quotient(q)
|
20
|
-
numeral = rounding.round(numeral) unless rounding.
|
31
|
+
numeral = Numerals::Numeral.from_quotient(q)
|
32
|
+
numeral = rounding.round(numeral) # unless rounding.free?
|
21
33
|
numeral
|
22
34
|
end
|
23
35
|
|
@@ -25,8 +37,20 @@ class Numerals::RationalConversion
|
|
25
37
|
Rational(*numeral.to_quotient)
|
26
38
|
end
|
27
39
|
|
40
|
+
def write(number, exact_input, output_rounding)
|
41
|
+
output_base = output_rounding.base
|
42
|
+
q = [number.numerator, number.denominator]
|
43
|
+
numeral = Numerals::Numeral.from_quotient(q, base: output_base)
|
44
|
+
numeral = output_rounding.round(numeral) # unless output_rounding.free?
|
45
|
+
numeral
|
46
|
+
end
|
47
|
+
|
48
|
+
def read(numeral, exact_input, approximate_simplified)
|
49
|
+
Rational(*numeral.to_quotient)
|
50
|
+
end
|
51
|
+
|
28
52
|
end
|
29
53
|
|
30
|
-
def Rational.numerals_conversion
|
54
|
+
def Rational.numerals_conversion(options = {})
|
31
55
|
Numerals::RationalConversion.instance
|
32
56
|
end
|