ruby-decimal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ == 0.1.0 2009-06-19
2
+
3
+ * Initial release
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Javier Goizueta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,24 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/decimal.rb
7
+ lib/decimal/version.rb
8
+ lib/decimal/decimal.rb
9
+ lib/decimal/support.rb
10
+ setup.rb
11
+ test/all_tests.rb
12
+ test/helper.rb
13
+ test/test_basic.rb
14
+ test/test_coercion.rb
15
+ test/test_comparisons.rb
16
+ test/test_define_conversions.rb
17
+ test/test_flags.rb
18
+ test/test_multithreading.rb
19
+ test/test_dectest.rb
20
+ test/test_round.rb
21
+ test/test_exact.rb
22
+ test/test_to_int.rb
23
+ test/test_to_rf.rb
24
+
@@ -0,0 +1,306 @@
1
+ = Introduction
2
+
3
+ Decimal is a standards-compliant arbitrary precision decimal floating-point type for Ruby.
4
+ It is based on the Python Decimal class.
5
+
6
+ The current implementation is written completely in Ruby, so it is rather slow.
7
+ The intentention is to experiment with this pure-ruby implementation to
8
+ define a nice feature-set and API for Decimal and have a good test suite for its
9
+ specification. Then an efficient implementation could be written, for example
10
+ by using a C extension wrapper around the decNumber library.
11
+
12
+ == Standars compliance.
13
+
14
+ Decimal pretends to be conformant to the General Decimal Arithmetic Specification
15
+ and the revised IEEE 754 standard (IEEE 754-2008).
16
+
17
+ = Examples of use
18
+
19
+ To install the library use gem from the command line: (you may not need sudo)
20
+ sudo gem install ruby-decimal
21
+
22
+ Then require the library in your code:
23
+ require 'decimal'
24
+
25
+ Now we can use the Decimal class simply like this:
26
+
27
+ puts Decimal(1)/Decimal(3) -> 0.3333333333333333333333333333
28
+
29
+ Decimal() is a constructor that can be used instead of Decimal.new()
30
+
31
+ == Contexts
32
+
33
+ Contexts are environments for arithmetic operations. They govern precision, set rules
34
+ for rounding, determine which signals are treated as exceptions, and limit the range
35
+ for exponents.
36
+
37
+ Each thread has an active context that can be accessed like this:
38
+
39
+ puts Decimal.context.precision -> 28
40
+
41
+ The active context can be globally for the current thread:
42
+
43
+ Decimal.context.precision = 2
44
+ puts Decimal.context.precision -> 2
45
+ puts Decimal(1)/Decimal(3) -> 0.33
46
+ Decimal.context.precision += 7
47
+ puts Decimal.context.precision -> 9
48
+ puts Decimal(1)/Decimal(3) -> 0.333333333
49
+
50
+ Or it can be altered locally inside a block:
51
+
52
+ Decimal.context do
53
+ Decimal.context.precision = 5
54
+ puts Decimal.context.precision
55
+ end -> 5
56
+ puts Decimal.context.precision -> 9
57
+
58
+ The block for a local context can be passed the current context as an argument:
59
+
60
+ Decimal.context do |local_context|
61
+ local_context.precision = 5
62
+ puts Decimal.context.precision
63
+ end -> 5
64
+ puts Decimal.context.precision -> 9
65
+
66
+ A context object can be used to define the local context:
67
+
68
+ my_context = Decimal::Context(:precision=>20)
69
+ Decimal.context(my_context) do |context|
70
+ puts context.precision
71
+ end -> 20
72
+
73
+ And individual parameters can be assigned like this:
74
+
75
+ puts Decimal.context.precision -> 9
76
+ puts Decimal.context.rounding -> half_even
77
+ Decimal.context(:rounding=>:down) do |context|
78
+ puts context.precision
79
+ puts context.rounding
80
+ end
81
+
82
+ Contexts created with the Decimal::Context() constructor
83
+ inherit from Decimal::DefaultContext.
84
+ Default context attributes can be established by modifying
85
+ that object:
86
+
87
+ Decimal::DefaultContext.precision = 10
88
+ Decimal.context = Decimal::Context(:rounding=>:half_up)
89
+ puts Decimal.context.precision -> 10
90
+
91
+ Note that a context object assigned to Decimal.context is copied,
92
+ so it is not altered through Decimal.context:
93
+
94
+ puts my_context.precision -> 20
95
+ Decimal.context = my_context
96
+ Decimal.context.precision = 2
97
+ puts my_context.precision -> 20
98
+
99
+ So, DefaultContext is not altered when modifying Decimal.context.
100
+
101
+ Methods that use a context have an optional parameter to override
102
+ the active context (Decimal.context) :
103
+
104
+ Decimal.context.precision = 3
105
+ puts Decimal(1).divide(3) -> 0.333
106
+ puts Decimal(1).divide(3, my_context) -> 0.33333333333333333333
107
+
108
+ Individual context parameters can also be overriden:
109
+
110
+ puts Decimal(1).divide(3, :precision=>6) -> 0.333333
111
+
112
+ There are two additional predefined contexts Decimal::ExtendedContext
113
+ and Decimal::BasicContext that are not meant to be modified; they
114
+ can be used to achieve reproducible results. We will use
115
+ Decimal::ExtendedContext in the following examples:
116
+
117
+ Decimal.context = Decimal::ExtendedContext
118
+
119
+ ==Rounding
120
+
121
+ Results are normally rounded using the precision (number of significant digits)
122
+ and rounding mode defined in the context.
123
+
124
+ Decimal.context.precision = 4
125
+ puts Decimal(1)/Decimal(3) -> 0.3333
126
+ puts Decimal('1E20')-Decimal('1E-20') -> 1.000E+20
127
+ Decimal.context.rounding = :half_up
128
+ puts +Decimal('100.05') -> 100.1
129
+ Decimal.context.rounding = :half_even
130
+ puts +Decimal('100.05') -> 100.0
131
+
132
+ Note that input values are not rounded, only results; we use
133
+ the plus operator to force rounding here:
134
+
135
+ Decimal.context.precision = 4
136
+ x = Decimal('123.45678')
137
+ puts x -> 123.45678
138
+ puts +x -> 123.5
139
+
140
+ Precision can be also set to exact to avoid rounding, by using
141
+ the exact property or using a 0 precision. In exact mode results
142
+ are never rounded and results that have an infinite number of
143
+ digits trigger the Decimal::Inexact exception.
144
+
145
+ Decimal.context.exact = true
146
+ puts Decimal('1E20')-Decimal('1E-20') -> 99999999999999999999.99999999999999999999
147
+ puts Decimal(16).sqrt -> 4
148
+ puts Decimal(16)/Decimal(4) -> 4
149
+ puts Decimal(1)/Decimal(3) -> Exception : Decimal::Inexact
150
+
151
+ Decimal.context.precision = 5
152
+ puts Decimal('1E20')-Decimal('1E-20') -> 1.0000E+20
153
+ puts Decimal(16).sqrt -> 4
154
+ puts Decimal(16)/Decimal(4) -> 4
155
+ puts Decimal(1)/Decimal(3) -> 0.33333
156
+
157
+ There are also some methods for explicit rounding that provide
158
+ an interface compatible with the Ruby interface of Float:
159
+
160
+ puts Decimal('101.5').round -> 102
161
+ puts Decimal('101.5').round(0) -> 102
162
+ puts Decimal('101.12345').round(2) -> 101.12
163
+ puts Decimal('101.12345').round(-1) -> 1.0E+2
164
+ puts Decimal('101.12345').round(:places=>2) -> 101.12
165
+ puts Decimal('101.12345').round(:precision=>2) -> 1.0E+2
166
+ puts Decimal('101.5').round(:rounding=>:half_up) -> 102
167
+ puts Decimal('101.5').ceil -> 102
168
+ puts Decimal('101.5').floor -> 101
169
+ puts Decimal('101.5').truncate -> 101
170
+
171
+ ==Special values
172
+ TODO
173
+
174
+ ==Exceptions
175
+ TODO
176
+
177
+ ==Numerical conversion
178
+
179
+ By default, Decimal is interoperable with Integer and Rational.
180
+ Conversion happens automatically to operands:
181
+
182
+ puts Decimal('0.1') + 1 -> 1.1
183
+ puts 7 + Decimal('0.2') -> 7.2
184
+ puts Rational(5,2) + Decimal('3') -> 5.5
185
+
186
+ Conversion can also be done explicitely with
187
+ the Decimal constructor:
188
+
189
+ puts Decimal(7) -> 7
190
+ puts Decimal(Rational(1,10)) -> 0.1
191
+
192
+ Converting a Decimal to other numerical types can be done with specific Ruby-style methods.
193
+
194
+ puts Decimal('1.1').to_i -> 1
195
+ puts Decimal('1.1').to_r -> 11/10
196
+
197
+ (note the truncated result of to_i)
198
+ Or with a generic method:
199
+ puts Decimal('1.1').convert_to(Integer) -> 1
200
+ puts Decimal('1.1').convert_to(Rational) -> 11/10
201
+
202
+ Conversion is also possible to Float:
203
+ puts Decimal('1.1').to_f -> 1.1
204
+ puts Decimal('1.1').convert_to(Float) -> 1.1
205
+
206
+ And with GDAS style operations:
207
+
208
+ puts Decimal('1.1').to_integral_value -> 1
209
+
210
+ The conversion system is extensible. For example, we can include BigDecimal into it
211
+ by defining suitable conversion procedures:
212
+
213
+ Decimal.context.define_conversion_from(BigDecimal) do |x, context|
214
+ Decimal(x.to_s)
215
+ end
216
+ Decimal.context.define_conversion_to(BigDecimal) do |x|
217
+ BigDecimal.new(x.to_s)
218
+ end
219
+
220
+ Now we can mix BigDecimals and Decimals in expressions and convert from Decimal
221
+ to BigDecimal:
222
+
223
+ puts BigDecimal.new('1.1') + Decimal('2.2') -> 3.3
224
+ puts Decimal('1.1').convert_to(BigDecimal) -> 0.11E1
225
+
226
+ Note that the conversions are defined in a Context object and will be available only
227
+ when that context applies. That way we can define conversions for specific purposes
228
+ without affecting a program globally.
229
+
230
+ As another example consider conversion from Float to Decimal, which is not defined by
231
+ default because it can be defined in different ways depending on the purpose.
232
+
233
+ A Float constant such as 0.1 defines a Float object which has a numerical value close to,
234
+ but not exactly 1/10. When converting that Float to Decimal we could decide to preserver
235
+ the exact numerical value of the number or try to find a simple decimal expression within
236
+ a given tolerance. If we take the first approach we can define this conversion:
237
+
238
+ Decimal.context.define_conversion_from(Float) do |x, context|
239
+ s,e = Math.frexp(x)
240
+ s = Math.ldexp(s, Float::MANT_DIG).to_i
241
+ e -= Float::MANT_DIG
242
+ Decimal(s*(Float::RADIX**e))
243
+ end
244
+
245
+ Note that the conversion we've defined depends on the context precision:
246
+
247
+ Decimal.local_context(:precision=>20) { puts Decimal(0.1) } -> 0.10000000000000000555
248
+
249
+ Decimal.local_context(:precision=>12) { puts Decimal(0.1) } -> 0.100000000000
250
+
251
+ == Available functionality
252
+
253
+ Consult the documentation for the classes Decimal and Decimal::Context.
254
+
255
+ = Decimal vs BigDecimal
256
+
257
+ --
258
+ EXPAND-
259
+ ++
260
+
261
+ Decimal solves some of the difficulties of using BigDecimal.
262
+
263
+ One of the major problems with BigDecimal is that it's not easy to control the number of
264
+ significant digits: while addition, subtraction and multiplication are exact (unless a limit is used),
265
+ divisions will need to be passed precision explicitly or they will loose an indeterminate number of digits.
266
+ With Decimal, Context objects are used to specify the exact number of digits to be used for all operations:
267
+ Decimal.context.precision = 10
268
+ puts Decimal(1)/Decimal(3)
269
+ Contexts are thread-safe and can be used for individual operations:
270
+ puts Decimal(1).divide(Decimal(e), Decimal::Context.new(:precision=>4))
271
+ Or use locally in a block without affecting other code:
272
+ Decimal.local_context {
273
+ Decimal.context.precision = 3
274
+ puts Decimal(1)/Decimal(3)
275
+ }
276
+ puts Decimal.context.precision
277
+
278
+ This allows in general to write simpler code; e.g. this is an exponential function, adapted from the
279
+ 'recipes' in Python's Decimal:
280
+ def exp(x,c=nil)
281
+ i, lasts, s, fact, num = 0, 0, 1, 1, 1
282
+ Decimal.local_context(c) do |context|
283
+ context.precision += 2
284
+ while s != lasts
285
+ lasts = s
286
+ i += 1
287
+ fact *= i
288
+ num *= x
289
+ s += num / fact
290
+ end
291
+ end
292
+ return +s
293
+ end
294
+ The final unary + applied to the result forces it to be rounded to the current precision
295
+ (because we have computed it with two extra digits)
296
+ The result of this method does not have trailing insignificant digits, as is common with BigDecimal.
297
+
298
+ --
299
+ EXPAND+
300
+ ++
301
+
302
+ = Roadmap
303
+
304
+ * Complete documentation (README sections on special values & exceptions, etc. and method descriptions.)
305
+ * Version 0.2.0: Implement GDAS exp(), power(), ln() log10() and also the Ruby-style operator **.
306
+ * Version 0.3.0:
@@ -0,0 +1,35 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ load 'tasks/setup.rb'
10
+ end
11
+
12
+ ensure_in_path 'lib'
13
+ #require 'decimal'
14
+ require 'decimal/version'
15
+
16
+ task :default => 'spec:run'
17
+
18
+
19
+ PROJ.name = 'ruby-decimal'
20
+ PROJ.description = "Ruby Decimal Type"
21
+ PROJ.authors = 'Javier Goizueta'
22
+ PROJ.email = 'javier@goizueta.info'
23
+ PROJ.version = DecimalSupport::VERSION::STRING
24
+ PROJ.rubyforge.name = 'ruby-decimal'
25
+ PROJ.url = "http://#{PROJ.rubyforge.name}.rubyforge.org"
26
+ PROJ.rdoc.opts = [
27
+ "--main", "README.txt",
28
+ '--title', 'Ruby Decimal Documentation',
29
+ "--opname", "index.html",
30
+ "--line-numbers",
31
+ "--inline-source"
32
+ ]
33
+ #PROJ.test.file = 'test/all_tests.rb'
34
+
35
+ # EOF
@@ -0,0 +1,4 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'decimal/support'
4
+ require 'decimal/decimal'
@@ -0,0 +1,2750 @@
1
+ require 'bigdecimal'
2
+ require 'forwardable'
3
+ require 'rational'
4
+ require 'monitor'
5
+ require 'ostruct'
6
+
7
+ # Decimal arbitrary precision floating point number.
8
+ # This implementation of Decimal is based on the Decimal module of Python,
9
+ # written by Eric Price, Facundo Batista, Raymond Hettinger, Aahz and Tim Peters.
10
+ class Decimal
11
+
12
+ extend DecimalSupport # allows use of unqualified FlagValues(), Flags()
13
+
14
+ ROUND_HALF_EVEN = :half_even
15
+ ROUND_HALF_DOWN = :half_down
16
+ ROUND_HALF_UP = :half_up
17
+ ROUND_FLOOR = :floor
18
+ ROUND_CEILING = :ceiling
19
+ ROUND_DOWN = :down
20
+ ROUND_UP = :up
21
+ ROUND_05UP = :up05
22
+
23
+ # Numerical conversion base support
24
+ # base (default) coercible types associated to procedures for numerical conversion
25
+ @base_coercible_types = {
26
+ Integer=>lambda{|x, context| x>=0 ? [+1,x,0] : [-1,-x,0]},
27
+ Rational=>lambda{|x, context|
28
+ x, y = Decimal.new(x.numerator), Decimal.new(x.denominator)
29
+ x.divide(y, context)
30
+ }
31
+ }
32
+ @base_conversions = {
33
+ Integer=>:to_i, Rational=>:to_r, Float=>:to_f
34
+ }
35
+ class <<self
36
+ attr_reader :base_coercible_types
37
+ attr_reader :base_conversions
38
+ end
39
+
40
+ # Numerical base of Decimal.
41
+ def self.radix
42
+ 10
43
+ end
44
+
45
+ # Integral power of the base: radix**n for integer n; returns an integer.
46
+ def self.int_radix_power(n)
47
+ 10**n
48
+ end
49
+
50
+ # Multiply by an integral power of the base: x*(radix**n) for x,n integer;
51
+ # returns an integer.
52
+ def self.int_mult_radix_power(x,n)
53
+ x * (10**n)
54
+ end
55
+
56
+ # Divide by an integral power of the base: x/(radix**n) for x,n integer;
57
+ # returns an integer.
58
+ def self.int_div_radix_power(x,n)
59
+ x / (10**n)
60
+ end
61
+
62
+
63
+ # Base class for errors.
64
+ class Error < StandardError
65
+ end
66
+
67
+ # Base class for exceptions.
68
+ #
69
+ # All exception conditions derive from this class.
70
+ # The exception classes also define the values returned when trapping is disable for
71
+ # a particular exception.
72
+ class Exception < StandardError
73
+ attr :context
74
+ def initialize(context=nil)
75
+ @context = context
76
+ end
77
+
78
+ # Defines the value returned when trapping is inactive
79
+ # for the condition. The arguments are those passed to
80
+ # Context#exception after the message.
81
+ def self.handle(context, *args)
82
+ end
83
+ end
84
+
85
+ # Invalid operation exception.
86
+ #
87
+ # The result of the operation is a quiet positive NaN,
88
+ # except when the cause is a signaling NaN, in which case the result is
89
+ # also a quiet NaN, but with the original sign, and an optional
90
+ # diagnostic information.
91
+ class InvalidOperation < Exception
92
+ def self.handle(context=nil, *args)
93
+ if args.size>0
94
+ sign, coeff, exp = args.first.split
95
+ Decimal.new([sign, coeff, :nan])._fix_nan(context)
96
+ else
97
+ Decimal.nan
98
+ end
99
+ end
100
+ def initialize(context=nil, *args)
101
+ @value = args.first if args.size>0
102
+ super
103
+ end
104
+ end
105
+
106
+ # Division by zero exception.
107
+ #
108
+ # The result of the operation is +/-Infinity, where the sign is the product
109
+ # of the signs of the operands for divide, or 1 for an odd power of -0.
110
+ class DivisionByZero < Exception
111
+ def self.handle(context,sign,*args)
112
+ Decimal.infinity(sign)
113
+ end
114
+ def initialize(context=nil, sign=nil, *args)
115
+ @sign = sign
116
+ super
117
+ end
118
+ end
119
+
120
+ # Cannot perform the division adequately exception.
121
+ #
122
+ # This occurs and signals invalid-operation if the integer result of a
123
+ # divide-integer or remainder operation had too many digits (would be
124
+ # longer than precision).
125
+ # The result is NaN.
126
+ class DivisionImpossible < Exception
127
+ def self.handle(context,*args)
128
+ Decimal.nan
129
+ end
130
+ end
131
+
132
+ # Undefined result of division exception.
133
+ #
134
+ # This occurs and signals invalid-operation if division by zero was
135
+ # attempted (during a divide-integer, divide, or remainder operation), and
136
+ # the dividend is also zero.
137
+ # The result is NaN.
138
+ class DivisionUndefined < Exception
139
+ def self.handle(context,*args)
140
+ Decimal.nan
141
+ end
142
+ end
143
+
144
+ # Inexact Exception.
145
+ #
146
+ # This occurs and signals inexact whenever the result of an operation is
147
+ # not exact (that is, it needed to be rounded and any discarded digits
148
+ # were non-zero), or if an overflow or underflow condition occurs. The
149
+ # result in all cases is unchanged.
150
+ class Inexact < Exception
151
+ end
152
+
153
+ # Overflow Exception.
154
+ #
155
+ # This occurs and signals overflow if the adjusted exponent of a result
156
+ # (from a conversion or from an operation that is not an attempt to divide
157
+ # by zero), after rounding, would be greater than the largest value that
158
+ # can be handled by the implementation (the value Emax).
159
+ #
160
+ # The result depends on the rounding mode:
161
+ #
162
+ # For round-half-up and round-half-even (and for round-half-down and
163
+ # round-up, if implemented), the result of the operation is +/-Infinity,
164
+ # where the sign is that of the intermediate result. For round-down, the
165
+ # result is the largest finite number that can be represented in the
166
+ # current precision, with the sign of the intermediate result. For
167
+ # round-ceiling, the result is the same as for round-down if the sign of
168
+ # the intermediate result is 1, or is +Infinity otherwise. For round-floor,
169
+ # the result is the same as for round-down if the sign of the intermediate
170
+ # result is 0, or is -Infinity otherwise. In all cases, Inexact and Rounded
171
+ # will also be raised.
172
+ class Overflow < Exception
173
+ def self.handle(context, sign, *args)
174
+ if [:half_up, :half_even, :half_down, :up].include?(context.rounding)
175
+ Decimal.infinity(sign)
176
+ elsif sign==+1
177
+ if context.rounding == :ceiling
178
+ Decimal.infinity(sign)
179
+ else
180
+ Decimal.new([sign, Decimal.int_radix_power(context.precision) - 1, context.emax - context.precision + 1])
181
+ end
182
+ elsif sign==-1
183
+ if context.rounding == :floor
184
+ Decimal.infinity(sign)
185
+ else
186
+ Decimal.new([sign, Decimal.int_radix_power(context.precision) - 1, context.emax - context.precision + 1])
187
+ end
188
+ end
189
+ end
190
+ def initialize(context=nil, sign=nil, *args)
191
+ @sign = sign
192
+ super
193
+ end
194
+ end
195
+
196
+ # Numerical Underflow with result rounded to 0 exception.
197
+ #
198
+ # This occurs and signals underflow if a result is inexact and the
199
+ # adjusted exponent of the result would be smaller (more negative) than
200
+ # the smallest value that can be handled by the implementation (the value
201
+ # emin). That is, the result is both inexact and subnormal.
202
+ #
203
+ # The result after an underflow will be a subnormal number rounded, if
204
+ # necessary, so that its exponent is not less than Etiny. This may result
205
+ # in 0 with the sign of the intermediate result and an exponent of etiny.
206
+ #
207
+ # In all cases, Inexact, Rounded, and Subnormal will also be raised.
208
+ class Underflow < Exception
209
+ end
210
+
211
+ # Clamped exception: exponent of a 0 changed to fit bounds.
212
+ #
213
+ # This occurs and signals clamped if the exponent of a result has been
214
+ # altered in order to fit the constraints of a specific concrete
215
+ # representation. This may occur when the exponent of a zero result would
216
+ # be outside the bounds of a representation, or when a large normal
217
+ # number would have an encoded exponent that cannot be represented. In
218
+ # this latter case, the exponent is reduced to fit and the corresponding
219
+ # number of zero digits are appended to the coefficient ("fold-down").
220
+ class Clamped < Exception
221
+ end
222
+
223
+ # Invalid context exception.
224
+ #
225
+ # This occurs and signals invalid-operation if an invalid context was
226
+ # detected during an operation. This can occur if contexts are not checked
227
+ # on creation and either the precision exceeds the capability of the
228
+ # underlying concrete representation or an unknown or unsupported rounding
229
+ # was specified. These aspects of the context need only be checked when
230
+ # the values are required to be used. The result is NaN.
231
+ class InvalidContext < Exception
232
+ def self.handle(context,*args)
233
+ Decimal.nan
234
+ end
235
+ end
236
+
237
+ # Number got rounded exception (not necessarily changed during rounding).
238
+ #
239
+ # This occurs and signals rounded whenever the result of an operation is
240
+ # rounded (that is, some zero or non-zero digits were discarded from the
241
+ # coefficient), or if an overflow or underflow condition occurs. The
242
+ # result in all cases is unchanged.
243
+ class Rounded < Exception
244
+ end
245
+
246
+ # Exponent < emin before rounding exception.
247
+ #
248
+ # This occurs and signals subnormal whenever the result of a conversion or
249
+ # operation is subnormal (that is, its adjusted exponent is less than
250
+ # Emin, before any rounding). The result in all cases is unchanged.
251
+ class Subnormal < Exception
252
+ end
253
+
254
+ # Conversion syntax error exception (Trying to convert badly formed string.)
255
+ #
256
+ # This occurs and signals invalid-operation if an string is being
257
+ # converted to a number and it does not conform to the numeric string
258
+ # syntax. The result is NaN.
259
+ class ConversionSyntax < InvalidOperation
260
+ def self.handle(context, *args)
261
+ Decimal.nan
262
+ end
263
+ end
264
+
265
+ EXCEPTIONS = FlagValues(Clamped, InvalidOperation, DivisionByZero, Inexact, Overflow, Underflow,
266
+ Rounded, Subnormal, DivisionImpossible, ConversionSyntax)
267
+
268
+ def self.Flags(*values)
269
+ DecimalSupport::Flags(EXCEPTIONS,*values)
270
+ end
271
+
272
+ # The context defines the arithmetic context: rounding mode, precision,...
273
+ # Decimal.context is the current (thread-local) context.
274
+ class Context
275
+
276
+ # If an options hash is passed, the options are
277
+ # applied to the default context; if a Context is passed as the first
278
+ # argument, it is used as the base instead of the default context.
279
+ #
280
+ # The valid options are:
281
+ # * :rounding : one of :half_even, :half_down, :half_up, :floor,
282
+ # :ceiling, :down, :up, :up05
283
+ # * :precision : number of digits (or 0 for exact precision)
284
+ # * :exact : true or false (precision is ignored when true)
285
+ # * :traps : a Flags object with the exceptions to be trapped
286
+ # * :flags : a Flags object with the raised flags
287
+ # * :ignored_flags : a Flags object with the exceptions to be ignored
288
+ # * :emin, :emax : minimum and maximum exponents
289
+ # * :capitals : (true or false) to use capitals in text representations
290
+ # * :clamp : (true or false) enables clamping
291
+ #
292
+ # See also the context constructor method Decimal.Context().
293
+ def initialize(*options)
294
+
295
+ if options.first.instance_of?(Context)
296
+ base = options.shift
297
+ copy_from base
298
+ else
299
+ @ignored_flags = Decimal::Flags()
300
+ @traps = Decimal::Flags()
301
+ @flags = Decimal::Flags()
302
+ @coercible_type_handlers = Decimal.base_coercible_types.dup
303
+ @conversions = Decimal.base_conversions.dup
304
+ end
305
+ assign options.first
306
+
307
+ end
308
+
309
+ attr_accessor :rounding, :emin, :emax, :flags, :traps, :ignored_flags, :capitals, :clamp
310
+
311
+ # Ignore all flags if they are raised
312
+ def ignore_all_flags
313
+ #@ignored_flags << EXCEPTIONS
314
+ @ignored_flags.set!
315
+ end
316
+
317
+ # Ignore a specified set of flags if they are raised
318
+ def ignore_flags(*flags)
319
+ #@ignored_flags << flags
320
+ @ignored_flags.set(*flags)
321
+ end
322
+
323
+ # Stop ignoring a set of flags, if they are raised
324
+ def regard_flags(*flags)
325
+ @ignored_flags.clear(*flags)
326
+ end
327
+
328
+ # 'tiny' exponet (emin - precision + 1)
329
+ def etiny
330
+ emin - precision + 1
331
+ end
332
+
333
+ # maximum exponent (emax - precision + 1)
334
+ def etop
335
+ emax - precision + 1
336
+ end
337
+
338
+ # synonym for precision()
339
+ def digits
340
+ self.precision
341
+ end
342
+
343
+ # synonym for precision=()
344
+ def digits=(n)
345
+ self.precision=n
346
+ end
347
+
348
+ # synonym for precision()
349
+ def prec
350
+ self.precision
351
+ end
352
+
353
+ # synonym for precision=()
354
+ def prec=(n)
355
+ self.precision = n
356
+ end
357
+
358
+ # is clamping enabled?
359
+ def clamp?
360
+ @clamp
361
+ end
362
+
363
+ # Set the number of digits of precision.
364
+ # If 0 is set the precision turns to be exact.
365
+ def precision=(n)
366
+ @precision = n
367
+ @exact = false unless n==0
368
+ update_precision
369
+ n
370
+ end
371
+
372
+ # Number of digits of precision
373
+ def precision
374
+ @precision
375
+ end
376
+
377
+ # Enables or disables the exact precision
378
+ def exact=(v)
379
+ @exact = v
380
+ update_precision
381
+ v
382
+ end
383
+
384
+ # Returns true if the precision is exact
385
+ def exact
386
+ @exact
387
+ end
388
+
389
+ # Returns true if the precision is exact
390
+ def exact?
391
+ @exact
392
+ end
393
+
394
+ # Alters the contexts by assigning options from a Hash. See Decimal#new() for the valid options.
395
+ def assign(options)
396
+ if options
397
+ @rounding = options[:rounding] unless options[:rounding].nil?
398
+ @precision = options[:precision] unless options[:precision].nil?
399
+ @traps = Decimal::Flags(options[:traps]) unless options[:traps].nil?
400
+ @flags = Decimal::Flags(options[:flags]) unless options[:flags].nil?
401
+ @ignored_flags = Decimal::Flags(options[:ignored_flags]) unless options[:ignored_flags].nil?
402
+ @emin = options[:emin] unless options[:emin].nil?
403
+ @emax = options[:emax] unless options[:emax].nil?
404
+ @capitals = options[:capitals ] unless options[:capitals ].nil?
405
+ @clamp = options[:clamp ] unless options[:clamp ].nil?
406
+ @exact = options[:exact ] unless options[:exact ].nil?
407
+ update_precision
408
+ end
409
+ end
410
+
411
+ attr_reader :coercible_type_handlers, :conversions
412
+ protected :coercible_type_handlers, :conversions
413
+
414
+ # Copy the state from other Context object.
415
+ def copy_from(other)
416
+ @rounding = other.rounding
417
+ @precision = other.precision
418
+ @traps = other.traps.dup
419
+ @flags = other.flags.dup
420
+ @ignored_flags = other.ignored_flags.dup
421
+ @emin = other.emin
422
+ @emax = other.emax
423
+ @capitals = other.capitals
424
+ @clamp = other.clamp
425
+ @exact = other.exact
426
+ @coercible_type_handlers = other.coercible_type_handlers.dup
427
+ @conversions = other.conversions.dup
428
+ end
429
+
430
+ def dup
431
+ Context.new(self)
432
+ end
433
+
434
+ CONDITION_MAP = {
435
+ #ConversionSyntax=>InvalidOperation,
436
+ #DivisionImpossible=>InvalidOperation,
437
+ DivisionUndefined=>InvalidOperation,
438
+ InvalidContext=>InvalidOperation
439
+ }
440
+
441
+ # Raises a flag (unless it is being ignores) and raises and
442
+ # exceptioin if the trap for it is enabled.
443
+ def exception(cond, msg='', *params)
444
+ err = (CONDITION_MAP[cond] || cond)
445
+ return err.handle(self, *params) if @ignored_flags[err]
446
+ @flags << err # @flags[err] = true
447
+ return cond.handle(self, *params) if !@traps[err]
448
+ raise err.new(*params), msg
449
+ end
450
+
451
+ # Addition of two decimal numbers
452
+ def add(x,y)
453
+ Decimal._convert(x).add(y,self)
454
+ end
455
+
456
+ # Subtraction of two decimal numbers
457
+ def subtract(x,y)
458
+ Decimal._convert(x).subtract(y,self)
459
+ end
460
+
461
+ # Multiplication of two decimal numbers
462
+ def multiply(x,y)
463
+ Decimal._convert(x).multiply(y,self)
464
+ end
465
+
466
+ # Division of two decimal numbers
467
+ def divide(x,y)
468
+ Decimal._convert(x).divide(y,self)
469
+ end
470
+
471
+ # Absolute value of a decimal number
472
+ def abs(x)
473
+ Decimal._convert(x).abs(self)
474
+ end
475
+
476
+ # Unary prefix plus operator
477
+ def plus(x)
478
+ Decimal._convert(x).plus(self)
479
+ end
480
+
481
+ # Unary prefix minus operator
482
+ def minus(x)
483
+ Decimal._convert(x)._neg(self)
484
+ end
485
+
486
+ # Converts a number to a string
487
+ def to_string(x, eng=false)
488
+ Decimal._convert(x)._fix(self).to_s(eng, self)
489
+ end
490
+
491
+ # Converts a number to a string, using scientific notation
492
+ def to_sci_string(x)
493
+ to_string x, false
494
+ end
495
+
496
+ # Converts a number to a string, using engineering notation
497
+ def to_eng_string(x)
498
+ to_string x, true
499
+ end
500
+
501
+ # Reduces an operand to its simplest form
502
+ # by removing trailing 0s and incrementing the exponent.
503
+ # (formerly called normalize in GDAS)
504
+ def reduce(x)
505
+ Decimal._convert(x).reduce(self)
506
+ end
507
+
508
+ # Adjusted exponent of x returned as a Decimal value.
509
+ def logb(x)
510
+ Decimal._convert(x).logb(self)
511
+ end
512
+
513
+ # Adds the second value to the exponent of the first: x*(radix**y)
514
+ #
515
+ # y must be an integer
516
+ def scaleb(x, y)
517
+ Decimal._convert(x).scaleb(y,self)
518
+ end
519
+
520
+
521
+ # Exponent in relation to the significand as an integer
522
+ # normalized to precision digits. (minimum exponent)
523
+ def normalized_integral_exponent(x)
524
+ x = Decimal._convert(x)
525
+ x.integral_exponent - (precision - x.number_of_digits)
526
+ end
527
+
528
+ # Significand normalized to precision digits
529
+ # x == normalized_integral_significand(x) * radix**(normalized_integral_exponent)
530
+ def normalized_integral_significand(x)
531
+ x = Decimal._convert(x)
532
+ x.integral_significand*(Decimal.int_radix_power(precision - x.number_of_digits))
533
+ end
534
+
535
+ # Returns both the (signed) normalized integral significand and the corresponding exponent
536
+ def to_normalized_int_scale(x)
537
+ x = Decimal._convert(x)
538
+ [x.sign*normalized_integral_significand(x), normalized_integral_exponent(x)]
539
+ end
540
+
541
+ # Is a normal number?
542
+ def normal?(x)
543
+ Decimal._convert(x).normal?(self)
544
+ end
545
+
546
+ # Is a subnormal number?
547
+ def subnormal?(x)
548
+ Decimal._convert(x).subnormal?(self)
549
+ end
550
+
551
+ # Classifies a number as one of
552
+ # 'sNaN', 'NaN', '-Infinity', '-Normal', '-Subnormal', '-Zero',
553
+ # '+Zero', '+Subnormal', '+Normal', '+Infinity'
554
+ def number_class(x)
555
+ Decimal._convert(x).number_class(self)
556
+ end
557
+
558
+ # Square root of a decimal number
559
+ def sqrt(x)
560
+ Decimal._convert(x).sqrt(self)
561
+ end
562
+
563
+ # Ruby-style integer division: (x/y).floor
564
+ def div(x,y)
565
+ Decimal._convert(x).div(y,self)
566
+ end
567
+
568
+ # Ruby-style modulo: x - y*div(x,y)
569
+ def modulo(x,y)
570
+ Decimal._convert(x).modulo(y,self)
571
+ end
572
+
573
+ # Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
574
+ def divmod(x,y)
575
+ Decimal._convert(x).divmod(y,self)
576
+ end
577
+
578
+ # General Decimal Arithmetic Specification integer division: (x/y).truncate
579
+ def divide_int(x,y)
580
+ Decimal._convert(x).divide_int(y,self)
581
+ end
582
+
583
+ # General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
584
+ def remainder(x,y)
585
+ Decimal._convert(x).remainder(y,self)
586
+ end
587
+
588
+ # General Decimal Arithmetic Specification remainder-near
589
+ # x - y*round_half_even(x/y)
590
+ def remainder_near(x,y)
591
+ Decimal._convert(x).remainder_near(y,self)
592
+ end
593
+
594
+ # General Decimal Arithmetic Specification integer division and remainder:
595
+ # (x/y).truncate, x - y*(x/y).truncate
596
+ def divrem(x,y)
597
+ Decimal._convert(x).divrem(y,self)
598
+ end
599
+
600
+ # Fused multiply-add.
601
+ #
602
+ # Computes (x*y+z) with no rounding of the intermediate product x*y.
603
+ def fma(x,y,z)
604
+ Decimal._convert(x).fma(y,z,self)
605
+ end
606
+
607
+ # Compares like <=> but returns a Decimal value.
608
+ # * -1 if x < y
609
+ # * 0 if x == b
610
+ # * +1 if x > y
611
+ # * NaN if x or y is NaN
612
+ def compare(x,y)
613
+ Decimal._convert(x).compare(y, self)
614
+ end
615
+
616
+ # Returns a copy of x with the sign set to +
617
+ def copy_abs(x)
618
+ Decimal._convert(x).copy_abs
619
+ end
620
+
621
+ # Returns a copy of x with the sign inverted
622
+ def copy_negate(x)
623
+ Decimal._convert(x).copy_negate
624
+ end
625
+
626
+ # Returns a copy of x with the sign of y
627
+ def copy_sign(x,y)
628
+ Decimal._convert(x).copy_sign(y)
629
+ end
630
+
631
+ # Rescale x so that the exponent is exp, either by padding with zeros
632
+ # or by truncating digits.
633
+ def rescale(x, exp, watch_exp=true)
634
+ Decimal._convert(x).rescale(exp, self, watch_exp)
635
+ end
636
+
637
+ # Quantize x so its exponent is the same as that of y.
638
+ def quantize(x, y, watch_exp=true)
639
+ Decimal._convert(x).quantize(y, self, watch_exp)
640
+ end
641
+
642
+ # Return true if x and y have the same exponent.
643
+ #
644
+ # If either operand is a special value, the following rules are used:
645
+ # * return true if both operands are infinities
646
+ # * return true if both operands are NaNs
647
+ # * otherwise, return false.
648
+ def same_quantum?(x,y)
649
+ Decimal._convert(x).same_quantum?(y)
650
+ end
651
+
652
+ # Rounds to a nearby integer.
653
+ #
654
+ # See also: Decimal#to_integral_value(), which does exactly the same as
655
+ # this method except that it doesn't raise Inexact or Rounded.
656
+ def to_integral_exact(x)
657
+ Decimal._convert(x).to_integral_exact(self)
658
+ end
659
+
660
+ # Rounds to a nearby integerwithout raising inexact, rounded.
661
+ #
662
+ # See also: Decimal#to_integral_exact(), which does exactly the same as
663
+ # this method except that it may raise Inexact or Rounded.
664
+ def to_integral_value(x)
665
+ Decimal._convert(x).to_integral_value(self)
666
+ end
667
+
668
+ # Returns the largest representable number smaller than x.
669
+ def next_minus(x)
670
+ Decimal._convert(x).next_minus(self)
671
+ end
672
+
673
+ # Returns the smallest representable number larger than x.
674
+ def next_plus(x)
675
+ Decimal._convert(x).next_plus(self)
676
+ end
677
+
678
+ # Returns the number closest to x, in the direction towards y.
679
+ #
680
+ # The result is the closest representable number to x
681
+ # (excluding x) that is in the direction towards y,
682
+ # unless both have the same value. If the two operands are
683
+ # numerically equal, then the result is a copy of x with the
684
+ # sign set to be the same as the sign of y.
685
+ def next_toward(x, y)
686
+ Decimal._convert(x).next_toward(y, self)
687
+ end
688
+
689
+ def to_s
690
+ inspect
691
+ end
692
+
693
+ def inspect
694
+ "<#{self.class}:\n" +
695
+ instance_variables.map { |v| " #{v}: #{eval(v)}"}.join("\n") +
696
+ ">\n"
697
+ end
698
+
699
+ # Maximum integral significand value for numbers using this context's precision.
700
+ def maximum_significand
701
+ if exact?
702
+ exception(InvalidOperation, 'Exact maximum significand')
703
+ nil
704
+ else
705
+ Decimal.int_radix_power(precision)-1
706
+ end
707
+ end
708
+
709
+ # Maximum number of diagnostic digits in NaNs for numbers using this context's precision.
710
+ def maximum_nan_diagnostic_digits
711
+ if exact?
712
+ nil # ?
713
+ else
714
+ precision - (clamp ? 1 : 0)
715
+ end
716
+ end
717
+
718
+ # Internal use: array of numeric types that be coerced to Decimal.
719
+ def coercible_types
720
+ @coercible_type_handlers.keys
721
+ end
722
+
723
+ # Internal use: array of numeric types that be coerced to Decimal, including Decimal
724
+ def coercible_types_or_decimal
725
+ [Decimal] + coercible_types
726
+ end
727
+
728
+ # Internally used to convert numeric types to Decimal (or to an array [sign,coefficient,exponent])
729
+ def _coerce(x)
730
+ c = x.class
731
+ while c!=Object && (h=@coercible_type_handlers[c]).nil?
732
+ c = c.superclass
733
+ end
734
+ if h
735
+ h.call(x, self)
736
+ else
737
+ nil
738
+ end
739
+ end
740
+
741
+ # Define a numerical conversion from type to Decimal.
742
+ # The block that defines the conversion has two parameters: the value to be converted and the context and
743
+ # must return either a Decimal or [sign,coefficient,exponent]
744
+ def define_conversion_from(type, &blk)
745
+ @coercible_type_handlers[type] = blk
746
+ end
747
+
748
+ # Define a numerical conversion from Decimal to type as an instance method of Decimal
749
+ def define_conversion_to(type, &blk)
750
+ @conversions[type] = blk
751
+ end
752
+
753
+ # Convert a Decimal x to other numerical type
754
+ def convert_to(type, x)
755
+ converter = @conversions[type]
756
+ if converter.nil?
757
+ raise TypeError, "Undefined conversion from Decimal to #{type}."
758
+ elsif converter.is_a?(Symbol)
759
+ x.send converter
760
+ else
761
+ converter.call(x)
762
+ end
763
+ end
764
+
765
+ private
766
+ def update_precision
767
+ if @exact || @precision==0
768
+ @exact = true
769
+ @precision = 0
770
+ @traps << Inexact
771
+ @ignored_flags[Inexact] = false
772
+ else
773
+ @traps[Inexact] = false
774
+ end
775
+ end
776
+
777
+ end
778
+
779
+ # the DefaultContext is the base for new contexts; it can be changed.
780
+ DefaultContext = Decimal::Context.new(
781
+ :exact=>false, :precision=>28, :rounding=>:half_even,
782
+ :emin=> -999999999, :emax=>+999999999,
783
+ :flags=>[],
784
+ :traps=>[DivisionByZero, Overflow, InvalidOperation],
785
+ :ignored_flags=>[],
786
+ :capitals=>true,
787
+ :clamp=>true)
788
+
789
+ BasicContext = Decimal::Context.new(DefaultContext,
790
+ :precision=>9, :rounding=>:half_up,
791
+ :traps=>[DivisionByZero, Overflow, InvalidOperation, Clamped, Underflow],
792
+ :flags=>[])
793
+
794
+ ExtendedContext = Decimal::Context.new(DefaultContext,
795
+ :precision=>9, :rounding=>:half_even,
796
+ :traps=>[], :flags=>[], :clamp=>false)
797
+
798
+ # Context constructor; if an options hash is passed, the options are
799
+ # applied to the default context; if a Context is passed as the first
800
+ # argument, it is used as the base instead of the default context.
801
+ #
802
+ # See Context#new() for the valid options
803
+ def Decimal.Context(*args)
804
+ case args.size
805
+ when 0
806
+ base = DefaultContext
807
+ when 1
808
+ arg = args.first
809
+ if arg.instance_of?(Context)
810
+ base = arg
811
+ options = nil
812
+ elsif arg.instance_of?(Hash)
813
+ base = DefaultContext
814
+ options = arg
815
+ else
816
+ raise TypeError,"invalid argument for Decimal.Context"
817
+ end
818
+ when 2
819
+ base = args.first
820
+ options = args.last
821
+ else
822
+ raise ArgumentError,"wrong number of arguments (#{args.size} for 0, 1 or 2)"
823
+ end
824
+
825
+ if options.nil? || options.empty?
826
+ base
827
+ else
828
+ Context.new(base, options)
829
+ end
830
+
831
+ end
832
+
833
+ # Define a context by passing either of:
834
+ # * A Context object
835
+ # * A hash of options (or nothing) to alter a copy of the current context.
836
+ # * A Context object and a hash of options to alter a copy of it
837
+ def Decimal.define_context(*options)
838
+ context = options.shift if options.first.instance_of?(Context)
839
+ if context && options.empty?
840
+ context
841
+ else
842
+ context ||= Decimal.context
843
+ Context(context, *options)
844
+ end
845
+ end
846
+
847
+ # The current context (thread-local).
848
+ # If arguments are passed they are interpreted as in Decimal.define_context() to change
849
+ # the current context.
850
+ # If a block is given, this method is a synonym for Decimal.local_context().
851
+ def Decimal.context(*args, &blk)
852
+ if blk
853
+ # setup a local context
854
+ local_context(*args, &blk)
855
+ elsif args.empty?
856
+ # return the current context
857
+ Thread.current['Decimal.context'] ||= DefaultContext.dup
858
+ else
859
+ # change the current context
860
+ Decimal.context = define_context(*args)
861
+ end
862
+ end
863
+
864
+ # Change the current context (thread-local).
865
+ def Decimal.context=(c)
866
+ Thread.current['Decimal.context'] = c.dup
867
+ end
868
+
869
+ # Defines a scope with a local context. A context can be passed which will be
870
+ # set a the current context for the scope; also a hash can be passed with
871
+ # options to apply to the local scope.
872
+ # Changes done to the current context are reversed when the scope is exited.
873
+ def Decimal.local_context(*args)
874
+ keep = context.dup
875
+ Decimal.context = define_context(*args)
876
+ result = yield Decimal.context
877
+ Decimal.context = keep
878
+ result
879
+ end
880
+
881
+ # A decimal number with value zero and the specified sign
882
+ def Decimal.zero(sign=+1)
883
+ Decimal.new([sign, 0, 0])
884
+ end
885
+
886
+ # A decimal infinite number with the specified sign
887
+ def Decimal.infinity(sign=+1)
888
+ Decimal.new([sign, 0, :inf])
889
+ end
890
+
891
+ # A decimal NaN (not a number)
892
+ def Decimal.nan()
893
+ Decimal.new([+1, nil, :nan])
894
+ end
895
+
896
+ #--
897
+ # =Notes on the representation of Decimal numbers.
898
+ #
899
+ # @sign is +1 for plus and -1 for minus
900
+ # @coeff is the integral significand stored as an integer (so leading zeros cannot be kept)
901
+ # @exp is the exponent to be applied to @coeff as an integer or one of :inf, :nan, :snan for special values
902
+ #
903
+ # The Python Decimal representation has these slots:
904
+ # _sign is 1 for minus, 0 for plus
905
+ # _int is the integral significand as a string of digits (leading zeroes are not kept)
906
+ # _exp is the exponent as an integer or 'F' for infinity, 'n' for NaN , 'N' for sNaN
907
+ # _is_especial is true for special values (infinity, NaN, sNaN)
908
+ # An additional class _WorkRep is used in Python for non-special decimal values with:
909
+ # sign
910
+ # int (significand as an integer)
911
+ # exp
912
+ #
913
+ # =Exponent values
914
+ #
915
+ # In GDAS (General Decimal Arithmetic Specification) numbers are represented by an unnormalized integral
916
+ # significand and an exponent (also called 'scale'.)
917
+ #
918
+ # The reduce operation (originally called 'normalize') removes trailing 0s and increments the exponent if necessary;
919
+ # the representation is rescaled to use the maximum exponent possible (while maintaining an integral significand.)
920
+ #
921
+ # A classical floating-point normalize opration would remove leading 0s and decrement the exponent instead,
922
+ # rescaling to the minimum exponent theat maintains the significand value under some conventional limit (1 or the radix).
923
+ #
924
+ # The logb and adjusted operations return the exponent that applies to the most significand digit (logb as a Decimal
925
+ # and adjusted as an integer.) This is the normalized scientific exponent.
926
+ #
927
+ # The most common normalized exponent is the normalized integral exponent for a fixed number of precision digits.
928
+ #
929
+ # The normalized fractional exponent is what BigDecima#exponent returns.
930
+ #
931
+ # ==Relations between exponent values
932
+ #
933
+ # The number of (kept) significand digits is s = a - e + 1
934
+ # where a is the adjusted exponent and e is the internal exponent (the unnormalized integral exponent.)
935
+ #
936
+ # The number of significant digits (excluding leading and trailing zeroes) is sr = a - re + 1
937
+ # where re is the internal exponent of the reduced value.
938
+ #
939
+ # The normalized integral exponent is e - (p - s) = a - p + 1
940
+ # where p is the fixed precision.
941
+ #
942
+ # The normalized fractional exponent is e + s = a + 1
943
+ #
944
+ # ==Example: 0.01204
945
+ #
946
+ # * The integral significand is 120400 and the internal exponent that applies to it is e = -7
947
+ # * The number of significand digits is s = 6
948
+ # * The reduced representation is 1204 with internal exponent re = -5
949
+ # * The number of significant digits sr = 4
950
+ # * The adjusted exponent is a = -2 (the adjusted representation is 1.204 with exponent -2)
951
+ # * Given a precision p = 8, the normalized integral representation is 12040000 with exponent -9
952
+ # * The normalized fractional representation is 0.1204 with exponent -1
953
+ #
954
+ # =Interoperatibility with other numeric types
955
+ #
956
+ # For some numeric types implicit conversion to Decimal is defined through these methods:
957
+ # * Decimal#coerce() is used when a Decimal is the right hand of an operator
958
+ # and the left hand is another numeric type
959
+ # * Decimal#_bin_op() used internally to define binary operators and use the Ruby coerce protocol:
960
+ # if the right-hand operand is of known type it is converted with Decimal; otherwise use coerce
961
+ # * Decimal._convert() converts known types to Decimal with Decimal() or raises an exception.
962
+ # * Decimal() casts known types and text representations of numbers to Decimal using the constructor.
963
+ # * Decimal#initialize performs the actual type conversion
964
+ #
965
+ # The known or 'coercible' types are initially Integer and Rational, but this can be extended to
966
+ # other types using define_conversion_from() in a Context object.
967
+ #++
968
+
969
+ # A decimal value can be defined by:
970
+ # * A String containing a text representation of the number
971
+ # * An Integer
972
+ # * A Rational
973
+ # * Another Decimal value.
974
+ # * A sign, coefficient and exponent (either as separate arguments, as an array or as a Hash with symbolic keys).
975
+ # This is the internal representation of Decimal, as returned by Decimal#split.
976
+ # The sign is +1 for plus and -1 for minus; the coefficient and exponent are
977
+ # integers, except for special values which are defined by :inf, :nan or :snan for the exponent.
978
+ # An optional Context can be passed as the last argument to override the current context; also a hash can be passed
979
+ # to override specific context parameters.
980
+ # The Decimal() admits the same parameters and can be used as a shortcut for Decimal creation.
981
+ def initialize(*args)
982
+ context = nil
983
+ if args.size>0 && args.last.instance_of?(Context)
984
+ context ||= args.pop
985
+ elsif args.size>1 && args.last.instance_of?(Hash)
986
+ context ||= args.pop
987
+ elsif args.size==1 && args.last.instance_of?(Hash)
988
+ arg = args.last
989
+ args = [arg[:sign], args[:coefficient], args[:exponent]]
990
+ arg.delete :sign
991
+ arg.delete :coefficient
992
+ arg.delete :exponent
993
+ context ||= arg
994
+ end
995
+
996
+ context = Decimal.define_context(context)
997
+
998
+ case args.size
999
+ when 3
1000
+ @sign, @coeff, @exp = args
1001
+ # TO DO: validate
1002
+
1003
+ when 1
1004
+ arg = args.first
1005
+ case arg
1006
+
1007
+ when Decimal
1008
+ @sign, @coeff, @exp = arg.split
1009
+
1010
+ when *context.coercible_types
1011
+ v = context._coerce(arg)
1012
+ @sign, @coeff, @exp = v.is_a?(Decimal) ? v.split : v
1013
+
1014
+ when String
1015
+ if arg.strip != arg
1016
+ @sign,@coeff,@exp = context.exception(ConversionSyntax, "no trailing or leading whitespace is permitted").split
1017
+ return
1018
+ end
1019
+ m = _parser(arg)
1020
+ if m.nil?
1021
+ @sign,@coeff,@exp = context.exception(ConversionSyntax, "Invalid literal for Decimal: #{arg.inspect}").split
1022
+ return
1023
+ end
1024
+ @sign = (m.sign == '-') ? -1 : +1
1025
+ if m.int || m.onlyfrac
1026
+ if m.int
1027
+ intpart = m.int
1028
+ fracpart = m.frac
1029
+ else
1030
+ intpart = ''
1031
+ fracpart = m.onlyfrac
1032
+ end
1033
+ @exp = m.exp.to_i
1034
+ if fracpart
1035
+ @coeff = (intpart+fracpart).to_i
1036
+ @exp -= fracpart.size
1037
+ else
1038
+ @coeff = intpart.to_i
1039
+ end
1040
+ else
1041
+ if m.diag
1042
+ # NaN
1043
+ @coeff = (m.diag.nil? || m.diag.empty?) ? nil : m.diag.to_i
1044
+ @coeff = nil if @coeff==0
1045
+ if @coeff
1046
+ max_diag_len = context.maximum_nan_diagnostic_digits
1047
+ if max_diag_len && @coeff >= Decimal.int_radix_power(max_diag_len)
1048
+ @sign,@coeff,@exp = context.exception(ConversionSyntax, "diagnostic info too long in NaN").split
1049
+ return
1050
+ end
1051
+ end
1052
+ @exp = m.signal ? :snan : :nan
1053
+ else
1054
+ # Infinity
1055
+ @coeff = 0
1056
+ @exp = :inf
1057
+ end
1058
+ end
1059
+ when Array
1060
+ @sign, @coeff, @exp = arg
1061
+ else
1062
+ raise TypeError, "invalid argument #{arg.inspect}"
1063
+ end
1064
+ else
1065
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1 or 3)"
1066
+ end
1067
+ end
1068
+
1069
+ # Returns the internal representation of the number, composed of:
1070
+ # * a sign which is +1 for plus and -1 for minus
1071
+ # * a coefficient (significand) which is an integer
1072
+ # * an exponent (an integer) or :inf, :nan or :snan for special values
1073
+ # The value of non-special numbers is sign*coefficient*10^exponent
1074
+ def split
1075
+ [@sign, @coeff, @exp]
1076
+ end
1077
+
1078
+ # Returns whether the number is a special value (NaN or Infinity).
1079
+ def special?
1080
+ @exp.instance_of?(Symbol)
1081
+ end
1082
+
1083
+ # Returns whether the number is not actualy one (NaN, not a number).
1084
+ def nan?
1085
+ @exp==:nan || @exp==:snan
1086
+ end
1087
+
1088
+ # Returns whether the number is a quite NaN (non-signaling)
1089
+ def qnan?
1090
+ @exp == :nan
1091
+ end
1092
+
1093
+ # Returns whether the number is a signaling NaN
1094
+ def snan?
1095
+ @exp == :snan
1096
+ end
1097
+
1098
+ # Returns whether the number is infinite
1099
+ def infinite?
1100
+ @exp == :inf
1101
+ end
1102
+
1103
+ # Returns whether the number is finite
1104
+ def finite?
1105
+ !special?
1106
+ end
1107
+
1108
+ # Returns whether the number is zero
1109
+ def zero?
1110
+ @coeff==0 && !special?
1111
+ end
1112
+
1113
+ # Returns whether the number not zero
1114
+ def nonzero?
1115
+ special? || @coeff>0
1116
+ end
1117
+
1118
+ # Returns whether the number is subnormal
1119
+ def subnormal?(context=nil)
1120
+ return false if special? || zero?
1121
+ context = Decimal.define_context(context)
1122
+ self.adjusted_exponent < context.emin
1123
+ end
1124
+
1125
+ # Returns whether the number is normal
1126
+ def normal?(context=nil)
1127
+ return true if special? || zero?
1128
+ context = Decimal.define_context(context)
1129
+ (context.emin <= self.adjusted_exponent) && (self.adjusted_exponent <= context.emax)
1130
+ end
1131
+
1132
+ # Classifies a number as one of
1133
+ # 'sNaN', 'NaN', '-Infinity', '-Normal', '-Subnormal', '-Zero',
1134
+ # '+Zero', '+Subnormal', '+Normal', '+Infinity'
1135
+ def number_class(context=nil)
1136
+ return "sNaN" if snan?
1137
+ return "NaN" if nan?
1138
+ if infinite?
1139
+ return '+Infinity' if @sign==+1
1140
+ return '-Infinity' # if @sign==-1
1141
+ end
1142
+ if zero?
1143
+ return '+Zero' if @sign==+1
1144
+ return '-Zero' # if @sign==-1
1145
+ end
1146
+ context = Decimal.define_context(context)
1147
+ if subnormal?(context)
1148
+ return '+Subnormal' if @sign==+1
1149
+ return '-Subnormal' # if @sign==-1
1150
+ end
1151
+ return '+Normal' if @sign==+1
1152
+ return '-Normal' if @sign==-1
1153
+ end
1154
+
1155
+ # Used internally to convert numbers to be used in an operation to a suitable numeric type
1156
+ def coerce(other)
1157
+ case other
1158
+ when *Decimal.context.coercible_types_or_decimal
1159
+ [Decimal(other),self]
1160
+ else
1161
+ super
1162
+ end
1163
+ end
1164
+
1165
+ # Used internally to define binary operators
1166
+ def _bin_op(op, meth, other, context=nil)
1167
+ context = Decimal.define_context(context)
1168
+ case other
1169
+ when *context.coercible_types_or_decimal
1170
+ self.send meth, Decimal(other, context), context
1171
+ else
1172
+ x, y = other.coerce(self)
1173
+ x.send op, y
1174
+ end
1175
+ end
1176
+ private :_bin_op
1177
+
1178
+ # Unary minus operator
1179
+ def -@(context=nil)
1180
+ #(context || Decimal.context).minus(self)
1181
+ _neg(context)
1182
+ end
1183
+
1184
+ # Unary plus operator
1185
+ def +@(context=nil)
1186
+ #(context || Decimal.context).plus(self)
1187
+ _pos(context)
1188
+ end
1189
+
1190
+ # Addition of two decimal numbers
1191
+ def +(other, context=nil)
1192
+ _bin_op :+, :add, other, context
1193
+ end
1194
+
1195
+ # Subtraction of two decimal numbers
1196
+ def -(other, context=nil)
1197
+ _bin_op :-, :subtract, other, context
1198
+ end
1199
+
1200
+ # Multiplication of two decimal numbers
1201
+ def *(other, context=nil)
1202
+ _bin_op :*, :multiply, other, context
1203
+ end
1204
+
1205
+ # Division of two decimal numbers
1206
+ def /(other, context=nil)
1207
+ _bin_op :/, :divide, other, context
1208
+ end
1209
+
1210
+ # Modulo of two decimal numbers
1211
+ def %(other, context=nil)
1212
+ _bin_op :%, :modulo, other, context
1213
+ end
1214
+
1215
+ # Addition
1216
+ def add(other, context=nil)
1217
+
1218
+ context = Decimal.define_context(context)
1219
+ other = Decimal._convert(other)
1220
+
1221
+ if self.special? || other.special?
1222
+ ans = _check_nans(context,other)
1223
+ return ans if ans
1224
+
1225
+ if self.infinite?
1226
+ if self.sign != other.sign && other.infinite?
1227
+ return context.exception(InvalidOperation, '-INF + INF')
1228
+ end
1229
+ return Decimal(self)
1230
+ end
1231
+
1232
+ return Decimal(other) if other.infinite?
1233
+ end
1234
+
1235
+ exp = [self.integral_exponent, other.integral_exponent].min
1236
+ negativezero = (context.rounding == ROUND_FLOOR && self.sign != other.sign)
1237
+
1238
+ if self.zero? && other.zero?
1239
+ sign = [self.sign, other.sign].max
1240
+ sign = -1 if negativezero
1241
+ ans = Decimal.new([sign, 0, exp])._fix(context)
1242
+ return ans
1243
+ end
1244
+
1245
+ if self.zero?
1246
+ exp = [exp, other.integral_exponent - context.precision - 1].max unless context.exact?
1247
+ return other._rescale(exp, context.rounding)._fix(context)
1248
+ end
1249
+
1250
+ if other.zero?
1251
+ exp = [exp, self.integral_exponent - context.precision - 1].max unless context.exact?
1252
+ return self._rescale(exp, context.rounding)._fix(context)
1253
+ end
1254
+
1255
+ op1, op2 = Decimal._normalize(self, other, context.precision)
1256
+
1257
+ result_sign = result_coeff = result_exp = nil
1258
+ if op1.sign != op2.sign
1259
+ return ans = Decimal.new([negativezero ? -1 : +1, 0, exp])._fix(context) if op1.integral_significand == op2.integral_significand
1260
+ op1,op2 = op2,op1 if op1.integral_significand < op2.integral_significand
1261
+ result_sign = op1.sign
1262
+ op1,op2 = op1.copy_negate, op2.copy_negate if result_sign < 0
1263
+ elsif op1.sign < 0
1264
+ result_sign = -1
1265
+ op1,op2 = op1.copy_negate, op2.copy_negate
1266
+ else
1267
+ result_sign = +1
1268
+ end
1269
+
1270
+ #puts "op1=#{op1.inspect} op2=#{op2.inspect}"
1271
+
1272
+
1273
+ if op2.sign == +1
1274
+ result_coeff = op1.integral_significand + op2.integral_significand
1275
+ else
1276
+ result_coeff = op1.integral_significand - op2.integral_significand
1277
+ end
1278
+
1279
+ result_exp = op1.integral_exponent
1280
+
1281
+ #puts "->#{Decimal([result_sign, result_coeff, result_exp]).inspect}"
1282
+
1283
+ return Decimal([result_sign, result_coeff, result_exp])._fix(context)
1284
+
1285
+ end
1286
+
1287
+
1288
+ # Subtraction
1289
+ def subtract(other, context=nil)
1290
+
1291
+ context = Decimal.define_context(context)
1292
+ other = Decimal._convert(other)
1293
+
1294
+ if self.special? || other.special?
1295
+ ans = _check_nans(context,other)
1296
+ return ans if ans
1297
+ end
1298
+ return add(other.copy_negate, context)
1299
+ end
1300
+
1301
+ # Multiplication
1302
+ def multiply(other, context=nil)
1303
+ context = Decimal.define_context(context)
1304
+ other = Decimal._convert(other)
1305
+ resultsign = self.sign * other.sign
1306
+ if self.special? || other.special?
1307
+ ans = _check_nans(context,other)
1308
+ return ans if ans
1309
+
1310
+ if self.infinite?
1311
+ return context.exception(InvalidOperation,"(+-)INF * 0") if other.zero?
1312
+ return Decimal.infinity(resultsign)
1313
+ end
1314
+ if other.infinite?
1315
+ return context.exception(InvalidOperation,"0 * (+-)INF") if self.zero?
1316
+ return Decimal.infinity(resultsign)
1317
+ end
1318
+ end
1319
+
1320
+ resultexp = self.integral_exponent + other.integral_exponent
1321
+
1322
+ return Decimal([resultsign, 0, resultexp])._fix(context) if self.zero? || other.zero?
1323
+ #return Decimal([resultsign, other.integral_significand, resultexp])._fix(context) if self.integral_significand==1
1324
+ #return Decimal([resultsign, self.integral_significand, resultexp])._fix(context) if other.integral_significand==1
1325
+
1326
+ return Decimal([resultsign, other.integral_significand*self.integral_significand, resultexp])._fix(context)
1327
+
1328
+ end
1329
+
1330
+ # Division
1331
+ def divide(other, context=nil)
1332
+ context = Decimal.define_context(context)
1333
+ other = Decimal._convert(other)
1334
+ resultsign = self.sign * other.sign
1335
+ if self.special? || other.special?
1336
+ ans = _check_nans(context,other)
1337
+ return ans if ans
1338
+ if self.infinite?
1339
+ return context.exception(InvalidOperation,"(+-)INF/(+-)INF") if other.infinite?
1340
+ return Decimal.infinity(resultsign)
1341
+ end
1342
+ if other.infinite?
1343
+ context.exception(Clamped,"Division by infinity")
1344
+ return Decimal.new([resultsign, 0, context.etiny])
1345
+ end
1346
+ end
1347
+
1348
+ if other.zero?
1349
+ return context.exception(DivisionUndefined, '0 / 0') if self.zero?
1350
+ return context.exception(DivisionByZero, 'x / 0', resultsign)
1351
+ end
1352
+
1353
+ if self.zero?
1354
+ exp = self.integral_exponent - other.integral_exponent
1355
+ coeff = 0
1356
+ else
1357
+ prec = context.exact? ? self.number_of_digits + 4*other.number_of_digits : context.precision # this assumes radix==10
1358
+ shift = other.number_of_digits - self.number_of_digits + prec + 1
1359
+ exp = self.integral_exponent - other.integral_exponent - shift
1360
+ if shift >= 0
1361
+ coeff, remainder = (self.integral_significand*Decimal.int_radix_power(shift)).divmod(other.integral_significand)
1362
+ else
1363
+ coeff, remainder = self.integral_significand.divmod(other.integral_significand*Decimal.int_radix_power(-shift))
1364
+ end
1365
+ if remainder != 0
1366
+ return context.exception(Inexact) if context.exact?
1367
+ coeff += 1 if (coeff%(Decimal.radix/2)) == 0
1368
+ else
1369
+ ideal_exp = self.integral_exponent - other.integral_exponent
1370
+ while (exp < ideal_exp) && ((coeff % Decimal.radix)==0)
1371
+ coeff /= Decimal.radix
1372
+ exp += 1
1373
+ end
1374
+ end
1375
+
1376
+ end
1377
+ return Decimal([resultsign, coeff, exp])._fix(context)
1378
+
1379
+ end
1380
+
1381
+ # Absolute value
1382
+ def abs(context=nil)
1383
+ if special?
1384
+ ans = _check_nans(context)
1385
+ return ans if ans
1386
+ end
1387
+ sign<0 ? _neg(context) : _pos(context)
1388
+ end
1389
+
1390
+ # Unary prefix plus operator
1391
+ def plus(context=nil)
1392
+ _pos(context)
1393
+ end
1394
+
1395
+ # Unary prefix minus operator
1396
+ def minus(context=nil)
1397
+ _neg(context)
1398
+ end
1399
+
1400
+ # Largest representable number smaller than itself
1401
+ def next_minus(context=nil)
1402
+ context = Decimal.define_context(context)
1403
+ if special?
1404
+ ans = _check_nans(context)
1405
+ return ans if ans
1406
+ if infinite?
1407
+ return Decimal.new(self) if @sign == -1
1408
+ # @sign == +1
1409
+ if context.exact?
1410
+ return context.exception(InvalidOperation, 'Exact +INF next minus')
1411
+ else
1412
+ return Decimal.new(+1, context.maximum_significand, context.etop)
1413
+ end
1414
+ end
1415
+ end
1416
+
1417
+ result = nil
1418
+ Decimal.local_context(context) do |local|
1419
+ local.rounding = :floor
1420
+ local.ignore_all_flags
1421
+ result = self._fix(local)
1422
+ if result == self
1423
+ result = self - Decimal(+1, 1, local.etiny-1)
1424
+ end
1425
+ end
1426
+ result
1427
+ end
1428
+
1429
+ # Smallest representable number larger than itself
1430
+ def next_plus(context=nil)
1431
+ context = Decimal.define_context(context)
1432
+ if special?
1433
+ ans = _check_nans(context)
1434
+ return ans if ans
1435
+ if infinite?
1436
+ return Decimal.new(self) if @sign == +1
1437
+ # @sign == -1
1438
+ if context.exact?
1439
+ return context.exception(InvalidOperation, 'Exact -INF next plus')
1440
+ else
1441
+ return Decimal.new(-1, context.maximum_significand, context.etop)
1442
+ end
1443
+ end
1444
+ end
1445
+
1446
+ result = nil
1447
+ Decimal.local_context(context) do |local|
1448
+ local.rounding = :ceiling
1449
+ local.ignore_all_flags
1450
+ result = self._fix(local)
1451
+ if result == self
1452
+ result = self + Decimal(+1, 1, local.etiny-1)
1453
+ end
1454
+ end
1455
+ result
1456
+
1457
+ end
1458
+
1459
+ # Returns the number closest to self, in the direction towards other.
1460
+ def next_toward(other, context=nil)
1461
+ context = Decimal.define_context(context)
1462
+ other = Decimal._convert(other)
1463
+ ans = _check_nans(context,other)
1464
+ return ans if ans
1465
+
1466
+ comparison = self <=> other
1467
+ return self.copy_sign(other) if comparison == 0
1468
+
1469
+ if comparison == -1
1470
+ result = self.next_plus(context)
1471
+ else # comparison == 1
1472
+ result = self.next_minus(context)
1473
+ end
1474
+
1475
+ # decide which flags to raise using value of ans
1476
+ if result.infinite?
1477
+ context.exception Overflow, 'Infinite result from next_toward', result.sign
1478
+ context.exception Rounded
1479
+ context.exception Inexact
1480
+ elsif result.adjusted_exponent < context.emin
1481
+ context.exception Underflow
1482
+ context.exception Subnormal
1483
+ context.exception Rounded
1484
+ context.exception Inexact
1485
+ # if precision == 1 then we don't raise Clamped for a
1486
+ # result 0E-etiny.
1487
+ context.exception Clamped if result.zero?
1488
+ end
1489
+
1490
+ result
1491
+ end
1492
+
1493
+ # Square root
1494
+ def sqrt(context=nil)
1495
+ context = Decimal.define_context(context)
1496
+ if special?
1497
+ ans = _check_nans(context)
1498
+ return ans if ans
1499
+ return Decimal.new(self) if infinite? && @sign==+1
1500
+ end
1501
+ return Decimal.new([@sign, 0, @exp/2])._fix(context) if zero?
1502
+ return context.exception(InvalidOperation, 'sqrt(-x), x>0') if @sign<0
1503
+ prec = context.precision + 1
1504
+ e = (@exp >> 1)
1505
+ if (@exp & 1)!=0
1506
+ c = @coeff*Decimal.radix
1507
+ l = (number_of_digits >> 1) + 1
1508
+ else
1509
+ c = @coeff
1510
+ l = (number_of_digits+1) >> 1
1511
+ end
1512
+ shift = prec - l
1513
+ if shift >= 0
1514
+ c = Decimal.int_mult_radix_power(c, (shift<<1))
1515
+ exact = true
1516
+ else
1517
+ c, remainder = c.divmod(Decimal.int_radix_power((-shift)<<1))
1518
+ exact = (remainder==0)
1519
+ end
1520
+ e -= shift
1521
+
1522
+ n = Decimal.int_radix_power(prec)
1523
+ while true
1524
+ q = c / n
1525
+ break if n <= q
1526
+ n = ((n + q) >> 1)
1527
+ end
1528
+ exact = exact && (n*n == c)
1529
+
1530
+ if exact
1531
+ if shift >= 0
1532
+ n = Decimal.int_div_radix_power(n, shift)
1533
+ else
1534
+ n = Decimal.int_mult_radix_power(n, -shift)
1535
+ end
1536
+ e += shift
1537
+ else
1538
+ return context.exception(Inexact) if context.exact?
1539
+ n += 1 if (n%5)==0
1540
+ end
1541
+ ans = Decimal.new([+1,n,e])
1542
+ Decimal.local_context(:rounding=>:half_even) do
1543
+ ans = ans._fix(context)
1544
+ end
1545
+ return ans
1546
+ end
1547
+
1548
+ # General Decimal Arithmetic Specification integer division and remainder:
1549
+ # (x/y).truncate, x - y*(x/y).truncate
1550
+ def divrem(other, context=nil)
1551
+ context = Decimal.define_context(context)
1552
+ other = Decimal._convert(other)
1553
+
1554
+ ans = _check_nans(context,other)
1555
+ return [ans,ans] if ans
1556
+
1557
+ sign = self.sign * other.sign
1558
+
1559
+ if self.infinite?
1560
+ if other.infinite?
1561
+ ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
1562
+ return [ans,ans]
1563
+ else
1564
+ return [Decimal.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
1565
+ end
1566
+ end
1567
+
1568
+ if other.zero?
1569
+ if self.zero?
1570
+ ans = context.exception(DivisionUndefined, 'divmod(0,0)')
1571
+ return [ans,ans]
1572
+ else
1573
+ return [context.exception(DivisionByZero, 'x // 0', sign),
1574
+ context.exception(InvalidOperation, 'x % 0')]
1575
+ end
1576
+ end
1577
+
1578
+ quotient, remainder = self._divide_truncate(other, context)
1579
+ return [quotient, remainder._fix(context)]
1580
+ end
1581
+
1582
+ # Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
1583
+ def divmod(other, context=nil)
1584
+ context = Decimal.define_context(context)
1585
+ other = Decimal._convert(other)
1586
+
1587
+ ans = _check_nans(context,other)
1588
+ return [ans,ans] if ans
1589
+
1590
+ sign = self.sign * other.sign
1591
+
1592
+ if self.infinite?
1593
+ if other.infinite?
1594
+ ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
1595
+ return [ans,ans]
1596
+ else
1597
+ return [Decimal.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
1598
+ end
1599
+ end
1600
+
1601
+ if other.zero?
1602
+ if self.zero?
1603
+ ans = context.exception(DivisionUndefined, 'divmod(0,0)')
1604
+ return [ans,ans]
1605
+ else
1606
+ return [context.exception(DivisionByZero, 'x // 0', sign),
1607
+ context.exception(InvalidOperation, 'x % 0')]
1608
+ end
1609
+ end
1610
+
1611
+ quotient, remainder = self._divide_floor(other, context)
1612
+ return [quotient, remainder._fix(context)]
1613
+ end
1614
+
1615
+
1616
+ # General Decimal Arithmetic Specification integer division: (x/y).truncate
1617
+ def divide_int(other, context=nil)
1618
+ context = Decimal.define_context(context)
1619
+ other = Decimal._convert(other)
1620
+
1621
+ ans = _check_nans(context,other)
1622
+ return ans if ans
1623
+
1624
+ sign = self.sign * other.sign
1625
+
1626
+ if self.infinite?
1627
+ return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
1628
+ return Decimal.infinity(sign)
1629
+ end
1630
+
1631
+ if other.zero?
1632
+ if self.zero?
1633
+ return context.exception(DivisionUndefined, '0 // 0')
1634
+ else
1635
+ return context.exception(DivisionByZero, 'x // 0', sign)
1636
+ end
1637
+ end
1638
+ return self._divide_truncate(other, context).first
1639
+ end
1640
+
1641
+ # Ruby-style integer division: (x/y).floor
1642
+ def div(other, context=nil)
1643
+ context = Decimal.define_context(context)
1644
+ other = Decimal._convert(other)
1645
+
1646
+ ans = _check_nans(context,other)
1647
+ return [ans,ans] if ans
1648
+
1649
+ sign = self.sign * other.sign
1650
+
1651
+ if self.infinite?
1652
+ return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
1653
+ return Decimal.infinity(sign)
1654
+ end
1655
+
1656
+ if other.zero?
1657
+ if self.zero?
1658
+ return context.exception(DivisionUndefined, '0 // 0')
1659
+ else
1660
+ return context.exception(DivisionByZero, 'x // 0', sign)
1661
+ end
1662
+ end
1663
+ return self._divide_floor(other, context).first
1664
+ end
1665
+
1666
+
1667
+ # Ruby-style modulo: x - y*div(x,y)
1668
+ def modulo(other, context=nil)
1669
+ context = Decimal.define_context(context)
1670
+ other = Decimal._convert(other)
1671
+
1672
+ ans = _check_nans(context,other)
1673
+ return ans if ans
1674
+
1675
+ #sign = self.sign * other.sign
1676
+
1677
+ if self.infinite?
1678
+ return context.exception(InvalidOperation, 'INF % x')
1679
+ elsif other.zero?
1680
+ if self.zero?
1681
+ return context.exception(DivisionUndefined, '0 % 0')
1682
+ else
1683
+ return context.exception(InvalidOperation, 'x % 0')
1684
+ end
1685
+ end
1686
+
1687
+ return self._divide_floor(other, context).last._fix(context)
1688
+ end
1689
+
1690
+ # General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
1691
+ def remainder(other, context=nil)
1692
+ context = Decimal.define_context(context)
1693
+ other = Decimal._convert(other)
1694
+
1695
+ ans = _check_nans(context,other)
1696
+ return ans if ans
1697
+
1698
+ #sign = self.sign * other.sign
1699
+
1700
+ if self.infinite?
1701
+ return context.exception(InvalidOperation, 'INF % x')
1702
+ elsif other.zero?
1703
+ if self.zero?
1704
+ return context.exception(DivisionUndefined, '0 % 0')
1705
+ else
1706
+ return context.exception(InvalidOperation, 'x % 0')
1707
+ end
1708
+ end
1709
+
1710
+ return self._divide_truncate(other, context).last._fix(context)
1711
+ end
1712
+
1713
+ # General Decimal Arithmetic Specification remainder-near:
1714
+ # x - y*round_half_even(x/y)
1715
+ def remainder_near(other, context=nil)
1716
+ context = Decimal.define_context(context)
1717
+ other = Decimal._convert(other)
1718
+
1719
+ ans = _check_nans(context,other)
1720
+ return ans if ans
1721
+
1722
+ sign = self.sign * other.sign
1723
+
1724
+ if self.infinite?
1725
+ return context.exception(InvalidOperation, 'remainder_near(INF,x)')
1726
+ elsif other.zero?
1727
+ if self.zero?
1728
+ return context.exception(DivisionUndefined, 'remainder_near(0,0)')
1729
+ else
1730
+ return context.exception(InvalidOperation, 'remainder_near(x,0)')
1731
+ end
1732
+ end
1733
+
1734
+ if other.infinite?
1735
+ return Decimal.new(self)._fix(context)
1736
+ end
1737
+
1738
+ ideal_exp = [self.integral_exponent, other.integral_exponent].min
1739
+ if self.zero?
1740
+ return Decimal([self.sign, 0, ideal_exp])._fix(context)
1741
+ end
1742
+
1743
+ expdiff = self.adjusted_exponent - other.adjusted_exponent
1744
+ if (expdiff >= context.precision+1) && !context.exact?
1745
+ return context.exception(DivisionImpossible)
1746
+ elsif expdiff <= -2
1747
+ return self._rescale(ideal_exp, context.rounding)._fix(context)
1748
+ end
1749
+
1750
+ self_coeff = self.integral_significand
1751
+ other_coeff = other.integral_significand
1752
+ de = self.integral_exponent - other.integral_exponent
1753
+ if de >= 0
1754
+ self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
1755
+ else
1756
+ other_coeff = Decimal.int_mult_radix_power(other_coeff, -de)
1757
+ end
1758
+ q, r = self_coeff.divmod(other_coeff)
1759
+ if 2*r + (q&1) > other_coeff
1760
+ r -= other_coeff
1761
+ q += 1
1762
+ end
1763
+
1764
+ return context.exception(DivisionImpossible) if q >= Decimal.int_radix_power(context.precision) && !context.exact?
1765
+
1766
+ sign = self.sign
1767
+ if r < 0
1768
+ sign = -sign
1769
+ r = -r
1770
+ end
1771
+
1772
+ return Decimal.new([sign, r, ideal_exp])._fix(context)
1773
+
1774
+ end
1775
+
1776
+ # Reduces an operand to its simplest form
1777
+ # by removing trailing 0s and incrementing the exponent.
1778
+ # (formerly called normalize in GDAS)
1779
+ def reduce(context=nil)
1780
+ context = Decimal.define_context(context)
1781
+ if special?
1782
+ ans = _check_nans(context)
1783
+ return ans if ans
1784
+ end
1785
+ dup = _fix(context)
1786
+ return dup if dup.infinite?
1787
+
1788
+ return Decimal.new([dup.sign, 0, 0]) if dup.zero?
1789
+
1790
+ exp_max = context.clamp? ? context.etop : context.emax
1791
+ end_d = nd = dup.number_of_digits
1792
+ exp = dup.integral_exponent
1793
+ coeff = dup.integral_significand
1794
+ dgs = dup.digits
1795
+ while (dgs[end_d-1]==0) && (exp < exp_max)
1796
+ exp += 1
1797
+ end_d -= 1
1798
+ end
1799
+ return Decimal.new([dup.sign, coeff/Decimal.int_radix_power(nd-end_d), exp])
1800
+
1801
+ end
1802
+
1803
+ # Returns the exponent of the magnitude of the most significant digit.
1804
+ #
1805
+ # The result is the integer which is the exponent of the magnitude
1806
+ # of the most significant digit of the number (as though it were truncated
1807
+ # to a single digit while maintaining the value of that digit and
1808
+ # without limiting the resulting exponent).
1809
+ def logb(context=nil)
1810
+ context = Decimal.define_context(context)
1811
+ ans = _check_nans(context)
1812
+ return ans if ans
1813
+ return Decimal.infinity if infinite?
1814
+ return context.exception(DivisionByZero,'logb(0)',-1) if zero?
1815
+ Decimal.new(adjusted_exponent)
1816
+ end
1817
+
1818
+ # Adds a value to the exponent.
1819
+ def scaleb(other, context=nil)
1820
+
1821
+ context = Decimal.define_context(context)
1822
+ other = Decimal._convert(other)
1823
+ ans = _check_nans(context, other)
1824
+ return ans if ans
1825
+ return context.exception(InvalidOperation) if other.infinite? || other.integral_exponent != 0
1826
+ unless context.exact?
1827
+ liminf = -2 * (context.emax + context.precision)
1828
+ limsup = 2 * (context.emax + context.precision)
1829
+ i = other.to_i
1830
+ return context.exception(InvalidOperation) if !((liminf <= i) && (i <= limsup))
1831
+ end
1832
+ return Decimal.new(self) if infinite?
1833
+ return Decimal.new(@sign, @coeff, @exp+i)._fix(context)
1834
+
1835
+ end
1836
+
1837
+ # Convert to other numerical type.
1838
+ def convert_to(type, context=nil)
1839
+ context = Decimal.define_context(context)
1840
+ context.convert_to(type, self)
1841
+ end
1842
+
1843
+ # Ruby-style to integer conversion.
1844
+ def to_i
1845
+ if special?
1846
+ return nil if nan?
1847
+ raise Error, "Cannot convert infinity to Integer"
1848
+ end
1849
+ if @exp >= 0
1850
+ return @sign*Decimal.int_mult_radix_power(@coeff,@exp)
1851
+ else
1852
+ return @sign*Decimal.int_div_radix_power(@coeff,-@exp)
1853
+ end
1854
+ end
1855
+
1856
+ # Ruby-style to string conversion.
1857
+ def to_s(eng=false,context=nil)
1858
+ # (context || Decimal.context).to_string(self)
1859
+ context = Decimal.define_context(context)
1860
+ sgn = sign<0 ? '-' : ''
1861
+ if special?
1862
+ if @exp==:inf
1863
+ "#{sgn}Infinity"
1864
+ elsif @exp==:nan
1865
+ "#{sgn}NaN#{@coeff}"
1866
+ else # exp==:snan
1867
+ "#{sgn}sNaN#{@coeff}"
1868
+ end
1869
+ else
1870
+ ds = @coeff.to_s
1871
+ n_ds = ds.size
1872
+ exp = integral_exponent
1873
+ leftdigits = exp + n_ds
1874
+ if exp<=0 && leftdigits>-6
1875
+ dotplace = leftdigits
1876
+ elsif !eng
1877
+ dotplace = 1
1878
+ elsif @coeff==0
1879
+ dotplace = (leftdigits+1)%3 - 1
1880
+ else
1881
+ dotplace = (leftdigits-1)%3 + 1
1882
+ end
1883
+
1884
+ if dotplace <=0
1885
+ intpart = '0'
1886
+ fracpart = '.' + '0'*(-dotplace) + ds
1887
+ elsif dotplace >= n_ds
1888
+ intpart = ds + '0'*(dotplace - n_ds)
1889
+ fracpart = ''
1890
+ else
1891
+ intpart = ds[0...dotplace]
1892
+ fracpart = '.' + ds[dotplace..-1]
1893
+ end
1894
+
1895
+ if leftdigits == dotplace
1896
+ e = ''
1897
+ else
1898
+ e = (context.capitals ? 'E' : 'e') + "%+d"%(leftdigits-dotplace)
1899
+ end
1900
+
1901
+ sgn + intpart + fracpart + e
1902
+
1903
+ end
1904
+ end
1905
+
1906
+ # Conversion to Rational.
1907
+ # Conversion of special values will raise an exception under Ruby 1.9
1908
+ def to_r
1909
+ if special?
1910
+ num = (@exp == :inf) ? @sign : 0
1911
+ Rational.respond_to?(:new!) ? Rational.new!(num,0) : Rational(num,0)
1912
+ else
1913
+ if @exp < 0
1914
+ Rational(@sign*@coeff, Decimal.int_radix_power(-@exp))
1915
+ else
1916
+ Rational(Decimal.int_mult_radix_power(@sign*@coeff,@exp), 1)
1917
+ end
1918
+ end
1919
+ end
1920
+
1921
+ # Conversion to Float
1922
+ def to_f
1923
+ if special?
1924
+ if @exp==:inf
1925
+ @sign/0.0
1926
+ else
1927
+ 0.0/0.0
1928
+ end
1929
+ else
1930
+ # to_rational.to_f
1931
+ # to_s.to_f
1932
+ @sign*@coeff*(10.0**@exp)
1933
+ end
1934
+ end
1935
+
1936
+ def inspect
1937
+ #"Decimal('#{self}')"
1938
+ #debug:
1939
+ "Decimal('#{self}') [coeff:#{@coeff.inspect} exp:#{@exp.inspect} s:#{@sign.inspect}]"
1940
+ end
1941
+
1942
+ # Internal comparison operator: returns -1 if the first number is less than the second,
1943
+ # 0 if both are equal or +1 if the first is greater than the secong.
1944
+ def <=>(other)
1945
+ case other
1946
+ when *Decimal.context.coercible_types_or_decimal
1947
+ other = Decimal(other)
1948
+ if self.special? || other.special?
1949
+ if self.nan? || other.nan?
1950
+ 1
1951
+ else
1952
+ self_v = self.finite? ? 0 : self.sign
1953
+ other_v = other.finite? ? 0 : other.sign
1954
+ self_v <=> other_v
1955
+ end
1956
+ else
1957
+ if self.zero?
1958
+ if other.zero?
1959
+ 0
1960
+ else
1961
+ -other.sign
1962
+ end
1963
+ elsif other.zero?
1964
+ self.sign
1965
+ elsif other.sign < self.sign
1966
+ +1
1967
+ elsif self.sign < other.sign
1968
+ -1
1969
+ else
1970
+ self_adjusted = self.adjusted_exponent
1971
+ other_adjusted = other.adjusted_exponent
1972
+ if self_adjusted == other_adjusted
1973
+ self_padded,other_padded = self.integral_significand,other.integral_significand
1974
+ d = self.integral_exponent - other.integral_exponent
1975
+ if d>0
1976
+ self_padded *= Decimal.int_radix_power(d)
1977
+ else
1978
+ other_padded *= Decimal.int_radix_power(-d)
1979
+ end
1980
+ (self_padded <=> other_padded)*self.sign
1981
+ elsif self_adjusted > other_adjusted
1982
+ self.sign
1983
+ else
1984
+ -self.sign
1985
+ end
1986
+ end
1987
+ end
1988
+ else
1989
+ if defined? other.coerce
1990
+ x, y = other.coerce(self)
1991
+ x <=> y
1992
+ else
1993
+ nil
1994
+ end
1995
+ end
1996
+ end
1997
+ def ==(other)
1998
+ (self<=>other) == 0
1999
+ end
2000
+ include Comparable
2001
+
2002
+ def hash
2003
+ ([Decimal]+reduce.split).hash # TODO: optimize
2004
+ end
2005
+
2006
+ def eql?(other)
2007
+ return false unless other.is_a?(Decimal)
2008
+ reduce.split == other.reduce.split
2009
+ end
2010
+
2011
+ # Compares like <=> but returns a Decimal value.
2012
+ def compare(other, context=nil)
2013
+
2014
+ other = Decimal._convert(other)
2015
+
2016
+ if self.special? || other.special?
2017
+ ans = _check_nans(context, other)
2018
+ return ans if ans
2019
+ end
2020
+
2021
+ return Decimal(self <=> other)
2022
+
2023
+ end
2024
+
2025
+ # Digits of the significand as an array of integers
2026
+ def digits
2027
+ @coeff.to_s.split('').map{|d| d.to_i}
2028
+ end
2029
+
2030
+ # Exponent of the magnitude of the most significant digit of the operand
2031
+ def adjusted_exponent
2032
+ if special?
2033
+ 0
2034
+ else
2035
+ @exp + number_of_digits - 1
2036
+ end
2037
+ end
2038
+
2039
+ # Synonym for Decimal#adjusted_exponent()
2040
+ def scientific_exponent
2041
+ adjusted_exponent
2042
+ end
2043
+
2044
+ # Exponent as though the significand were a fraction (the decimal point before its first digit)
2045
+ def fractional_exponent
2046
+ scientific_exponent + 1
2047
+ end
2048
+
2049
+ # Number of digits in the significand
2050
+ def number_of_digits
2051
+ # digits.size
2052
+ @coeff.to_s.size
2053
+ end
2054
+
2055
+ # Significand as an integer
2056
+ def integral_significand
2057
+ @coeff
2058
+ end
2059
+
2060
+ # Exponent of the significand as an integer
2061
+ def integral_exponent
2062
+ fractional_exponent - number_of_digits
2063
+ end
2064
+
2065
+ # Sign of the number: +1 for plus / -1 for minus.
2066
+ def sign
2067
+ @sign
2068
+ end
2069
+
2070
+ # Return the value of the number as an integer and a scale.
2071
+ def to_int_scale
2072
+ if special?
2073
+ nil
2074
+ else
2075
+ [@sign*integral_significand, integral_exponent]
2076
+ end
2077
+ end
2078
+
2079
+ # Returns copy with sign inverted
2080
+ def _neg(context=nil)
2081
+ if special?
2082
+ ans = _check_nans(context)
2083
+ return ans if ans
2084
+ end
2085
+ if zero?
2086
+ ans = copy_abs
2087
+ else
2088
+ ans = copy_negate
2089
+ end
2090
+ context = Decimal.define_context(context)
2091
+ ans._fix(context)
2092
+ end
2093
+
2094
+ # Returns a copy with precision adjusted
2095
+ def _pos(context=nil)
2096
+ if special?
2097
+ ans = _check_nans(context)
2098
+ return ans if ans
2099
+ end
2100
+ if zero?
2101
+ ans = copy_abs
2102
+ else
2103
+ ans = Decimal.new(self)
2104
+ end
2105
+ context = Decimal.define_context(context)
2106
+ ans._fix(context)
2107
+ end
2108
+
2109
+ # Returns a copy with positive sign
2110
+ def _abs(round=true, context=nil)
2111
+ return copy_abs if not round
2112
+
2113
+ if special?
2114
+ ans = _check_nans(context)
2115
+ return ans if ans
2116
+ end
2117
+ if sign>0
2118
+ ans = _neg(context)
2119
+ else
2120
+ ans = _pos(context)
2121
+ end
2122
+ ans
2123
+ end
2124
+
2125
+ # Round if it is necessary to keep within precision.
2126
+ def _fix(context)
2127
+ return self if context.exact?
2128
+
2129
+ if special?
2130
+ if nan?
2131
+ return _fix_nan(context)
2132
+ else
2133
+ return Decimal.new(self)
2134
+ end
2135
+ end
2136
+
2137
+ etiny = context.etiny
2138
+ etop = context.etop
2139
+ if zero?
2140
+ exp_max = context.clamp? ? etop : context.emax
2141
+ new_exp = [[@exp, etiny].max, exp_max].min
2142
+ if new_exp!=@exp
2143
+ context.exception Clamped
2144
+ return Decimal.new([sign,0,new_exp])
2145
+ else
2146
+ return Decimal.new(self)
2147
+ end
2148
+ end
2149
+
2150
+ nd = number_of_digits
2151
+ exp_min = nd + @exp - context.precision
2152
+ if exp_min > etop
2153
+ context.exception Inexact
2154
+ context.exception Rounded
2155
+ return context.exception(Overflow, 'above Emax', sign)
2156
+ end
2157
+
2158
+ self_is_subnormal = exp_min < etiny
2159
+
2160
+ if self_is_subnormal
2161
+ context.exception Subnormal
2162
+ exp_min = etiny
2163
+ end
2164
+
2165
+ if @exp < exp_min
2166
+ #puts "_fix(#{self}) rounded; e=#{@exp} em=#{exp_min}"
2167
+ context.exception Rounded
2168
+ # dig is the digits number from 0 (MS) to number_of_digits-1 (LS)
2169
+ # dg = numberof_digits-dig is from 1 (LS) to number_of_digits (MS)
2170
+ dg = exp_min - @exp # dig = number_of_digits + exp - exp_min
2171
+ if dg > number_of_digits # dig<0
2172
+ d = Decimal.new([sign,1,exp_min-1])
2173
+ dg = number_of_digits # dig = 0
2174
+ else
2175
+ d = Decimal.new(self)
2176
+ end
2177
+ changed = d._round(context.rounding, dg)
2178
+ coeff = Decimal.int_div_radix_power(d.integral_significand, dg)
2179
+ coeff += 1 if changed==1
2180
+ ans = Decimal.new([sign, coeff, exp_min])
2181
+ if changed!=0
2182
+ context.exception Inexact
2183
+ if self_is_subnormal
2184
+ context.exception Underflow
2185
+ if ans.zero?
2186
+ context.exception Clamped
2187
+ end
2188
+ elsif ans.number_of_digits == context.precision+1
2189
+ if ans.integral_exponent< etop
2190
+ ans = Decimal.new([ans.sign, Decimal.int_div_radix_power(ans.integral_significand,1), ans.integral_exponent+1])
2191
+ else
2192
+ ans = context.exception(Overflow, 'above Emax', d.sign)
2193
+ end
2194
+ end
2195
+ end
2196
+ return ans
2197
+ end
2198
+
2199
+ if context.clamp? && @exp>etop
2200
+ context.exception Clamped
2201
+ self_padded = Decimal.int_mult_radix_power(@coeff, @exp-etop)
2202
+ return Decimal.new([sign,self_padded,etop])
2203
+ end
2204
+
2205
+ return Decimal.new(self)
2206
+
2207
+ end
2208
+
2209
+
2210
+ ROUND_ARITHMETIC = true
2211
+
2212
+ # Round to i digits using the specified method
2213
+ def _round(rounding, i)
2214
+ send("_round_#{rounding}", i)
2215
+ end
2216
+
2217
+ # Round down (toward 0, truncate) to i digits
2218
+ def _round_down(i)
2219
+ if ROUND_ARITHMETIC
2220
+ (@coeff % Decimal.int_radix_power(i))==0 ? 0 : -1
2221
+ else
2222
+ d = @coeff.to_s
2223
+ p = d.size - i
2224
+ d[p..-1].match(/\A0+\Z/) ? 0 : -1
2225
+ end
2226
+ end
2227
+
2228
+ # Round up (away from 0) to i digits
2229
+ def _round_up(i)
2230
+ -_round_down(i)
2231
+ end
2232
+
2233
+ # Round to closest i-digit number with ties down (rounds 5 toward 0)
2234
+ def _round_half_down(i)
2235
+ if ROUND_ARITHMETIC
2236
+ m = Decimal.int_radix_power(i)
2237
+ if (m>1) && ((@coeff%m) == m/2)
2238
+ -1
2239
+ else
2240
+ _round_half_up(i)
2241
+ end
2242
+ else
2243
+ d = @coeff.to_s
2244
+ p = d.size - i
2245
+ d[p..-1].match(/^5d*$/) ? -1 : _round_half_up(i)
2246
+ end
2247
+
2248
+ end
2249
+
2250
+ # Round to closest i-digit number with ties up (rounds 5 away from 0)
2251
+ def _round_half_up(i)
2252
+ if ROUND_ARITHMETIC
2253
+ m = Decimal.int_radix_power(i)
2254
+ if (m>1) && ((@coeff%m) >= m/2)
2255
+ 1
2256
+ else
2257
+ (@coeff % m)==0 ? 0 : -1
2258
+ end
2259
+ else
2260
+ d = @coeff.to_s
2261
+ p = d.size - i
2262
+ if '56789'.include?(d[p,1])
2263
+ 1
2264
+ else
2265
+ d[p..-1].match(/^0+$/) ? 0 : -1
2266
+ end
2267
+ end
2268
+
2269
+ end
2270
+
2271
+ # Round to closest i-digit number with ties (5) to an even digit
2272
+ def _round_half_even(i)
2273
+ if ROUND_ARITHMETIC
2274
+ m = Decimal.int_radix_power(i)
2275
+ if (m>1) && ((@coeff%m) == m/2 && ((@coeff/m)%2)==0)
2276
+ -1
2277
+ else
2278
+ _round_half_up(i)
2279
+ end
2280
+ else
2281
+ d = @coeff.to_s
2282
+ p = d.size - i
2283
+
2284
+ if d[p..-1].match(/\A#{radix/2}0*\Z/) && (p==0 || ((d[p-1,1].to_i%2)==0))
2285
+ -1
2286
+ else
2287
+ _round_half_up(i)
2288
+ end
2289
+
2290
+ end
2291
+ end
2292
+
2293
+ # Round up (not away from 0 if negative) to i digits
2294
+ def _round_ceiling(i)
2295
+ sign<0 ? _round_down(i) : -_round_down(i)
2296
+ end
2297
+
2298
+ # Round down (not toward 0 if negative) to i digits
2299
+ def _round_floor(i)
2300
+ sign>0 ? _round_down(i) : -_round_down(i)
2301
+ end
2302
+
2303
+ # Round down unless digit i-1 is 0 or 5
2304
+ def _round_up05(i)
2305
+ if ROUND_ARITHMETIC
2306
+ dg = (@coeff%Decimal.int_radix_power(i+1))/Decimal.int_radix_power(i)
2307
+ else
2308
+ d = @coeff.to_s
2309
+ p = d.size - i
2310
+ dg = (p>0) ? d[p-1,1].to_i : 0
2311
+ end
2312
+ if [0,Decimal.radix/2].include?(dg)
2313
+ -_round_down(i)
2314
+ else
2315
+ _round_down(i)
2316
+ end
2317
+ end
2318
+
2319
+ # adjust payload of a NaN to the context
2320
+ def _fix_nan(context)
2321
+ if !context.exact?
2322
+ payload = @coeff
2323
+ payload = nil if payload==0
2324
+
2325
+ max_payload_len = context.maximum_nan_diagnostic_digits
2326
+
2327
+ if number_of_digits > max_payload_len
2328
+ payload = payload.to_s[-max_payload_len..-1].to_i
2329
+ return Decimal([@sign, payload, @exp])
2330
+ end
2331
+ end
2332
+ Decimal(self)
2333
+ end
2334
+
2335
+ # Check if the number or other is NaN, signal if sNaN or return NaN;
2336
+ # return nil if none is NaN.
2337
+ def _check_nans(context=nil, other=nil)
2338
+ #self_is_nan = self.nan?
2339
+ #other_is_nan = other.nil? ? false : other.nan?
2340
+ if self.nan? || (other && other.nan?)
2341
+ context = Decimal.define_context(context)
2342
+ return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
2343
+ return context.exception(InvalidOperation, 'sNaN', other) if other && other.snan?
2344
+ return self._fix_nan(context) if self.nan?
2345
+ return other._fix_nan(context)
2346
+ else
2347
+ return nil
2348
+ end
2349
+ end
2350
+
2351
+ # Rescale so that the exponent is exp, either by padding with zeros
2352
+ # or by truncating digits, using the given rounding mode.
2353
+ #
2354
+ # Specials are returned without change. This operation is
2355
+ # quiet: it raises no flags, and uses no information from the
2356
+ # context.
2357
+ #
2358
+ # exp = exp to scale to (an integer)
2359
+ # rounding = rounding mode
2360
+ def _rescale(exp, rounding)
2361
+
2362
+ return Decimal.new(self) if special?
2363
+ return Decimal.new([sign, 0, exp]) if zero?
2364
+ return Decimal.new([sign, @coeff*Decimal.int_radix_power(self.integral_exponent - exp), exp]) if self.integral_exponent > exp
2365
+ #nd = number_of_digits + self.integral_exponent - exp
2366
+ nd = exp - self.integral_exponent
2367
+ if number_of_digits < nd
2368
+ slf = Decimal.new([sign, 1, exp-1])
2369
+ nd = number_of_digits
2370
+ else
2371
+ slf = Decimal.new(self)
2372
+ end
2373
+ changed = slf._round(rounding, nd)
2374
+ coeff = Decimal.int_div_radix_power(@coeff, nd)
2375
+ coeff += 1 if changed==1
2376
+ Decimal.new([slf.sign, coeff, exp])
2377
+
2378
+ end
2379
+
2380
+ # Normalizes op1, op2 to have the same exp and length of coefficient. Used for addition.
2381
+ def Decimal._normalize(op1, op2, prec=0)
2382
+ #puts "N: #{op1.inspect} #{op2.inspect} p=#{prec}"
2383
+ if op1.integral_exponent < op2.integral_exponent
2384
+ swap = true
2385
+ tmp,other = op2,op1
2386
+ else
2387
+ swap = false
2388
+ tmp,other = op1,op2
2389
+ end
2390
+ tmp_len = tmp.number_of_digits
2391
+ other_len = other.number_of_digits
2392
+ exp = tmp.integral_exponent + [-1, tmp_len - prec - 2].min
2393
+ #puts "exp=#{exp}"
2394
+ if (other_len+other.integral_exponent-1 < exp) && prec>0
2395
+ other = Decimal.new([other.sign, 1, exp])
2396
+ #puts "other = #{other.inspect}"
2397
+ end
2398
+ tmp = Decimal.new([tmp.sign, int_mult_radix_power(tmp.integral_significand, tmp.integral_exponent-other.integral_exponent), other.integral_exponent])
2399
+ #puts "tmp=#{tmp.inspect}"
2400
+ return swap ? [other, tmp] : [tmp, other]
2401
+ end
2402
+
2403
+ # Returns a copy of with the sign set to +
2404
+ def copy_abs
2405
+ Decimal.new([+1,@coeff,@exp])
2406
+ end
2407
+
2408
+ # Returns a copy of with the sign inverted
2409
+ def copy_negate
2410
+ Decimal.new([-@sign,@coeff,@exp])
2411
+ end
2412
+
2413
+ # Returns a copy of with the sign of other
2414
+ def copy_sign(other)
2415
+ Decimal.new([other.sign, @coeff, @exp])
2416
+ end
2417
+
2418
+ # Returns true if the value is an integer
2419
+ def integral?
2420
+ if finite?
2421
+ if @exp>=0 || @coeff==0
2422
+ true
2423
+ else
2424
+ if @exp <= -number_of_digits
2425
+ false
2426
+ else
2427
+ m = Decimal.int_radix_power(-@exp)
2428
+ (@coeff % m) == 0
2429
+ end
2430
+ end
2431
+ else
2432
+ false
2433
+ end
2434
+ end
2435
+
2436
+ # Rescale so that the exponent is exp, either by padding with zeros
2437
+ # or by truncating digits.
2438
+ def rescale(exp, context=nil, watch_exp=true)
2439
+ context = Decimal.define_context(context)
2440
+ exp = Decimal._convert(exp)
2441
+ if self.special? || exp.special?
2442
+ ans = _check_nans(context, exp)
2443
+ return ans if ans
2444
+ if exp.infinite? || self.infinite?
2445
+ return Decimal.new(self) if exp.infinite? && self.infinite?
2446
+ return context.exception(InvalidOperation, 'rescale with one INF')
2447
+ end
2448
+ end
2449
+ return context.exception(InvalidOperation,"exponent of rescale is not integral") unless exp.integral?
2450
+ exp = exp.to_i
2451
+ _watched_rescale(exp, context, watch_exp)
2452
+ end
2453
+
2454
+ # Quantize so its exponent is the same as that of y.
2455
+ def quantize(exp, context=nil, watch_exp=true)
2456
+ exp = Decimal._convert(exp)
2457
+ context = Decimal.define_context(context)
2458
+ if self.special? || exp.special?
2459
+ ans = _check_nans(context, exp)
2460
+ return ans if ans
2461
+ if exp.infinite? || self.infinite?
2462
+ return Decimal.new(self) if exp.infinite? && self.infinite?
2463
+ return context.exception(InvalidOperation, 'quantize with one INF')
2464
+ end
2465
+ end
2466
+ exp = exp.integral_exponent
2467
+ _watched_rescale(exp, context, watch_exp)
2468
+ end
2469
+
2470
+ def _watched_rescale(exp, context, watch_exp)
2471
+ if !watch_exp
2472
+ ans = _rescale(exp, context.rounding)
2473
+ context.exception(Rounded) if ans.integral_exponent > self.integral_exponent
2474
+ context.exception(Inexact) if ans != self
2475
+ return ans
2476
+ end
2477
+
2478
+ if exp < context.etiny || exp > context.emax
2479
+ return context.exception(InvalidOperation, "target operation out of bounds in quantize/rescale")
2480
+ end
2481
+
2482
+ return Decimal.new([@sign, 0, exp])._fix(context) if zero?
2483
+
2484
+ self_adjusted = adjusted_exponent
2485
+ return context.exception(InvalidOperation,"exponent of quantize/rescale result too large for current context") if self_adjusted > context.emax
2486
+ return context.exception(InvalidOperation,"quantize/rescale has too many digits for current context") if (self_adjusted - exp + 1 > context.precision) && !context.exact?
2487
+
2488
+ ans = _rescale(exp, context.rounding)
2489
+ return context.exception(InvalidOperation,"exponent of rescale result too large for current context") if ans.adjusted_exponent > context.emax
2490
+ return context.exception(InvalidOperation,"rescale result has too many digits for current context") if (ans.number_of_digits > context.precision) && !context.exact?
2491
+ if ans.integral_exponent > self.integral_exponent
2492
+ context.exception(Rounded)
2493
+ context.exception(Inexact) if ans!=self
2494
+ end
2495
+ context.exception(Subnormal) if !ans.zero? && (ans.adjusted_exponent < context.emin)
2496
+ return ans._fix(context)
2497
+ end
2498
+
2499
+ # Return true if has the same exponent as other.
2500
+ #
2501
+ # If either operand is a special value, the following rules are used:
2502
+ # * return true if both operands are infinities
2503
+ # * return true if both operands are NaNs
2504
+ # * otherwise, return false.
2505
+ def same_quantum?(other)
2506
+ other = Decimal._convert(other)
2507
+ if self.special? || other.special?
2508
+ return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
2509
+ end
2510
+ return self.integral_exponent == other.integral_exponent
2511
+ end
2512
+
2513
+ # Rounds to a nearby integer. May raise Inexact or Rounded.
2514
+ def to_integral_exact(context=nil)
2515
+ context = Decimal.define_context(context)
2516
+ if special?
2517
+ ans = _check_nans(context)
2518
+ return ans if ans
2519
+ return Decimal.new(self)
2520
+ end
2521
+ return Decimal.new(self) if @exp >= 0
2522
+ return Decimal.new([@sign, 0, 0]) if zero?
2523
+ context.exception Rounded
2524
+ ans = _rescale(0, context.rounding)
2525
+ context.exception Inexact if ans != self
2526
+ return ans
2527
+ end
2528
+
2529
+ # Rounds to a nearby integer. Doesn't raise Inexact or Rounded.
2530
+ def to_integral_value(context=nil)
2531
+ context = Decimal.define_context(context)
2532
+ if special?
2533
+ ans = _check_nans(context)
2534
+ return ans if ans
2535
+ return Decimal.new(self)
2536
+ end
2537
+ return Decimal.new(self) if @exp >= 0
2538
+ return _rescale(0, context.rounding)
2539
+ end
2540
+
2541
+ # General rounding.
2542
+ #
2543
+ # With an integer argument this acts like Float#round: the parameter specifies the number
2544
+ # of fractional digits (or digits to the left of the decimal point if negative).
2545
+ #
2546
+ # Options can be passed as a Hash instead; valid options are:
2547
+ # * :rounding method for rounding (see Context#new())
2548
+ # The precision can be specified as:
2549
+ # * :places number of fractional digits as above.
2550
+ # * :exponent specifies the exponent corresponding to the
2551
+ # digit to be rounded (exponent == -places)
2552
+ # * :precision or :significan_digits is the number of digits
2553
+ # * :power 10^exponent, value of the digit to be rounded,
2554
+ # should be passed as a type convertible to Decimal.
2555
+ # * :index 0-based index of the digit to be rounded
2556
+ # * :rindex right 0-based index of the digit to be rounded
2557
+ #
2558
+ # The default is :places=>0 (round to integer).
2559
+ #
2560
+ # Example: ways of specifiying the rounding position
2561
+ # number: 1 2 3 4 . 5 6 7 8
2562
+ # :places -3 -2 -1 0 1 2 3 4
2563
+ # :exponent 3 2 1 0 -1 -2 -3 -4
2564
+ # :precision 1 2 3 4 5 6 7 8
2565
+ # :power 1E3 1E2 10 1 0.1 1E-2 1E-3 1E-4
2566
+ # :index 0 1 2 3 4 5 6 7
2567
+ # :index 7 6 5 4 3 2 1 0
2568
+ def round(opt={})
2569
+ opt = { :places=>opt } if opt.kind_of?(Integer)
2570
+ r = opt[:rounding] || :half_up
2571
+ as_int = false
2572
+ if v=(opt[:precision] || opt[:significant_digits])
2573
+ prec = v
2574
+ elsif v=(opt[:places])
2575
+ prec = adjusted_exponent + 1 + v
2576
+ elsif v=(opt[:exponent])
2577
+ prec = adjusted_exponent + 1 - v
2578
+ elsif v=(opt[:power])
2579
+ prec = adjusted_exponent + 1 - Decimal(v).adjusted_exponent
2580
+ elsif v=(opt[:index])
2581
+ prec = i+1
2582
+ elsif v=(opt[:rindex])
2583
+ prec = number_of_digits - v
2584
+ else
2585
+ prec = adjusted_exponent + 1
2586
+ as_int = true
2587
+ end
2588
+ result = plus(:rounding=>r, :precision=>prec)
2589
+ return as_int ? result.to_i : result
2590
+ end
2591
+
2592
+ # General ceiling operation (as for Float) with same options for precision
2593
+ # as Decimal#round()
2594
+ def ceil(opt={})
2595
+ opt[:rounding] = :ceiling
2596
+ round opt
2597
+ end
2598
+
2599
+ # General floor operation (as for Float) with same options for precision
2600
+ # as Decimal#round()
2601
+ def floor(opt={})
2602
+ opt[:rounding] = :floor
2603
+ round opt
2604
+ end
2605
+
2606
+ # General truncate operation (as for Float) with same options for precision
2607
+ # as Decimal#round()
2608
+ def truncate(opt={})
2609
+ opt[:rounding] = :down
2610
+ round opt
2611
+ end
2612
+
2613
+ # Fused multiply-add.
2614
+ #
2615
+ # Computes (self*other+third) with no rounding of the intermediate product self*other.
2616
+ def fma(other, third, context=nil)
2617
+ context = Decimal.define_context(context)
2618
+ other = Decimal._convert(other)
2619
+ third = Decimal._convert(third)
2620
+ if self.special? || other.special?
2621
+ return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
2622
+ return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
2623
+ if self.nan?
2624
+ product = self
2625
+ elsif other.nan?
2626
+ product = other
2627
+ elsif self.infinite?
2628
+ return context.exception(InvalidOperation, 'INF * 0 in fma') if other.zero?
2629
+ product = Decimal.infinity(self.sign*other.sign)
2630
+ elsif other.infinite?
2631
+ return context.exception(InvalidOperation, '0 * INF in fma') if self.zero?
2632
+ product = Decimal.infinity(self.sign*other.sign)
2633
+ end
2634
+ else
2635
+ product = Decimal.new([self.sign*other.sign,self.integral_significand*other.integral_significand, self.integral_exponent+other.integral_exponent])
2636
+ end
2637
+ return product.add(third, context)
2638
+ end
2639
+
2640
+ def _divide_truncate(other, context)
2641
+ context = Decimal.define_context(context)
2642
+ sign = self.sign * other.sign
2643
+ if other.infinite?
2644
+ ideal_exp = self.integral_exponent
2645
+ else
2646
+ ideal_exp = [self.integral_exponent, other.integral_exponent].min
2647
+ end
2648
+
2649
+ expdiff = self.adjusted_exponent - other.adjusted_exponent
2650
+ if self.zero? || other.infinite? || (expdiff <= -2)
2651
+ return [Decimal.new([sign, 0, 0]), _rescale(ideal_exp, context.rounding)]
2652
+ end
2653
+ if (expdiff <= context.precision) || context.exact?
2654
+ self_coeff = self.integral_significand
2655
+ other_coeff = other.integral_significand
2656
+ de = self.integral_exponent - other.integral_exponent
2657
+ if de >= 0
2658
+ self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
2659
+ else
2660
+ other_coeff = Decimal.int_mult_radix_power(other_coeff, -de)
2661
+ end
2662
+ q, r = self_coeff.divmod(other_coeff)
2663
+ if (q < Decimal.int_radix_power(context.precision)) || context.exact?
2664
+ return [Decimal([sign, q, 0]),Decimal([self.sign, r, ideal_exp])]
2665
+ end
2666
+ end
2667
+ # Here the quotient is too large to be representable
2668
+ ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
2669
+ return [ans, ans]
2670
+
2671
+ end
2672
+
2673
+ def _divide_floor(other, context)
2674
+ context = Decimal.define_context(context)
2675
+ sign = self.sign * other.sign
2676
+ if other.infinite?
2677
+ ideal_exp = self.integral_exponent
2678
+ else
2679
+ ideal_exp = [self.integral_exponent, other.integral_exponent].min
2680
+ end
2681
+
2682
+ expdiff = self.adjusted_exponent - other.adjusted_exponent
2683
+ if self.zero? || other.infinite? || (expdiff <= -2)
2684
+ return [Decimal.new([sign, 0, 0]), _rescale(ideal_exp, context.rounding)]
2685
+ end
2686
+ if (expdiff <= context.precision) || context.exact?
2687
+ self_coeff = self.integral_significand*self.sign
2688
+ other_coeff = other.integral_significand*other.sign
2689
+ de = self.integral_exponent - other.integral_exponent
2690
+ if de >= 0
2691
+ self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
2692
+ else
2693
+ other_coeff = Decimal.int_mult_radix_power(other_coeff, -de)
2694
+ end
2695
+ q, r = self_coeff.divmod(other_coeff)
2696
+ if r<0
2697
+ r = -r
2698
+ rs = -1
2699
+ else
2700
+ rs = +1
2701
+ end
2702
+ if q<0
2703
+ q = -q
2704
+ qs = -1
2705
+ else
2706
+ qs = +1
2707
+ end
2708
+ if (q < Decimal.int_radix_power(context.precision)) || context.exact?
2709
+ return [Decimal([qs, q, 0]),Decimal([rs, r, ideal_exp])]
2710
+ end
2711
+ end
2712
+ # Here the quotient is too large to be representable
2713
+ ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
2714
+ return [ans, ans]
2715
+
2716
+ end
2717
+
2718
+ # Convert a numeric value to decimal (internal use)
2719
+ def Decimal._convert(x, error=true)
2720
+ case x
2721
+ when Decimal
2722
+ x
2723
+ when *Decimal.context.coercible_types
2724
+ Decimal.new(x)
2725
+ else
2726
+ raise TypeError, "Unable to convert #{x.class} to Decimal" if error
2727
+ nil
2728
+ end
2729
+ end
2730
+
2731
+ # Parse numeric text literals (internal use)
2732
+ def _parser(txt)
2733
+ md = /^\s*([-+])?(?:(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([-+]?\d+))?|Inf(?:inity)?|(s)?NaN(\d*))\s*$/i.match(txt)
2734
+ if md
2735
+ OpenStruct.new :sign=>md[1], :int=>md[2], :frac=>md[3], :onlyfrac=>md[4], :exp=>md[5],
2736
+ :signal=>md[6], :diag=>md[7]
2737
+ end
2738
+ end
2739
+
2740
+ end
2741
+
2742
+ # Decimal constructor. See Decimal#new for the parameters.
2743
+ # If a Decimal is passed a reference to it is returned (no new object is created).
2744
+ def Decimal(*args)
2745
+ if args.size==1 && args.first.instance_of?(Decimal)
2746
+ args.first
2747
+ else
2748
+ Decimal.new(*args)
2749
+ end
2750
+ end