numerals 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +24 -0
- data/Rakefile +19 -0
- data/lib/numerals/conversions/bigdecimal.rb +30 -0
- data/lib/numerals/conversions/float.rb +226 -0
- data/lib/numerals/conversions/flt.rb +162 -0
- data/lib/numerals/conversions/integer.rb +39 -0
- data/lib/numerals/conversions/rational.rb +32 -0
- data/lib/numerals/conversions.rb +57 -0
- data/lib/numerals/digits.rb +99 -0
- data/lib/numerals/formatting/digits_definition.rb +75 -0
- data/lib/numerals/formatting/options.rb +84 -0
- data/lib/numerals/numeral.rb +650 -0
- data/lib/numerals/rounding.rb +229 -0
- data/lib/numerals/support.rb +10 -0
- data/lib/numerals/version.rb +3 -0
- data/lib/numerals.rb +12 -0
- data/numerals.gemspec +26 -0
- data/test/data.yaml +101 -0
- data/test/helper.rb +40 -0
- data/test/test_digits_definition.rb +110 -0
- data/test/test_float_conversions.rb +58 -0
- data/test/test_flt_conversions.rb +277 -0
- data/test/test_integer_conversions.rb +50 -0
- data/test/test_numeral.rb +366 -0
- data/test/test_rational_conversions.rb +75 -0
- data/test/test_rounding.rb +77 -0
- metadata +138 -0
@@ -0,0 +1,229 @@
|
|
1
|
+
# Rounding of Numerals
|
2
|
+
class Rounding
|
3
|
+
|
4
|
+
# Rounding is defined by the rounding mode and the precision,
|
5
|
+
# and is used to stablish the desired accuracy of a Numeral result.
|
6
|
+
#
|
7
|
+
# The rounding mode may be any of the valid Flt rounding modes
|
8
|
+
# (:half_even, :half_down, :half_up, :floor, :ceiling, :down, :up or :up05)
|
9
|
+
# or :exact for no rounding at all (to represent the situation where
|
10
|
+
# we want to get an exact numeral result.
|
11
|
+
#
|
12
|
+
# The precision may be defined either as a relative :precision value
|
13
|
+
# (number of significant digits of the result numeral) or as an :absolute
|
14
|
+
# :places that indicate the number of digits to the right of the fractional
|
15
|
+
# point. Negative values of :places will round to digits in integral positions.
|
16
|
+
#
|
17
|
+
# The base of the numerals to be rounded must also be defined (10 by default)
|
18
|
+
#
|
19
|
+
def initialize(*args)
|
20
|
+
if Hash === args.last
|
21
|
+
options = args.pop.dup
|
22
|
+
else
|
23
|
+
options = {}
|
24
|
+
end
|
25
|
+
args.each do |arg|
|
26
|
+
if Symbol === arg
|
27
|
+
options[:mode] = arg
|
28
|
+
elsif Integer === arg
|
29
|
+
options[:precision] = arg
|
30
|
+
else
|
31
|
+
raise "Invalid Rounding definition"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
assign! options
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :mode, :base
|
38
|
+
|
39
|
+
include ModalSupport::BracketConstructor
|
40
|
+
include ModalSupport::StateEquivalent
|
41
|
+
|
42
|
+
def [](options={})
|
43
|
+
assign! options
|
44
|
+
end
|
45
|
+
|
46
|
+
def assign!(options)
|
47
|
+
@mode = options[:mode] || @mode
|
48
|
+
@precision = options[:precision] || @precision
|
49
|
+
@places = options[:places] || @places
|
50
|
+
@base = options[:base] || @base
|
51
|
+
|
52
|
+
if (@precision == 0 || @precision.nil?) && @places.nil?
|
53
|
+
@precision = 0
|
54
|
+
@mode = :exact
|
55
|
+
else
|
56
|
+
@mode ||= :half_even
|
57
|
+
end
|
58
|
+
if @mode == :exact
|
59
|
+
@precision = 0
|
60
|
+
@places = nil
|
61
|
+
end
|
62
|
+
@base ||= 10
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def parameters
|
67
|
+
if exact?
|
68
|
+
{ mode: :exact }
|
69
|
+
elsif relative?
|
70
|
+
{ mode: @mode, precision: @precision }
|
71
|
+
elsif absolute?
|
72
|
+
{ mode: @mode, places: @places }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_s
|
77
|
+
if exact?
|
78
|
+
"Rounding[:exact]"
|
79
|
+
elsif relative?
|
80
|
+
"Rounding[#{@mode.inspect}, precision: #{@precision}]"
|
81
|
+
elsif absolute?
|
82
|
+
"Rounding[#{@mode.inspect}, places: #{@places}]"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
def exact?
|
91
|
+
@mode == :exact
|
92
|
+
end
|
93
|
+
|
94
|
+
def absolute?
|
95
|
+
!exact? && !@precision
|
96
|
+
end
|
97
|
+
|
98
|
+
def relative?
|
99
|
+
!exact? && !absolute?
|
100
|
+
end
|
101
|
+
|
102
|
+
# Number of significant digits for a given numerical/numeral value
|
103
|
+
def precision(value)
|
104
|
+
if relative? || exact?
|
105
|
+
@precision
|
106
|
+
else
|
107
|
+
@places + num_integral_digits(value)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Number of fractional placesfor a given numerical/numeral value
|
112
|
+
def places(value)
|
113
|
+
if absolute? || exact?
|
114
|
+
@places
|
115
|
+
else
|
116
|
+
@precision - num_integral_digits(value)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Round a numeral. If the numeral has been truncated
|
121
|
+
# the :round_up option must be used to pass the information
|
122
|
+
# about the discarded digits:
|
123
|
+
# * nil if all discarded digits where 0 (the truncated value is exact)
|
124
|
+
# * :lo if there where non-zero discarded digits, but the first discarded digit
|
125
|
+
# is below half the base.
|
126
|
+
# * :tie if the first discarded was half the base and there where no more nonzero digits,
|
127
|
+
# i.e. the original value was a 'tie', exactly halfway between the truncated value
|
128
|
+
# and the next value with the same number of digits.
|
129
|
+
# * :hi if the original value was above the tie value.
|
130
|
+
def round(numeral, options={})
|
131
|
+
round_up = options[:round_up]
|
132
|
+
numeral, round_up = truncate(numeral, round_up)
|
133
|
+
adjust(numeral, round_up)
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def check_base(numeral)
|
139
|
+
if numeral.base != @base
|
140
|
+
raise "Invalid Numeral (base #{numeral.base}) for a base #{@base} Rounding"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Truncate a numeral and return also a round_up value with information about
|
145
|
+
# the digits beyond the truncation point that can be used to round the truncated
|
146
|
+
# numeral. If the numeral has already been truncated, the round_up result of
|
147
|
+
# that truncation should be passed as the second argument.
|
148
|
+
def truncate(numeral, round_up=nil)
|
149
|
+
check_base numeral
|
150
|
+
if exact?
|
151
|
+
round_up = nil
|
152
|
+
else
|
153
|
+
n = precision(numeral)
|
154
|
+
unless n==numeral.digits.size && numeral.approximate?
|
155
|
+
if n < numeral.digits.size - 1
|
156
|
+
rest_digits = numeral.digits[n+1..-1]
|
157
|
+
else
|
158
|
+
rest_digits = []
|
159
|
+
end
|
160
|
+
if numeral.repeating? && numeral.repeat < numeral.digits.size && n >= numeral.repeat
|
161
|
+
rest_digits += numeral.digits[numeral.repeat..-1]
|
162
|
+
end
|
163
|
+
digits = numeral.digits[0, n]
|
164
|
+
if digits.size < n
|
165
|
+
digits += (digits.size...n).map{|i| numeral.digit_value_at(i)}
|
166
|
+
end
|
167
|
+
if numeral.base % 2 == 0
|
168
|
+
tie_digit = numeral.base / 2
|
169
|
+
max_lo = tie_digit - 1
|
170
|
+
else
|
171
|
+
max_lo = numeral.base / 2
|
172
|
+
end
|
173
|
+
next_digit = numeral.digit_value_at(n)
|
174
|
+
if next_digit == 0
|
175
|
+
unless round_up.nil? && rest_digits.all?{|d| d == 0}
|
176
|
+
round_up = :lo
|
177
|
+
end
|
178
|
+
elsif next_digit <= max_lo # next_digit < tie_digit
|
179
|
+
round_up = :lo
|
180
|
+
elsif next_digit == tie_digit
|
181
|
+
if round_up || rest_digits.any?{|d| d != 0}
|
182
|
+
round_up = :hi
|
183
|
+
else
|
184
|
+
round_up = :tie
|
185
|
+
end
|
186
|
+
else # next_digit > tie_digit
|
187
|
+
round_up = :hi
|
188
|
+
end
|
189
|
+
numeral = Numeral[digits, point: numeral.point, sign: numeral.sign, normalize: :approximate]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
[numeral, round_up]
|
193
|
+
end
|
194
|
+
|
195
|
+
# Adjust a truncated numeral using the round-up information
|
196
|
+
def adjust(numeral, round_up)
|
197
|
+
check_base numeral
|
198
|
+
point, digits = Flt::Support.adjust_digits(
|
199
|
+
numeral.point, numeral.digits.digits_array,
|
200
|
+
round_mode: @mode,
|
201
|
+
negative: numeral.sign == -1,
|
202
|
+
round_up: round_up,
|
203
|
+
base: numeral.base
|
204
|
+
)
|
205
|
+
Numeral[digits, point: point, base: numeral.base, sign: numeral.sign, normalize: :approximate]
|
206
|
+
end
|
207
|
+
|
208
|
+
ZERO_DIGITS = 0 # 1?
|
209
|
+
|
210
|
+
# Number of digits in the integer part of the value (excluding leading zeros).
|
211
|
+
def num_integral_digits(value)
|
212
|
+
case value
|
213
|
+
when 0
|
214
|
+
ZERO_DIGITS
|
215
|
+
when Numeral
|
216
|
+
if value.zero?
|
217
|
+
ZERO_DIGITS
|
218
|
+
else
|
219
|
+
if @base != value.base
|
220
|
+
value = value.to_base(@base)
|
221
|
+
end
|
222
|
+
value.normalized(remove_trailing_zeros: true).point
|
223
|
+
end
|
224
|
+
else
|
225
|
+
Conversions.order_of_magnitude(value, base: @base)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
data/lib/numerals.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'modalsupport'
|
2
|
+
|
3
|
+
require "numerals/version"
|
4
|
+
require 'numerals/numeral'
|
5
|
+
require 'numerals/rounding'
|
6
|
+
require 'numerals/conversions/float'
|
7
|
+
require 'numerals/conversions/integer'
|
8
|
+
require 'numerals/conversions/rational'
|
9
|
+
require 'numerals/conversions/bigdecimal'
|
10
|
+
require 'numerals/conversions/flt'
|
11
|
+
require 'numerals/formatting/digits_definition'
|
12
|
+
require 'numerals/formatting/options'
|
data/numerals.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'numerals/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "numerals"
|
8
|
+
spec.version = Numerals::VERSION
|
9
|
+
spec.authors = ["Javier Goizueta"]
|
10
|
+
spec.email = ["jgoizueta@gmail.com"]
|
11
|
+
spec.summary = %q{Number representation as text.}
|
12
|
+
spec.description = %q{Number formatting and reading.}
|
13
|
+
spec.homepage = "https://github.com/jgoizueta/numerals"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'flt', "~> 1.3.4"
|
22
|
+
spec.add_dependency 'modalsupport', "~> 0.9.2"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
data/test/data.yaml
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
---
|
2
|
+
- A91C2BB757F72141
|
3
|
+
- D84014519CD8253F
|
4
|
+
- BF30A46FFF51ED3F
|
5
|
+
- 91D03B54623CC03E
|
6
|
+
- D403F243699B4B3F
|
7
|
+
- 6D1F99449A26D540
|
8
|
+
- 92817CDBC7715E3F
|
9
|
+
- 72696E8F13BB323F
|
10
|
+
- 683C16C10F79FE3E
|
11
|
+
- 22801BA12A074740
|
12
|
+
- 7081D3172A53E5BF
|
13
|
+
- C0DE790FC0FBE9BF
|
14
|
+
- 3AE5F0923E55D33F
|
15
|
+
- 92B6BEEC140A8FBF
|
16
|
+
- CE66ABACDBD80F3F
|
17
|
+
- ACC70B95DCFF6BC0
|
18
|
+
- 1461EF81707378BF
|
19
|
+
- AE09EC08D0F1ADBF
|
20
|
+
- 34DA3FFF72E9D83F
|
21
|
+
- C664AD3F9AC4BFBF
|
22
|
+
- 2101BE78DFDC74BE
|
23
|
+
- 7EE9B042D4628140
|
24
|
+
- 90368189CC8D753F
|
25
|
+
- 337C9D874DC4C5BE
|
26
|
+
- 0CFDA79A7FDCED3F
|
27
|
+
- EC94C739F2CFB3BF
|
28
|
+
- 1D5436848A1AEBBE
|
29
|
+
- B725B6C420034640
|
30
|
+
- 48C692FEAA59DEBF
|
31
|
+
- BC4CB816B0BAB5BF
|
32
|
+
- C2D835BC80B99A40
|
33
|
+
- 6A565C2E720847BF
|
34
|
+
- 050189AF84C84EC1
|
35
|
+
- 0060B28B63B5DC3F
|
36
|
+
- 18A387F2A64E5FC0
|
37
|
+
- FBC8B0D428E302C1
|
38
|
+
- A30DD43ED762B4C0
|
39
|
+
- 3D85522EC70AFDBE
|
40
|
+
- FCF62D2923F0583F
|
41
|
+
- DB588C2A9C26FBC0
|
42
|
+
- BA4E1863DBE6FCBE
|
43
|
+
- 5C34946E1A12D33F
|
44
|
+
- 90E63D7E81888740
|
45
|
+
- 82541C0DE9F1443F
|
46
|
+
- 9F2A7781EE4B683F
|
47
|
+
- 0082C4B6393EA7BF
|
48
|
+
- 768EDD6B97D19540
|
49
|
+
- 87BA76258BEBFBBE
|
50
|
+
- 7A6580A6639DD7BF
|
51
|
+
- 26DDD435F13B12BF
|
52
|
+
- 1AF857C69682DBBF
|
53
|
+
- E731C0DCDAAE51BF
|
54
|
+
- DB9DB0551A511F3F
|
55
|
+
- 04977B9C4C73D13F
|
56
|
+
- 44D5BB96C84587C0
|
57
|
+
- CE3DE8C2DF9942BF
|
58
|
+
- 23F12DE055F30C3F
|
59
|
+
- C10951998E1B7440
|
60
|
+
- 1CC3F51802F309C0
|
61
|
+
- FB97E7DB6B081DC1
|
62
|
+
- 5C811354280FEA3F
|
63
|
+
- A405ED0A749718BF
|
64
|
+
- 322939F71F7A51BF
|
65
|
+
- F3E06C6EEB2342BF
|
66
|
+
- 5A6D9DF3F879D3C0
|
67
|
+
- BC466E35C5AF9940
|
68
|
+
- EB4571E54EB7CD3F
|
69
|
+
- BBA9A8401CD4D13F
|
70
|
+
- 6A565DEA5E4F8A40
|
71
|
+
- 20586794310B93BF
|
72
|
+
- 80B8449C203B9BC0
|
73
|
+
- 0E9C461358F4AABF
|
74
|
+
- 469E0A1D42DEA73F
|
75
|
+
- 711DA636DD2C41BF
|
76
|
+
- 414A9E166BE2A0C0
|
77
|
+
- 407FF9F39253F2BE
|
78
|
+
- BAD158256942D4C0
|
79
|
+
- 2D4424FE12BE94BF
|
80
|
+
- 7F0F15B537E997C0
|
81
|
+
- 4ADF1BD93C66F1BF
|
82
|
+
- 2DAF002ADBC1E0BF
|
83
|
+
- 3739FF3C2BE601C0
|
84
|
+
- 38ACCEAE7B88083F
|
85
|
+
- 7C2D9D7FA150C23F
|
86
|
+
- B726087920E8EA3F
|
87
|
+
- C075B44F459250BE
|
88
|
+
- 9EDAB9C61F7D783F
|
89
|
+
- 2FE6362CACE5153F
|
90
|
+
- 98A24B93A2F4C33E
|
91
|
+
- 6FD39CEB5C7F15C0
|
92
|
+
- C5BE550840E4503F
|
93
|
+
- 214EA7E4F9619640
|
94
|
+
- 4DEF9253DE1C10C0
|
95
|
+
- B8C76C5B85E4FDBF
|
96
|
+
- 07D21EB7A400F13F
|
97
|
+
- DB103669202EAEBF
|
98
|
+
- 9F59E7B3EA71E63F
|
99
|
+
- 83712959474BF440
|
100
|
+
- 8D5B7FA245A650BF
|
101
|
+
- 16FAF25CCBB8ECBE
|
data/test/helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
# require 'minitest/spec'
|
3
|
+
# require 'minitest/unit'
|
4
|
+
$: << "." unless $:.include?(".") # for Ruby 1.9.2
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'/../lib/numerals'))
|
6
|
+
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
module PrepareData
|
10
|
+
|
11
|
+
@@data = []
|
12
|
+
|
13
|
+
def self.add(x)
|
14
|
+
@@data << [x].pack('E').unpack('H*')[0].upcase
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.init
|
18
|
+
unless File.exist?('test/data.yaml')
|
19
|
+
100.times do
|
20
|
+
x = rand
|
21
|
+
x *= rand(1000) if rand<0.5
|
22
|
+
x /= rand(1000) if rand<0.5
|
23
|
+
x *= rand(9999) if rand<0.5
|
24
|
+
x /= rand(9999) if rand<0.5
|
25
|
+
x = -x if rand<0.5
|
26
|
+
#puts x
|
27
|
+
add x
|
28
|
+
end
|
29
|
+
add 1.0/3
|
30
|
+
add 0.1
|
31
|
+
File.open('test/data.yaml','w') { |out| out << @@data.to_yaml }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
PrepareData.init
|
37
|
+
|
38
|
+
def BigDec(x)
|
39
|
+
BigDecimal.new(x.to_s)
|
40
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
|
4
|
+
require 'test/unit'
|
5
|
+
include Numerals
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
class TestDigitsDefinition < Test::Unit::TestCase
|
9
|
+
|
10
|
+
DEFAULT_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
11
|
+
MAX_TEST_BASE = DEFAULT_DIGITS.size
|
12
|
+
|
13
|
+
def default_digits(b)
|
14
|
+
DEFAULT_DIGITS[0,b]
|
15
|
+
end
|
16
|
+
|
17
|
+
def define_from_digits(b)
|
18
|
+
DigitsDefinition[default_digits(b)]
|
19
|
+
end
|
20
|
+
|
21
|
+
def define_from_base(b)
|
22
|
+
DigitsDefinition[base: b]
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_base(b, digits)
|
26
|
+
assert_equal b, digits.radix
|
27
|
+
(0...b).each do |digit_value|
|
28
|
+
digit_char = default_digits(b)[digit_value]
|
29
|
+
assert_equal digit_char, digits.digit_char(digit_value)
|
30
|
+
assert_equal digit_value, digits.digit_value(digit_char)
|
31
|
+
assert digits.is_digit?(digit_char)
|
32
|
+
end
|
33
|
+
[-10,-5,-2,-1,b,b+1,b+2,b+10].each do |invalid_digit_value|
|
34
|
+
assert_nil digits.digit_char(invalid_digit_value)
|
35
|
+
end
|
36
|
+
invalid_chars = %w(- / & ñ)
|
37
|
+
if b < MAX_TEST_BASE
|
38
|
+
(b+1...MAX_TEST_BASE).each do |i|
|
39
|
+
invalid_chars << DEFAULT_DIGITS[i]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
invalid_chars.each do |invalid_digit_char|
|
43
|
+
assert_nil digits.digit_value(invalid_digit_char)
|
44
|
+
assert !digits.is_digit?(invalid_digit_char)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_digits_definition
|
49
|
+
(0..MAX_TEST_BASE).each do |base|
|
50
|
+
check_base base, define_from_digits(base)
|
51
|
+
check_base base, define_from_base(base)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_digits_case
|
56
|
+
uppercase_digits = DigitsDefinition[base: 16, downcase: false]
|
57
|
+
|
58
|
+
assert_equal 10, uppercase_digits.digit_value('A')
|
59
|
+
assert_equal 11, uppercase_digits.digit_value('B')
|
60
|
+
assert_equal 15, uppercase_digits.digit_value('F')
|
61
|
+
|
62
|
+
assert_equal 10, uppercase_digits.digit_value('a')
|
63
|
+
assert_equal 11, uppercase_digits.digit_value('b')
|
64
|
+
assert_equal 15, uppercase_digits.digit_value('f')
|
65
|
+
|
66
|
+
assert_equal 'A', uppercase_digits.digit_char(10)
|
67
|
+
assert_equal 'B', uppercase_digits.digit_char(11)
|
68
|
+
assert_equal 'F', uppercase_digits.digit_char(15)
|
69
|
+
|
70
|
+
downcase_digits = DigitsDefinition[base: 16, downcase: true]
|
71
|
+
|
72
|
+
assert_equal 10, downcase_digits.digit_value('A')
|
73
|
+
assert_equal 11, downcase_digits.digit_value('B')
|
74
|
+
assert_equal 15, downcase_digits.digit_value('F')
|
75
|
+
|
76
|
+
assert_equal 10, downcase_digits.digit_value('a')
|
77
|
+
assert_equal 11, downcase_digits.digit_value('b')
|
78
|
+
assert_equal 15, downcase_digits.digit_value('f')
|
79
|
+
|
80
|
+
assert_equal 'a', downcase_digits.digit_char(10)
|
81
|
+
assert_equal 'b', downcase_digits.digit_char(11)
|
82
|
+
assert_equal 'f', downcase_digits.digit_char(15)
|
83
|
+
|
84
|
+
|
85
|
+
cs_uppercase_digits = DigitsDefinition[base: 16, downcase: false, case_sensitive: true]
|
86
|
+
|
87
|
+
assert_equal 10, cs_uppercase_digits.digit_value('A')
|
88
|
+
assert_equal 11, cs_uppercase_digits.digit_value('B')
|
89
|
+
assert_equal 15, cs_uppercase_digits.digit_value('F')
|
90
|
+
assert_nil cs_uppercase_digits.digit_value('a')
|
91
|
+
assert_nil cs_uppercase_digits.digit_value('b')
|
92
|
+
assert_nil cs_uppercase_digits.digit_value('f')
|
93
|
+
assert_equal 'A', cs_uppercase_digits.digit_char(10)
|
94
|
+
assert_equal 'B', cs_uppercase_digits.digit_char(11)
|
95
|
+
assert_equal 'F', cs_uppercase_digits.digit_char(15)
|
96
|
+
|
97
|
+
cs_downcase_digits = DigitsDefinition[base: 16, downcase: true, case_sensitive: true]
|
98
|
+
|
99
|
+
assert_equal 10, cs_downcase_digits.digit_value('a')
|
100
|
+
assert_equal 11, cs_downcase_digits.digit_value('b')
|
101
|
+
assert_equal 15, cs_downcase_digits.digit_value('f')
|
102
|
+
assert_nil cs_downcase_digits.digit_value('A')
|
103
|
+
assert_nil cs_downcase_digits.digit_value('B')
|
104
|
+
assert_nil cs_downcase_digits.digit_value('F')
|
105
|
+
assert_equal 'a', cs_downcase_digits.digit_char(10)
|
106
|
+
assert_equal 'b', cs_downcase_digits.digit_char(11)
|
107
|
+
assert_equal 'f', cs_downcase_digits.digit_char(15)
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'helper.rb'))
|
2
|
+
|
3
|
+
require 'numerals'
|
4
|
+
include Numerals
|
5
|
+
|
6
|
+
class TestFloatConversions < Test::Unit::TestCase # < Minitest::Test
|
7
|
+
|
8
|
+
def test_special
|
9
|
+
assert_equal Numeral.nan, Conversions.number_to_numeral(Float.context.nan)
|
10
|
+
assert_equal Numeral.nan, Conversions.number_to_numeral(Float.context.nan, :fixed, Rounding[:exact, base: 2])
|
11
|
+
assert_equal Numeral.nan, Conversions.number_to_numeral(Float.context.nan, :fixed, Rounding[:exact, base: 10])
|
12
|
+
assert_equal Numeral.nan, Conversions.number_to_numeral(Float.context.nan, :fixed, Rounding[precision: 10, base: 10])
|
13
|
+
assert_equal Numeral.nan, Conversions.number_to_numeral(Float.context.nan, :free)
|
14
|
+
|
15
|
+
assert_equal Numeral.infinity, Conversions.number_to_numeral(Float.context.infinity)
|
16
|
+
assert_equal Numeral.infinity, Conversions.number_to_numeral(Float.context.infinity, :fixed, Rounding[:exact, base: 2])
|
17
|
+
assert_equal Numeral.infinity, Conversions.number_to_numeral(Float.context.infinity, :fixed, Rounding[:exact, base: 10])
|
18
|
+
assert_equal Numeral.infinity, Conversions.number_to_numeral(Float.context.infinity, :fixed, Rounding[precision: 10, base: 10])
|
19
|
+
assert_equal Numeral.infinity, Conversions.number_to_numeral(Float.context.infinity, :free)
|
20
|
+
|
21
|
+
assert_equal Numeral.infinity(-1), Conversions.number_to_numeral(Float.context.infinity(-1))
|
22
|
+
assert_equal Numeral.infinity(-1), Conversions.number_to_numeral(Float.context.infinity(-1), :fixed, Rounding[:exact, base: 2])
|
23
|
+
assert_equal Numeral.infinity(-1), Conversions.number_to_numeral(Float.context.infinity(-1), :fixed, Rounding[:exact, base: 10])
|
24
|
+
assert_equal Numeral.infinity(-1), Conversions.number_to_numeral(Float.context.infinity(-1), :fixed, Rounding[precision: 10, base: 10])
|
25
|
+
assert_equal Numeral.infinity(-1), Conversions.number_to_numeral(Float.context.infinity(-1), :free)
|
26
|
+
|
27
|
+
assert Conversions.numeral_to_number(Numeral.nan, Float).nan?
|
28
|
+
assert_equal Float.context.infinity, Conversions.numeral_to_number(Numeral.infinity, Float)
|
29
|
+
assert_equal Float.context.infinity(-1), Conversions.numeral_to_number(Numeral.infinity(-1), Float)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_exact
|
33
|
+
assert_equal Numeral[1,point:1], Conversions.number_to_numeral(1.0, :fixed, Rounding[:exact, base: 10])
|
34
|
+
assert_equal Numeral[1,point:1, sign: -1], Conversions.number_to_numeral(-1.0, :fixed, Rounding[:exact, base: 10])
|
35
|
+
|
36
|
+
assert_equal Numeral[1,point:1, base: 2], Conversions.number_to_numeral(1.0, :fixed, Rounding[:exact, base: 2])
|
37
|
+
assert_equal Numeral[1,point:1, sign: -1, base: 2], Conversions.number_to_numeral(-1.0, :fixed, Rounding[:exact, base: 2])
|
38
|
+
|
39
|
+
[0.1, 0.01, 0.001, 1/3.0, 10/3.0, 100/3.0, Math::PI, 0.5, 123.0, 123.45, 1.23E32, 1.23E-32].each do |x|
|
40
|
+
[x, -x].each do |y|
|
41
|
+
numeral = exact_decimal(y)
|
42
|
+
tmp = Conversions.number_to_numeral(y, :fixed, Rounding[:exact, base: 10])
|
43
|
+
assert_equal numeral, Conversions.number_to_numeral(y, :fixed, Rounding[:exact, base: 10]), "#{y} to base 10 exact numeral"
|
44
|
+
assert_equal y, Conversions.numeral_to_number(numeral, Float), "#{x} base 10 numeral to float"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def exact_decimal(x)
|
50
|
+
Flt::DecNum.context(exact: true){
|
51
|
+
Flt::BinNum.context(Flt::BinNum::FloatContext){
|
52
|
+
d = Flt::BinNum(x).to_decimal_exact
|
53
|
+
Numeral[d.coefficient.to_s.chars.map(&:to_i), sign: d.sign, point: d.fractional_exponent, normalize: :exact]
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|