flt 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +41 -0
- data/License.txt +20 -0
- data/Manifest.txt +42 -0
- data/README.txt +557 -0
- data/Rakefile +34 -0
- data/lib/flt.rb +9 -0
- data/lib/flt/b.rb +6 -0
- data/lib/flt/bigdecimal.rb +151 -0
- data/lib/flt/bin_num.rb +250 -0
- data/lib/flt/d.rb +6 -0
- data/lib/flt/dec_num.rb +1239 -0
- data/lib/flt/float.rb +458 -0
- data/lib/flt/math.rb +66 -0
- data/lib/flt/num.rb +4211 -0
- data/lib/flt/sugar.rb +102 -0
- data/lib/flt/support.rb +1335 -0
- data/lib/flt/tolerance.rb +561 -0
- data/lib/flt/tolerance/sugar.rb +77 -0
- data/lib/flt/version.rb +9 -0
- data/setup.rb +1585 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +192 -0
- data/tasks/git.rake +40 -0
- data/tasks/manifest.rake +48 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +279 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/test/all_tests.rb +23 -0
- data/test/helper.rb +101 -0
- data/test/reader.rb +68 -0
- data/test/test_basic.rb +396 -0
- data/test/test_bin.rb +245 -0
- data/test/test_bin_arithmetic.rb +94 -0
- data/test/test_binfloat_conversion.rb +24 -0
- data/test/test_coercion.rb +22 -0
- data/test/test_comparisons.rb +53 -0
- data/test/test_dectest.rb +216 -0
- data/test/test_define_conversions.rb +144 -0
- data/test/test_epsilon.rb +55 -0
- data/test/test_exact.rb +147 -0
- data/test/test_flags.rb +34 -0
- data/test/test_multithreading.rb +32 -0
- data/test/test_num_constructor.rb +133 -0
- data/test/test_odd_even.rb +78 -0
- data/test/test_round.rb +104 -0
- data/test/test_to_int.rb +104 -0
- data/test/test_to_rf.rb +36 -0
- data/test/test_tol.rb +102 -0
- data/test/test_ulp.rb +127 -0
- metadata +147 -0
data/lib/flt/math.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'flt/dec_num'
|
2
|
+
|
3
|
+
module Flt
|
4
|
+
class DecNum
|
5
|
+
module Math
|
6
|
+
|
7
|
+
extend Flt # to access constructor methods DecNum
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Trinogometry
|
12
|
+
|
13
|
+
# Pi
|
14
|
+
def pi(decimals=nil)
|
15
|
+
three = DecNum(3)
|
16
|
+
lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
|
17
|
+
Flt::DecNum.context(:precision=>decimals) do |local_context|
|
18
|
+
local_context.precision += 2 # extra digits for intermediate steps
|
19
|
+
while s != lasts
|
20
|
+
lasts = s
|
21
|
+
n, na = n+na, na+8
|
22
|
+
d, da = d+da, da+32
|
23
|
+
t = (t * n) / d
|
24
|
+
s += t
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return +s
|
28
|
+
end
|
29
|
+
|
30
|
+
# Cosine of angle in radians
|
31
|
+
def cos(x)
|
32
|
+
i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
|
33
|
+
DecNum.context do |local_context|
|
34
|
+
local_context.precision += 2 # extra digits for intermediate steps
|
35
|
+
while s != lasts
|
36
|
+
lasts = s
|
37
|
+
i += 2
|
38
|
+
fact *= i * (i-1)
|
39
|
+
num *= x * x
|
40
|
+
sign *= -1
|
41
|
+
s += num / fact * sign
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return +s
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sine of angle in radians
|
48
|
+
def sin(x)
|
49
|
+
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
|
50
|
+
DecNum.context do |local_context|
|
51
|
+
local_context.precision += 2 # extra digits for intermediate steps
|
52
|
+
while s != lasts
|
53
|
+
lasts = s
|
54
|
+
i += 2
|
55
|
+
fact *= i * (i-1)
|
56
|
+
num *= x * x
|
57
|
+
sign *= -1
|
58
|
+
s += num / fact * sign
|
59
|
+
end
|
60
|
+
end
|
61
|
+
return +s
|
62
|
+
end
|
63
|
+
|
64
|
+
end # Math
|
65
|
+
end # DecNum
|
66
|
+
end # Flt
|
data/lib/flt/num.rb
ADDED
@@ -0,0 +1,4211 @@
|
|
1
|
+
# Base classes for floating-point numbers and contexts.
|
2
|
+
|
3
|
+
#--
|
4
|
+
# =Notes on the representation of Flt::Num numbers.
|
5
|
+
#
|
6
|
+
# @sign is +1 for plus and -1 for minus
|
7
|
+
# @coeff is the integral significand stored as an integer (so leading zeros cannot be kept)
|
8
|
+
# @exp is the exponent to be applied to @coeff as an integer or one of :inf, :nan, :snan for special values
|
9
|
+
#
|
10
|
+
# The original Python Decimal representation has these slots:
|
11
|
+
# _sign is 1 for minus, 0 for plus
|
12
|
+
# _int is the integral significand as a string of digits (leading zeroes are not kept)
|
13
|
+
# _exp is the exponent as an integer or 'F' for infinity, 'n' for NaN , 'N' for sNaN
|
14
|
+
# _is_especial is true for special values (infinity, NaN, sNaN)
|
15
|
+
# An additional class _WorkRep is used in Python for non-special decimal values with:
|
16
|
+
# sign
|
17
|
+
# int (significand as an integer)
|
18
|
+
# exp
|
19
|
+
#
|
20
|
+
# =Exponent values
|
21
|
+
#
|
22
|
+
# In GDAS (General Decimal Arithmetic Specification) numbers are represented by an unnormalized integral
|
23
|
+
# significand and an exponent (also called 'scale'.)
|
24
|
+
#
|
25
|
+
# The reduce operation (originally called 'normalize') removes trailing 0s and increments the exponent if necessary;
|
26
|
+
# the representation is rescaled to use the maximum exponent possible (while maintaining an integral significand.)
|
27
|
+
#
|
28
|
+
# A classical floating-point normalize opwration would remove leading 0s and decrement the exponent instead,
|
29
|
+
# rescaling to the minimum exponent theat maintains the significand value under some conventional limit (1 or the radix).
|
30
|
+
#
|
31
|
+
# The logb and adjusted operations return the exponent that applies to the most significand digit (logb as a Decimal
|
32
|
+
# and adjusted as an integer.) This is the normalized scientific exponent.
|
33
|
+
#
|
34
|
+
# The most common normalized exponent is the normalized integral exponent for a fixed number of precision digits.
|
35
|
+
#
|
36
|
+
# The normalized fractional exponent is what BigDecima#exponent returns.
|
37
|
+
#
|
38
|
+
# ==Relations between exponent values
|
39
|
+
#
|
40
|
+
# The number of (kept) significand digits is s = a - e + 1
|
41
|
+
# where a is the adjusted exponent and e is the internal exponent (the unnormalized integral exponent.)
|
42
|
+
#
|
43
|
+
# The number of significant digits (excluding leading and trailing zeroes) is sr = a - re + 1
|
44
|
+
# where re is the internal exponent of the reduced value.
|
45
|
+
#
|
46
|
+
# The normalized integral exponent is e - (p - s) = a - p + 1
|
47
|
+
# where p is the fixed precision.
|
48
|
+
#
|
49
|
+
# The normalized fractional exponent is e + s = a + 1
|
50
|
+
#
|
51
|
+
# ==Example: 0.01204
|
52
|
+
#
|
53
|
+
# * The integral significand is 120400 and the internal exponent that applies to it is e = -7
|
54
|
+
# * The number of significand digits is s = 6
|
55
|
+
# * The reduced representation is 1204 with internal exponent re = -5
|
56
|
+
# * The number of significant digits sr = 4
|
57
|
+
# * The adjusted exponent is a = -2 (the adjusted representation is 1.204 with exponent -2)
|
58
|
+
# * Given a precision p = 8, the normalized integral representation is 12040000 with exponent -9
|
59
|
+
# * The normalized fractional representation is 0.1204 with exponent -1
|
60
|
+
#
|
61
|
+
# ==Exponent limits
|
62
|
+
#
|
63
|
+
# The (integral) exponent e must be within this limits: etiny <= e <= etop
|
64
|
+
# The adjusted exponent a must: emin <= a <= emax
|
65
|
+
# emin, emax are the limite of the exponent shown in scientific notation and are use to defined
|
66
|
+
# the exponent limits in the contexts.
|
67
|
+
# etiny = emin-precision+1 and etop=emax-precision+1 are the limits of the internal exponent.
|
68
|
+
# Note that for significands with less than precision digits we can use exponents greater than etop
|
69
|
+
# without causing overflow: +Decimal(+1,1,emax) == Decimal(+1,K,etop) where K=10**(precision-1)
|
70
|
+
#
|
71
|
+
# =Interoperatibility with other numeric types
|
72
|
+
#
|
73
|
+
# For some numeric types implicit conversion to DecNum is defined through these methods:
|
74
|
+
# * DecNum#coerce() is used when a Decimal is the right hand of an operator
|
75
|
+
# and the left hand is another numeric type
|
76
|
+
# * DecNum#_bin_op() used internally to define binary operators and use the Ruby coerce protocol:
|
77
|
+
# if the right-hand operand is of known type it is converted with Decimal; otherwise use coerce
|
78
|
+
# * _convert() converts known types to Decimal with Decimal() or raises an exception.
|
79
|
+
# * DecNum() casts known types and text representations of numbers to Decimal using the constructor.
|
80
|
+
# * DecNum#initialize performs the actual type conversion
|
81
|
+
#
|
82
|
+
# The known or 'coercible' types for DecNum are initially Integer and Rational, but this can be extended to
|
83
|
+
# other types using define_conversion_from() in a Context object.
|
84
|
+
#++
|
85
|
+
|
86
|
+
#--
|
87
|
+
# TODO: selecting the kind of ulp is awkward; consider one of these options:
|
88
|
+
# * don't support variant ulps; always use Muller's ulp
|
89
|
+
# * use an options hash for the kind of ulp parameter
|
90
|
+
# * keep the kind of ulp in the context
|
91
|
+
# also, note that Tolerance uses only the Muller king of ulp.
|
92
|
+
# TODO: move the exception classes from Flt::Num to Flt ? move also Flt::Num::ContextBas to Flt ?
|
93
|
+
# TODO: find better name for :all_digits (:preserve_precision, :mantain_precision, ...) ?
|
94
|
+
# TODO: should the context determine the mode for cross-base literal-to-Num conversion (:free, :fixed)?
|
95
|
+
# BinNum.context.input = :fixed; x = BinNum('0.1')
|
96
|
+
#++
|
97
|
+
|
98
|
+
require 'flt/support'
|
99
|
+
require 'flt/version'
|
100
|
+
|
101
|
+
require 'bigdecimal'
|
102
|
+
require 'forwardable'
|
103
|
+
require 'rational'
|
104
|
+
require 'monitor'
|
105
|
+
require 'ostruct'
|
106
|
+
|
107
|
+
module Flt
|
108
|
+
|
109
|
+
# Generic radix arbitrary-precision, floating-point numbers. This is a base class for
|
110
|
+
# floating point types of specific radix.
|
111
|
+
#
|
112
|
+
# The implementation of floating-point arithmetic is largely based on the Decimal module of Python,
|
113
|
+
# written by Eric Price, Facundo Batista, Raymond Hettinger, Aahz and Tim Peters.
|
114
|
+
class Num < Numeric
|
115
|
+
|
116
|
+
extend Support # allows use of unqualified FlagValues(), Flags(), etc.
|
117
|
+
include Support::AuxiliarFunctions # make auxiliar functions available unqualified to instance menthods
|
118
|
+
|
119
|
+
ROUND_HALF_EVEN = :half_even
|
120
|
+
ROUND_HALF_DOWN = :half_down
|
121
|
+
ROUND_HALF_UP = :half_up
|
122
|
+
ROUND_FLOOR = :floor
|
123
|
+
ROUND_CEILING = :ceiling
|
124
|
+
ROUND_DOWN = :down
|
125
|
+
ROUND_UP = :up
|
126
|
+
ROUND_05UP = :up05
|
127
|
+
|
128
|
+
# Numerical conversion base support
|
129
|
+
# base (default) coercible types associated to procedures for numerical conversion
|
130
|
+
@_base_coercible_types = {
|
131
|
+
Integer=>lambda{|x, context| x>=0 ? [+1,x,0] : [-1,-x,0]},
|
132
|
+
Rational=>lambda{|x, context|
|
133
|
+
x, y = context.num_class.new(x.numerator), context.num_class.new(x.denominator)
|
134
|
+
z = x.divide(y, context)
|
135
|
+
z
|
136
|
+
}
|
137
|
+
}
|
138
|
+
@_base_conversions = {
|
139
|
+
Integer=>:to_i, Rational=>:to_r, Float=>:to_f
|
140
|
+
}
|
141
|
+
class <<self
|
142
|
+
attr_reader :_base_coercible_types
|
143
|
+
attr_reader :_base_conversions
|
144
|
+
def base_coercible_types
|
145
|
+
Num._base_coercible_types
|
146
|
+
end
|
147
|
+
def base_conversions
|
148
|
+
Num._base_conversions
|
149
|
+
end
|
150
|
+
# We use this two level scheme to acces base_... because we're using instance variables of the object
|
151
|
+
# Num to store the base_... objects (and we store them to avoid generating them each time) and to access
|
152
|
+
# them would requiere that derived classes define their own versios of the accesors, even if they
|
153
|
+
# only call super.
|
154
|
+
end
|
155
|
+
|
156
|
+
# Base class for errors.
|
157
|
+
class Error < StandardError
|
158
|
+
end
|
159
|
+
|
160
|
+
# Base class for exceptions.
|
161
|
+
#
|
162
|
+
# All exception conditions derive from this class.
|
163
|
+
# The exception classes also define the values returned when trapping is disable for
|
164
|
+
# a particular exception.
|
165
|
+
class Exception < StandardError
|
166
|
+
attr :context
|
167
|
+
def initialize(context=nil)
|
168
|
+
@context = context
|
169
|
+
end
|
170
|
+
|
171
|
+
# Defines the value returned when trapping is inactive
|
172
|
+
# for the condition. The arguments are those passed to
|
173
|
+
# Context#exception after the message.
|
174
|
+
def self.handle(context, *args)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Invalid operation exception.
|
179
|
+
#
|
180
|
+
# The result of the operation is a quiet positive NaN,
|
181
|
+
# except when the cause is a signaling NaN, in which case the result is
|
182
|
+
# also a quiet NaN, but with the original sign, and an optional
|
183
|
+
# diagnostic information.
|
184
|
+
class InvalidOperation < Exception
|
185
|
+
def self.handle(context, *args)
|
186
|
+
if args.size>0
|
187
|
+
sign, coeff, exp = args.first.split
|
188
|
+
context.num_class.new([sign, coeff, :nan])._fix_nan(context)
|
189
|
+
else
|
190
|
+
context.num_class.nan
|
191
|
+
end
|
192
|
+
end
|
193
|
+
def initialize(context=nil, *args)
|
194
|
+
@value = args.first if args.size>0
|
195
|
+
super context
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Division by zero exception.
|
200
|
+
#
|
201
|
+
# The result of the operation is +/-Infinity, where the sign is the product
|
202
|
+
# of the signs of the operands for divide, or 1 for an odd power of -0.
|
203
|
+
class DivisionByZero < Exception
|
204
|
+
def self.handle(context,sign,*args)
|
205
|
+
context.num_class.infinity(sign)
|
206
|
+
end
|
207
|
+
def initialize(context=nil, sign=nil, *args)
|
208
|
+
@sign = sign
|
209
|
+
super context
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Cannot perform the division adequately exception.
|
214
|
+
#
|
215
|
+
# This occurs and signals invalid-operation if the integer result of a
|
216
|
+
# divide-integer or remainder operation had too many digits (would be
|
217
|
+
# longer than precision).
|
218
|
+
# The result is NaN.
|
219
|
+
class DivisionImpossible < Exception
|
220
|
+
def self.handle(context,*args)
|
221
|
+
context.num_class.nan
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Undefined result of division exception.
|
226
|
+
#
|
227
|
+
# This occurs and signals invalid-operation if division by zero was
|
228
|
+
# attempted (during a divide-integer, divide, or remainder operation), and
|
229
|
+
# the dividend is also zero.
|
230
|
+
# The result is NaN.
|
231
|
+
class DivisionUndefined < Exception
|
232
|
+
def self.handle(context,*args)
|
233
|
+
context.num_class.nan
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Inexact Exception.
|
238
|
+
#
|
239
|
+
# This occurs and signals inexact whenever the result of an operation is
|
240
|
+
# not exact (that is, it needed to be rounded and any discarded digits
|
241
|
+
# were non-zero), or if an overflow or underflow condition occurs. The
|
242
|
+
# result in all cases is unchanged unless the context has exact precision,
|
243
|
+
# in which case the result is Nan
|
244
|
+
class Inexact < Exception
|
245
|
+
def self.handle(context, *args)
|
246
|
+
context.num_class.nan if context.exact?
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Overflow Exception.
|
251
|
+
#
|
252
|
+
# This occurs and signals overflow if the adjusted exponent of a result
|
253
|
+
# (from a conversion or from an operation that is not an attempt to divide
|
254
|
+
# by zero), after rounding, would be greater than the largest value that
|
255
|
+
# can be handled by the implementation (the value Emax).
|
256
|
+
#
|
257
|
+
# The result depends on the rounding mode:
|
258
|
+
#
|
259
|
+
# For round-half-up and round-half-even (and for round-half-down and
|
260
|
+
# round-up, if implemented), the result of the operation is +/-Infinity,
|
261
|
+
# where the sign is that of the intermediate result. For round-down, the
|
262
|
+
# result is the largest finite number that can be represented in the
|
263
|
+
# current precision, with the sign of the intermediate result. For
|
264
|
+
# round-ceiling, the result is the same as for round-down if the sign of
|
265
|
+
# the intermediate result is 1, or is +Infinity otherwise. For round-floor,
|
266
|
+
# the result is the same as for round-down if the sign of the intermediate
|
267
|
+
# result is 0, or is -Infinity otherwise. In all cases, Inexact and Rounded
|
268
|
+
# will also be raised.
|
269
|
+
class Overflow < Exception
|
270
|
+
def self.handle(context, sign, *args)
|
271
|
+
if [:half_up, :half_even, :half_down, :up].include?(context.rounding)
|
272
|
+
context.num_class.infinity(sign)
|
273
|
+
elsif sign==+1
|
274
|
+
if context.rounding == :ceiling
|
275
|
+
context.num_class.infinity(sign)
|
276
|
+
else
|
277
|
+
context.num_class.new([sign, context.num_class.int_radix_power(context.precision) - 1, context.emax - context.precision + 1])
|
278
|
+
end
|
279
|
+
elsif sign==-1
|
280
|
+
if context.rounding == :floor
|
281
|
+
context.num_class.infinity(sign)
|
282
|
+
else
|
283
|
+
context.num_class.new([sign, context.num_class.int_radix_power(context.precision) - 1, context.emax - context.precision + 1])
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
def initialize(context=nil, sign=nil, *args)
|
288
|
+
@sign = sign
|
289
|
+
super context
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Numerical Underflow with result rounded to 0 exception.
|
294
|
+
#
|
295
|
+
# This occurs and signals underflow if a result is inexact and the
|
296
|
+
# adjusted exponent of the result would be smaller (more negative) than
|
297
|
+
# the smallest value that can be handled by the implementation (the value
|
298
|
+
# emin). That is, the result is both inexact and subnormal.
|
299
|
+
#
|
300
|
+
# The result after an underflow will be a subnormal number rounded, if
|
301
|
+
# necessary, so that its exponent is not less than Etiny. This may result
|
302
|
+
# in 0 with the sign of the intermediate result and an exponent of etiny.
|
303
|
+
#
|
304
|
+
# In all cases, Inexact, Rounded, and Subnormal will also be raised.
|
305
|
+
class Underflow < Exception
|
306
|
+
end
|
307
|
+
|
308
|
+
# Clamped exception: exponent of a 0 changed to fit bounds.
|
309
|
+
#
|
310
|
+
# This occurs and signals clamped if the exponent of a result has been
|
311
|
+
# altered in order to fit the constraints of a specific concrete
|
312
|
+
# representation. This may occur when the exponent of a zero result would
|
313
|
+
# be outside the bounds of a representation, or when a large normal
|
314
|
+
# number would have an encoded exponent that cannot be represented. In
|
315
|
+
# this latter case, the exponent is reduced to fit and the corresponding
|
316
|
+
# number of zero digits are appended to the coefficient ("fold-down").
|
317
|
+
class Clamped < Exception
|
318
|
+
end
|
319
|
+
|
320
|
+
# Invalid context exception.
|
321
|
+
#
|
322
|
+
# This occurs and signals invalid-operation if an invalid context was
|
323
|
+
# detected during an operation. This can occur if contexts are not checked
|
324
|
+
# on creation and either the precision exceeds the capability of the
|
325
|
+
# underlying concrete representation or an unknown or unsupported rounding
|
326
|
+
# was specified. These aspects of the context need only be checked when
|
327
|
+
# the values are required to be used. The result is NaN.
|
328
|
+
class InvalidContext < Exception
|
329
|
+
def self.handle(context,*args)
|
330
|
+
context.num_class.nan
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# Number got rounded exception (not necessarily changed during rounding).
|
335
|
+
#
|
336
|
+
# This occurs and signals rounded whenever the result of an operation is
|
337
|
+
# rounded (that is, some zero or non-zero digits were discarded from the
|
338
|
+
# coefficient), or if an overflow or underflow condition occurs. The
|
339
|
+
# result in all cases is unchanged.
|
340
|
+
class Rounded < Exception
|
341
|
+
end
|
342
|
+
|
343
|
+
# Exponent < emin before rounding exception.
|
344
|
+
#
|
345
|
+
# This occurs and signals subnormal whenever the result of a conversion or
|
346
|
+
# operation is subnormal (that is, its adjusted exponent is less than
|
347
|
+
# Emin, before any rounding). The result in all cases is unchanged.
|
348
|
+
class Subnormal < Exception
|
349
|
+
end
|
350
|
+
|
351
|
+
# Conversion syntax error exception (Trying to convert badly formed string.)
|
352
|
+
#
|
353
|
+
# This occurs and signals invalid-operation if an string is being
|
354
|
+
# converted to a number and it does not conform to the numeric string
|
355
|
+
# syntax. The result is NaN.
|
356
|
+
class ConversionSyntax < InvalidOperation
|
357
|
+
def self.handle(context, *args)
|
358
|
+
context.num_class.nan
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
EXCEPTIONS = FlagValues(Clamped, InvalidOperation, DivisionByZero, Inexact, Overflow, Underflow,
|
363
|
+
Rounded, Subnormal, DivisionImpossible, ConversionSyntax)
|
364
|
+
|
365
|
+
def self.Flags(*values)
|
366
|
+
Flt::Support::Flags(EXCEPTIONS,*values)
|
367
|
+
end
|
368
|
+
|
369
|
+
# Base class for Context classes.
|
370
|
+
#
|
371
|
+
# Derived classes will implement Floating-Point contexts for the specific
|
372
|
+
# floating-point types (DecNum, BinNum)
|
373
|
+
class ContextBase
|
374
|
+
# If an options hash is passed, the options are
|
375
|
+
# applied to the default context; if a Context is passed as the first
|
376
|
+
# argument, it is used as the base instead of the default context.
|
377
|
+
#
|
378
|
+
# The valid options are:
|
379
|
+
# * :rounding : one of :half_even, :half_down, :half_up, :floor,
|
380
|
+
# :ceiling, :down, :up, :up05
|
381
|
+
# * :precision : number of digits (or 0 for exact precision)
|
382
|
+
# * :exact : if true precision is ignored and Inexact conditions are trapped,
|
383
|
+
# if :quiet it set exact precision but no trapping;
|
384
|
+
# * :traps : a Flags object with the exceptions to be trapped
|
385
|
+
# * :flags : a Flags object with the raised flags
|
386
|
+
# * :ignored_flags : a Flags object with the exceptions to be ignored
|
387
|
+
# * :emin, :emax : minimum and maximum adjusted exponents
|
388
|
+
# * :elimit : the exponent limits can also be defined by a single value;
|
389
|
+
# if positive it is taken as emax and emin=1-emax; otherwiae it is
|
390
|
+
# taken as emin and emax=1-emin. Such limits comply with IEEE 754-2008
|
391
|
+
# * :capitals : (true or false) to use capitals in text representations
|
392
|
+
# * :clamp : (true or false) enables clamping
|
393
|
+
#
|
394
|
+
# See also the context constructor method Flt::Num.Context().
|
395
|
+
def initialize(num_class, *options)
|
396
|
+
@num_class = num_class
|
397
|
+
|
398
|
+
if options.first.kind_of?(ContextBase)
|
399
|
+
base = options.shift
|
400
|
+
copy_from base
|
401
|
+
else
|
402
|
+
@exact = false
|
403
|
+
@rounding = @emin = @emax = nil
|
404
|
+
@capitals = false
|
405
|
+
@clamp = false
|
406
|
+
@ignored_flags = Num::Flags()
|
407
|
+
@traps = Num::Flags()
|
408
|
+
@flags = Num::Flags()
|
409
|
+
@coercible_type_handlers = num_class.base_coercible_types.dup
|
410
|
+
@conversions = num_class.base_conversions.dup
|
411
|
+
end
|
412
|
+
assign options.first
|
413
|
+
|
414
|
+
end
|
415
|
+
|
416
|
+
# This gives access to the numeric class (Flt::Num-derived) this context is for.
|
417
|
+
def num_class
|
418
|
+
@num_class
|
419
|
+
end
|
420
|
+
|
421
|
+
# Constructor for the associated numeric class
|
422
|
+
def Num(*args)
|
423
|
+
num_class.Num(*args)
|
424
|
+
end
|
425
|
+
|
426
|
+
def radix
|
427
|
+
@num_class.radix
|
428
|
+
end
|
429
|
+
|
430
|
+
# Integral power of the base: radix**n for integer n; returns an integer.
|
431
|
+
def int_radix_power(n)
|
432
|
+
@num_class.int_radix_power(n)
|
433
|
+
end
|
434
|
+
|
435
|
+
# Multiply by an integral power of the base: x*(radix**n) for x,n integer;
|
436
|
+
# returns an integer.
|
437
|
+
def int_mult_radix_power(x,n)
|
438
|
+
@num_class.int_mult_radix_power(x,n)
|
439
|
+
end
|
440
|
+
|
441
|
+
# Divide by an integral power of the base: x/(radix**n) for x,n integer;
|
442
|
+
# returns an integer.
|
443
|
+
def int_div_radix_power(x,n)
|
444
|
+
@num_class.int_div_radix_power(x,n)
|
445
|
+
end
|
446
|
+
|
447
|
+
attr_accessor :rounding, :emin, :emax, :flags, :traps, :ignored_flags, :capitals, :clamp
|
448
|
+
|
449
|
+
# TODO: consider the convenience of adding accessors of this kind:
|
450
|
+
# def rounding(new_rounding=nil)
|
451
|
+
# old_rounding = @rounding
|
452
|
+
# @rounding = new_rounding unless new_rounding.nil?
|
453
|
+
# old_rounding
|
454
|
+
# end
|
455
|
+
|
456
|
+
# Ignore all flags if they are raised
|
457
|
+
def ignore_all_flags
|
458
|
+
#@ignored_flags << EXCEPTIONS
|
459
|
+
@ignored_flags.set!
|
460
|
+
end
|
461
|
+
|
462
|
+
# Ignore a specified set of flags if they are raised
|
463
|
+
def ignore_flags(*flags)
|
464
|
+
#@ignored_flags << flags
|
465
|
+
@ignored_flags.set(*flags)
|
466
|
+
end
|
467
|
+
|
468
|
+
# Stop ignoring a set of flags, if they are raised
|
469
|
+
def regard_flags(*flags)
|
470
|
+
@ignored_flags.clear(*flags)
|
471
|
+
end
|
472
|
+
|
473
|
+
# 'tiny' exponent (emin - precision + 1)
|
474
|
+
# is the minimum valid value for the (integral) exponent
|
475
|
+
def etiny
|
476
|
+
emin - precision + 1
|
477
|
+
end
|
478
|
+
|
479
|
+
# top exponent (emax - precision + 1)
|
480
|
+
# is the maximum valid value for the (integral) exponent
|
481
|
+
def etop
|
482
|
+
emax - precision + 1
|
483
|
+
end
|
484
|
+
|
485
|
+
# Set the exponent limits, according to IEEE 754-2008
|
486
|
+
# if e > 0 it is taken as emax and emin=1-emax
|
487
|
+
# if e < 0 it is taken as emin and emax=1-emin
|
488
|
+
def elimit=(e)
|
489
|
+
@emin, @emax = [elimit, 1-elimit].sort
|
490
|
+
end
|
491
|
+
|
492
|
+
# synonym for precision()
|
493
|
+
def digits
|
494
|
+
self.precision
|
495
|
+
end
|
496
|
+
|
497
|
+
# synonym for precision=()
|
498
|
+
def digits=(n)
|
499
|
+
self.precision=n
|
500
|
+
end
|
501
|
+
|
502
|
+
# synonym for precision()
|
503
|
+
def prec
|
504
|
+
self.precision
|
505
|
+
end
|
506
|
+
|
507
|
+
# synonym for precision=()
|
508
|
+
def prec=(n)
|
509
|
+
self.precision = n
|
510
|
+
end
|
511
|
+
|
512
|
+
# is clamping enabled?
|
513
|
+
def clamp?
|
514
|
+
@clamp
|
515
|
+
end
|
516
|
+
|
517
|
+
# Set the number of digits of precision.
|
518
|
+
# If 0 is set the precision turns to be exact.
|
519
|
+
def precision=(n)
|
520
|
+
@precision = n
|
521
|
+
@exact = false unless n==0
|
522
|
+
update_precision
|
523
|
+
n
|
524
|
+
end
|
525
|
+
|
526
|
+
# Number of digits of precision
|
527
|
+
def precision
|
528
|
+
@precision
|
529
|
+
end
|
530
|
+
|
531
|
+
# Enables or disables the exact precision
|
532
|
+
def exact=(v)
|
533
|
+
@exact = v
|
534
|
+
update_precision
|
535
|
+
v
|
536
|
+
end
|
537
|
+
|
538
|
+
# Returns true if the precision is exact
|
539
|
+
def exact
|
540
|
+
@exact
|
541
|
+
end
|
542
|
+
|
543
|
+
# Returns true if the precision is exact
|
544
|
+
def exact?
|
545
|
+
@exact
|
546
|
+
end
|
547
|
+
|
548
|
+
# Alters the contexts by assigning options from a Hash. See DecNum#new() for the valid options.
|
549
|
+
def assign(options)
|
550
|
+
if options
|
551
|
+
@rounding = options[:rounding] unless options[:rounding].nil?
|
552
|
+
@precision = options[:precision] unless options[:precision].nil?
|
553
|
+
@traps = DecNum::Flags(options[:traps]) unless options[:traps].nil?
|
554
|
+
@flags = DecNum::Flags(options[:flags]) unless options[:flags].nil?
|
555
|
+
@ignored_flags = DecNum::Flags(options[:ignored_flags]) unless options[:ignored_flags].nil?
|
556
|
+
if elimit=options[:elimit]
|
557
|
+
@emin, @emax = [elimit, 1-elimit].sort
|
558
|
+
end
|
559
|
+
@emin = options[:emin] unless options[:emin].nil?
|
560
|
+
@emax = options[:emax] unless options[:emax].nil?
|
561
|
+
@capitals = options[:capitals ] unless options[:capitals ].nil?
|
562
|
+
@clamp = options[:clamp ] unless options[:clamp ].nil?
|
563
|
+
@exact = options[:exact ] unless options[:exact ].nil?
|
564
|
+
update_precision
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
attr_reader :coercible_type_handlers, :conversions
|
569
|
+
protected :coercible_type_handlers, :conversions
|
570
|
+
|
571
|
+
# Copy the state from other Context object.
|
572
|
+
def copy_from(other)
|
573
|
+
raise TypeError, "Assign #{other.num_class} context to #{self.num_class} context" if other.num_class != self.num_class
|
574
|
+
@rounding = other.rounding
|
575
|
+
@precision = other.precision
|
576
|
+
@traps = other.traps.dup
|
577
|
+
@flags = other.flags.dup
|
578
|
+
@ignored_flags = other.ignored_flags.dup
|
579
|
+
@emin = other.emin
|
580
|
+
@emax = other.emax
|
581
|
+
@capitals = other.capitals
|
582
|
+
@clamp = other.clamp
|
583
|
+
@exact = other.exact
|
584
|
+
@coercible_type_handlers = other.coercible_type_handlers.dup
|
585
|
+
@conversions = other.conversions.dup
|
586
|
+
end
|
587
|
+
|
588
|
+
def dup
|
589
|
+
self.class.new(self)
|
590
|
+
end
|
591
|
+
|
592
|
+
CONDITION_MAP = {
|
593
|
+
#ConversionSyntax=>InvalidOperation,
|
594
|
+
#DivisionImpossible=>InvalidOperation,
|
595
|
+
DivisionUndefined=>InvalidOperation,
|
596
|
+
InvalidContext=>InvalidOperation
|
597
|
+
}
|
598
|
+
|
599
|
+
# Raises a flag (unless it is being ignores) and raises and
|
600
|
+
# exceptioin if the trap for it is enabled.
|
601
|
+
def exception(cond, msg='', *params)
|
602
|
+
err = (CONDITION_MAP[cond] || cond)
|
603
|
+
return err.handle(self, *params) if @ignored_flags[err]
|
604
|
+
@flags << err # @flags[err] = true
|
605
|
+
return cond.handle(self, *params) if !@traps[err]
|
606
|
+
raise err.new(*params), msg
|
607
|
+
end
|
608
|
+
|
609
|
+
# Addition of two decimal numbers
|
610
|
+
def add(x,y)
|
611
|
+
_convert(x).add(y,self)
|
612
|
+
end
|
613
|
+
|
614
|
+
# Subtraction of two decimal numbers
|
615
|
+
def subtract(x,y)
|
616
|
+
_convert(x).subtract(y,self)
|
617
|
+
end
|
618
|
+
|
619
|
+
# Multiplication of two decimal numbers
|
620
|
+
def multiply(x,y)
|
621
|
+
_convert(x).multiply(y,self)
|
622
|
+
end
|
623
|
+
|
624
|
+
# Division of two decimal numbers
|
625
|
+
def divide(x,y)
|
626
|
+
_convert(x).divide(y,self)
|
627
|
+
end
|
628
|
+
|
629
|
+
# Absolute value of a decimal number
|
630
|
+
def abs(x)
|
631
|
+
_convert(x).abs(self)
|
632
|
+
end
|
633
|
+
|
634
|
+
# Unary prefix plus operator
|
635
|
+
def plus(x)
|
636
|
+
_convert(x).plus(self)
|
637
|
+
end
|
638
|
+
|
639
|
+
# Unary prefix minus operator
|
640
|
+
def minus(x)
|
641
|
+
_convert(x)._neg(self)
|
642
|
+
end
|
643
|
+
|
644
|
+
# Converts a number to a string
|
645
|
+
def to_string(x, eng=false)
|
646
|
+
_convert(x)._fix(self).to_s(eng, self)
|
647
|
+
end
|
648
|
+
|
649
|
+
# Converts a number to a string, using scientific notation
|
650
|
+
def to_sci_string(x)
|
651
|
+
to_string x, false
|
652
|
+
end
|
653
|
+
|
654
|
+
# Converts a number to a string, using engineering notation
|
655
|
+
def to_eng_string(x)
|
656
|
+
to_string x, true
|
657
|
+
end
|
658
|
+
|
659
|
+
# Reduces an operand to its simplest form
|
660
|
+
# by removing trailing 0s and incrementing the exponent.
|
661
|
+
# (formerly called normalize in GDAS)
|
662
|
+
def reduce(x)
|
663
|
+
_convert(x).reduce(self)
|
664
|
+
end
|
665
|
+
|
666
|
+
# Normalizes (changes quantum) so that the coefficient has precision digits, unless it is subnormal.
|
667
|
+
# For surnormal numbers the Subnormal flag is raised an a subnormal is returned with the smallest
|
668
|
+
# possible exponent.
|
669
|
+
#
|
670
|
+
# This is different from reduce GDAS function which was formerly called normalize, and corresponds
|
671
|
+
# to the classic meaning of floating-point normalization.
|
672
|
+
#
|
673
|
+
# Note that the number is also rounded (precision is reduced) if it had more precision than the context.
|
674
|
+
def normalize(x)
|
675
|
+
_convert(x).normalize(self)
|
676
|
+
end
|
677
|
+
|
678
|
+
# Adjusted exponent of x returned as a DecNum value.
|
679
|
+
def logb(x)
|
680
|
+
_convert(x).logb(self)
|
681
|
+
end
|
682
|
+
|
683
|
+
# Adds the second value to the exponent of the first: x*(radix**y)
|
684
|
+
#
|
685
|
+
# y must be an integer
|
686
|
+
def scaleb(x, y)
|
687
|
+
_convert(x).scaleb(y,self)
|
688
|
+
end
|
689
|
+
|
690
|
+
# Exponent in relation to the significand as an integer
|
691
|
+
# normalized to precision digits. (minimum exponent)
|
692
|
+
def normalized_integral_exponent(x)
|
693
|
+
x = _convert(x)
|
694
|
+
x.exponent - (precision - x.number_of_digits)
|
695
|
+
end
|
696
|
+
|
697
|
+
# Significand normalized to precision digits
|
698
|
+
# x == normalized_integral_significand(x) * radix**(normalized_integral_exponent)
|
699
|
+
def normalized_integral_significand(x)
|
700
|
+
x = _convert(x)
|
701
|
+
x.coefficient*(num_class.int_radix_power(precision - x.number_of_digits))
|
702
|
+
end
|
703
|
+
|
704
|
+
# Returns both the (signed) normalized integral significand and the corresponding exponent
|
705
|
+
def to_normalized_int_scale(x)
|
706
|
+
x = _convert(x)
|
707
|
+
[x.sign*normalized_integral_significand(x), normalized_integral_exponent(x)]
|
708
|
+
end
|
709
|
+
|
710
|
+
# Is a normal number?
|
711
|
+
def normal?(x)
|
712
|
+
_convert(x).normal?(self)
|
713
|
+
end
|
714
|
+
|
715
|
+
# Is a subnormal number?
|
716
|
+
def subnormal?(x)
|
717
|
+
_convert(x).subnormal?(self)
|
718
|
+
end
|
719
|
+
|
720
|
+
# Classifies a number as one of
|
721
|
+
# 'sNaN', 'NaN', '-Infinity', '-Normal', '-Subnormal', '-Zero',
|
722
|
+
# '+Zero', '+Subnormal', '+Normal', '+Infinity'
|
723
|
+
def number_class(x)
|
724
|
+
_convert(x).number_class(self)
|
725
|
+
end
|
726
|
+
|
727
|
+
# Square root of a decimal number
|
728
|
+
def sqrt(x)
|
729
|
+
_convert(x).sqrt(self)
|
730
|
+
end
|
731
|
+
|
732
|
+
# Ruby-style integer division: (x/y).floor
|
733
|
+
def div(x,y)
|
734
|
+
_convert(x).div(y,self)
|
735
|
+
end
|
736
|
+
|
737
|
+
# Ruby-style modulo: x - y*div(x,y)
|
738
|
+
def modulo(x,y)
|
739
|
+
_convert(x).modulo(y,self)
|
740
|
+
end
|
741
|
+
|
742
|
+
# Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
|
743
|
+
def divmod(x,y)
|
744
|
+
_convert(x).divmod(y,self)
|
745
|
+
end
|
746
|
+
|
747
|
+
# General Decimal Arithmetic Specification integer division: (x/y).truncate
|
748
|
+
def divide_int(x,y)
|
749
|
+
_convert(x).divide_int(y,self)
|
750
|
+
end
|
751
|
+
|
752
|
+
# General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
|
753
|
+
def remainder(x,y)
|
754
|
+
_convert(x).remainder(y,self)
|
755
|
+
end
|
756
|
+
|
757
|
+
# General Decimal Arithmetic Specification remainder-near
|
758
|
+
# x - y*round_half_even(x/y)
|
759
|
+
def remainder_near(x,y)
|
760
|
+
_convert(x).remainder_near(y,self)
|
761
|
+
end
|
762
|
+
|
763
|
+
# General Decimal Arithmetic Specification integer division and remainder:
|
764
|
+
# (x/y).truncate, x - y*(x/y).truncate
|
765
|
+
def divrem(x,y)
|
766
|
+
_convert(x).divrem(y,self)
|
767
|
+
end
|
768
|
+
|
769
|
+
# Fused multiply-add.
|
770
|
+
#
|
771
|
+
# Computes (x*y+z) with no rounding of the intermediate product x*y.
|
772
|
+
def fma(x,y,z)
|
773
|
+
_convert(x).fma(y,z,self)
|
774
|
+
end
|
775
|
+
|
776
|
+
# Compares like <=> but returns a DecNum value.
|
777
|
+
# * -1 if x < y
|
778
|
+
# * 0 if x == b
|
779
|
+
# * +1 if x > y
|
780
|
+
# * NaN if x or y is NaN
|
781
|
+
def compare(x,y)
|
782
|
+
_convert(x).compare(y, self)
|
783
|
+
end
|
784
|
+
|
785
|
+
# Returns a copy of x with the sign set to +
|
786
|
+
def copy_abs(x)
|
787
|
+
_convert(x).copy_abs
|
788
|
+
end
|
789
|
+
|
790
|
+
# Returns a copy of x with the sign inverted
|
791
|
+
def copy_negate(x)
|
792
|
+
_convert(x).copy_negate
|
793
|
+
end
|
794
|
+
|
795
|
+
# Returns a copy of x with the sign of y
|
796
|
+
def copy_sign(x,y)
|
797
|
+
_convert(x).copy_sign(y)
|
798
|
+
end
|
799
|
+
|
800
|
+
# Rescale x so that the exponent is exp, either by padding with zeros
|
801
|
+
# or by truncating digits.
|
802
|
+
def rescale(x, exp, watch_exp=true)
|
803
|
+
_convert(x).rescale(exp, self, watch_exp)
|
804
|
+
end
|
805
|
+
|
806
|
+
# Quantize x so its exponent is the same as that of y.
|
807
|
+
def quantize(x, y, watch_exp=true)
|
808
|
+
_convert(x).quantize(y, self, watch_exp)
|
809
|
+
end
|
810
|
+
|
811
|
+
# Return true if x and y have the same exponent.
|
812
|
+
#
|
813
|
+
# If either operand is a special value, the following rules are used:
|
814
|
+
# * return true if both operands are infinities
|
815
|
+
# * return true if both operands are NaNs
|
816
|
+
# * otherwise, return false.
|
817
|
+
def same_quantum?(x,y)
|
818
|
+
_convert(x).same_quantum?(y)
|
819
|
+
end
|
820
|
+
|
821
|
+
# Rounds to a nearby integer.
|
822
|
+
#
|
823
|
+
# See also: DecNum#to_integral_value(), which does exactly the same as
|
824
|
+
# this method except that it doesn't raise Inexact or Rounded.
|
825
|
+
def to_integral_exact(x)
|
826
|
+
_convert(x).to_integral_exact(self)
|
827
|
+
end
|
828
|
+
|
829
|
+
# Rounds to a nearby integerwithout raising inexact, rounded.
|
830
|
+
#
|
831
|
+
# See also: DecNum#to_integral_exact(), which does exactly the same as
|
832
|
+
# this method except that it may raise Inexact or Rounded.
|
833
|
+
def to_integral_value(x)
|
834
|
+
_convert(x).to_integral_value(self)
|
835
|
+
end
|
836
|
+
|
837
|
+
# Returns the largest representable number smaller than x.
|
838
|
+
def next_minus(x)
|
839
|
+
_convert(x).next_minus(self)
|
840
|
+
end
|
841
|
+
|
842
|
+
# Returns the smallest representable number larger than x.
|
843
|
+
def next_plus(x)
|
844
|
+
_convert(x).next_plus(self)
|
845
|
+
end
|
846
|
+
|
847
|
+
# Returns the number closest to x, in the direction towards y.
|
848
|
+
#
|
849
|
+
# The result is the closest representable number to x
|
850
|
+
# (excluding x) that is in the direction towards y,
|
851
|
+
# unless both have the same value. If the two operands are
|
852
|
+
# numerically equal, then the result is a copy of x with the
|
853
|
+
# sign set to be the same as the sign of y.
|
854
|
+
def next_toward(x, y)
|
855
|
+
_convert(x).next_toward(y, self)
|
856
|
+
end
|
857
|
+
|
858
|
+
# ulp (unit in the last place) according to the definition proposed by J.M. Muller in
|
859
|
+
# "On the definition of ulp(x)" INRIA No. 5504
|
860
|
+
def ulp(x=nil, mode=:low)
|
861
|
+
x ||= 1
|
862
|
+
_convert(x).ulp(self, mode)
|
863
|
+
end
|
864
|
+
|
865
|
+
# Some singular DecNum values that depend on the context
|
866
|
+
|
867
|
+
# Maximum finite number
|
868
|
+
def maximum_finite(sign=+1)
|
869
|
+
return exception(InvalidOperation, "Exact context maximum finite value") if exact?
|
870
|
+
# equals +Num(+1, 1, emax)
|
871
|
+
# equals Num.infinity.next_minus(self)
|
872
|
+
Num(sign, num_class.int_radix_power(precision)-1, etop)
|
873
|
+
end
|
874
|
+
|
875
|
+
# Minimum positive normal number
|
876
|
+
def minimum_normal(sign=+1)
|
877
|
+
return exception(InvalidOperation, "Exact context maximum normal value") if exact?
|
878
|
+
#Num(sign, 1, emin).normalize(self)
|
879
|
+
Num(sign, minimum_normalized_coefficient, etiny)
|
880
|
+
end
|
881
|
+
|
882
|
+
# Maximum subnormal number
|
883
|
+
def maximum_subnormal(sign=+1)
|
884
|
+
return exception(InvalidOperation, "Exact context maximum subnormal value") if exact?
|
885
|
+
# equals mininum_normal.next_minus(self)
|
886
|
+
Num(sign, num_class.int_radix_power(precision-1)-1, etiny)
|
887
|
+
end
|
888
|
+
|
889
|
+
# Minimum nonzero positive number (minimum positive subnormal)
|
890
|
+
def minimum_nonzero(sign=+1)
|
891
|
+
return exception(InvalidOperation, "Exact context minimum nonzero value") if exact?
|
892
|
+
Num(sign, 1, etiny)
|
893
|
+
end
|
894
|
+
|
895
|
+
# This is the difference between 1 and the smallest DecNum
|
896
|
+
# value greater than 1: (DecNum(1).next_plus - DecNum(1))
|
897
|
+
def epsilon(sign=+1)
|
898
|
+
return exception(InvalidOperation, "Exact context epsilon") if exact?
|
899
|
+
Num(sign, 1, 1-precision)
|
900
|
+
end
|
901
|
+
|
902
|
+
# The strict epsilon is the smallest value that produces something different from 1
|
903
|
+
# wehen added to 1. It may be smaller than the general epsilon, because
|
904
|
+
# of the particular rounding rules used.
|
905
|
+
def strict_epsilon(sign=+1)
|
906
|
+
return exception(InvalidOperation, "Exact context strict epsilon") if exact?
|
907
|
+
# assume radix is even (num_class.radix%2 == 0)
|
908
|
+
case rounding
|
909
|
+
when :down, :floor
|
910
|
+
# largest epsilon: 0.0...10 (precision digits shown to the right of the decimal point)
|
911
|
+
exp = 1-precision
|
912
|
+
coeff = 1
|
913
|
+
when :half_even, :half_down
|
914
|
+
# next largest: 0.0...050...1 (+precision-1 additional digits here)
|
915
|
+
exp = 1-2*precision
|
916
|
+
coeff = 1 + num_class.int_radix_power(precision)/2
|
917
|
+
when :half_up
|
918
|
+
# next largest: 0.0...05 (precision digits shown to the right of the decimal point)
|
919
|
+
exp = 1-2*precision
|
920
|
+
coeff = num_class.int_radix_power(precision)/2
|
921
|
+
when :up, :ceiling, :up05
|
922
|
+
# smallest epsilon
|
923
|
+
return minimum_nonzero(sign)
|
924
|
+
end
|
925
|
+
return Num(sign, coeff, exp)
|
926
|
+
end
|
927
|
+
|
928
|
+
# This is the maximum relative error corresponding to 1/2 ulp:
|
929
|
+
# (radix/2)*radix**(-precision) == epsilon/2
|
930
|
+
# This is called "machine epsilon" in Goldberg's "What Every Computer Scientist..."
|
931
|
+
def half_epsilon(sign=+1)
|
932
|
+
Num(sign, num_class.radix/2, -precision)
|
933
|
+
end
|
934
|
+
|
935
|
+
def to_s
|
936
|
+
inspect
|
937
|
+
end
|
938
|
+
|
939
|
+
def inspect
|
940
|
+
class_name = self.class.to_s.split('::').last
|
941
|
+
"<#{class_name}:\n" +
|
942
|
+
instance_variables.map { |v| " #{v}: #{eval(v).inspect}"}.join("\n") +
|
943
|
+
">\n"
|
944
|
+
end
|
945
|
+
|
946
|
+
# Maximum integral significand value for numbers using this context's precision.
|
947
|
+
def maximum_coefficient
|
948
|
+
if exact?
|
949
|
+
exception(InvalidOperation, 'Exact maximum coefficient')
|
950
|
+
nil
|
951
|
+
else
|
952
|
+
num_class.int_radix_power(precision)-1
|
953
|
+
end
|
954
|
+
end
|
955
|
+
|
956
|
+
# Minimum value of a normalized coefficient (normalized unit)
|
957
|
+
def minimum_normalized_coefficient
|
958
|
+
if exact?
|
959
|
+
exception(InvalidOperation, 'Exact maximum coefficient')
|
960
|
+
nil
|
961
|
+
else
|
962
|
+
num_class.int_radix_power(precision-1)
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
# Maximum number of diagnostic digits in NaNs for numbers using this context's precision.
|
967
|
+
def maximum_nan_diagnostic_digits
|
968
|
+
if exact?
|
969
|
+
nil # ?
|
970
|
+
else
|
971
|
+
precision - (clamp ? 1 : 0)
|
972
|
+
end
|
973
|
+
end
|
974
|
+
|
975
|
+
# Internal use: array of numeric types that be coerced to DecNum.
|
976
|
+
def coercible_types
|
977
|
+
@coercible_type_handlers.keys
|
978
|
+
end
|
979
|
+
|
980
|
+
# Internal use: array of numeric types that be coerced to DecNum, including DecNum
|
981
|
+
def coercible_types_or_num
|
982
|
+
[num_class] + coercible_types
|
983
|
+
end
|
984
|
+
|
985
|
+
# Internally used to convert numeric types to DecNum (or to an array [sign,coefficient,exponent])
|
986
|
+
def _coerce(x)
|
987
|
+
c = x.class
|
988
|
+
while c!=Object && (h=@coercible_type_handlers[c]).nil?
|
989
|
+
c = c.superclass
|
990
|
+
end
|
991
|
+
if h
|
992
|
+
h.call(x, self)
|
993
|
+
else
|
994
|
+
nil
|
995
|
+
end
|
996
|
+
end
|
997
|
+
|
998
|
+
# Define a numerical conversion from type to DecNum.
|
999
|
+
# The block that defines the conversion has two parameters: the value to be converted and the context and
|
1000
|
+
# must return either a DecNum or [sign,coefficient,exponent]
|
1001
|
+
def define_conversion_from(type, &blk)
|
1002
|
+
@coercible_type_handlers[type] = blk
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
# Define a numerical conversion from DecNum to type as an instance method of DecNum
|
1006
|
+
def define_conversion_to(type, &blk)
|
1007
|
+
@conversions[type] = blk
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
# Convert a DecNum x to other numerical type
|
1011
|
+
def convert_to(type, x)
|
1012
|
+
converter = @conversions[type]
|
1013
|
+
if converter.nil?
|
1014
|
+
raise TypeError, "Undefined conversion from DecNum to #{type}."
|
1015
|
+
elsif converter.is_a?(Symbol)
|
1016
|
+
x.send converter
|
1017
|
+
else
|
1018
|
+
converter.call(x)
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
# Simply calls x.split; implemented to ease handling Float and BigDecimal as Nums withoug
|
1023
|
+
# having to add methods like split to those classes.
|
1024
|
+
def split(x)
|
1025
|
+
_convert(x).split
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
def to_int_scale(x)
|
1029
|
+
_convert(x).to_int_scale
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
def sign(x)
|
1033
|
+
_convert(x).sign
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
def coefficient(x)
|
1037
|
+
_convert(x).coefficient
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
def exponent(x)
|
1041
|
+
_convert(x).exponent
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
def nan?(x)
|
1045
|
+
_convert(x).nan?
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def infinite?(x)
|
1049
|
+
_convert(x).infinite?
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
def zero?(x)
|
1053
|
+
_convert(x).zero?
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
private
|
1057
|
+
|
1058
|
+
def _convert(x)
|
1059
|
+
# cannot call AuxiliarFunctions._convert now because it needs num_class
|
1060
|
+
# alternatives:
|
1061
|
+
# num_class.send(:_convert, x) # cannot num_class._convert because it is private
|
1062
|
+
# extend ContextBase with AuxiliarFunctions
|
1063
|
+
@num_class.send :_convert, x
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def update_precision
|
1067
|
+
if @emax && !@emin
|
1068
|
+
@emin = 1 - @emax
|
1069
|
+
elsif @emin && !@emax
|
1070
|
+
@emax = 1 - @emin
|
1071
|
+
end
|
1072
|
+
if @exact || @precision==0
|
1073
|
+
quiet = (@exact == :quiet)
|
1074
|
+
@exact = true
|
1075
|
+
@precision = 0
|
1076
|
+
@traps << Inexact unless quiet
|
1077
|
+
@ignored_flags[Inexact] = false
|
1078
|
+
else
|
1079
|
+
@traps[Inexact] = false
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
# Context constructor; if an options hash is passed, the options are
|
1086
|
+
# applied to the default context; if a Context is passed as the first
|
1087
|
+
# argument, it is used as the base instead of the default context.
|
1088
|
+
#
|
1089
|
+
# Note that this method should be called on concrete floating point types such as
|
1090
|
+
# Flt::DecNum and Flt::BinNum, and not in the abstract base class Flt::Num.
|
1091
|
+
#
|
1092
|
+
# See Flt::Num::ContextBase#new() for the valid options
|
1093
|
+
def self.Context(*args)
|
1094
|
+
case args.size
|
1095
|
+
when 0
|
1096
|
+
base = self::DefaultContext
|
1097
|
+
when 1
|
1098
|
+
arg = args.first
|
1099
|
+
if arg.instance_of?(self::Context)
|
1100
|
+
base = arg
|
1101
|
+
options = nil
|
1102
|
+
elsif arg.instance_of?(Hash)
|
1103
|
+
base = self::DefaultContext
|
1104
|
+
options = arg
|
1105
|
+
else
|
1106
|
+
raise TypeError,"invalid argument for #{num_class}.Context"
|
1107
|
+
end
|
1108
|
+
when 2
|
1109
|
+
base = args.first
|
1110
|
+
options = args.last
|
1111
|
+
else
|
1112
|
+
raise ArgumentError,"wrong number of arguments (#{args.size} for 0, 1 or 2)"
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
if options.nil? || options.empty?
|
1116
|
+
base
|
1117
|
+
else
|
1118
|
+
self::Context.new(base, options)
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
# Define a context by passing either of:
|
1124
|
+
# * A Context object (of the same type)
|
1125
|
+
# * A hash of options (or nothing) to alter a copy of the current context.
|
1126
|
+
# * A Context object and a hash of options to alter a copy of it
|
1127
|
+
def self.define_context(*options)
|
1128
|
+
context = options.shift if options.first.instance_of?(self::Context)
|
1129
|
+
if context && options.empty?
|
1130
|
+
context
|
1131
|
+
else
|
1132
|
+
context ||= self.context
|
1133
|
+
self.Context(context, *options)
|
1134
|
+
end
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
# This makes the class define context accesible to instance methods
|
1138
|
+
def define_context(*options)
|
1139
|
+
self.class.define_context(*options)
|
1140
|
+
end
|
1141
|
+
private :define_context
|
1142
|
+
|
1143
|
+
# The current context (thread-local).
|
1144
|
+
# If arguments are passed they are interpreted as in Num.define_context() to change
|
1145
|
+
# the current context.
|
1146
|
+
# If a block is given, this method is a synonym for Num.local_context().
|
1147
|
+
def self.context(*args, &blk)
|
1148
|
+
if blk
|
1149
|
+
# setup a local context
|
1150
|
+
local_context(*args, &blk)
|
1151
|
+
elsif args.empty?
|
1152
|
+
# return the current context
|
1153
|
+
# return the current context
|
1154
|
+
self._context = self::DefaultContext.dup if _context.nil?
|
1155
|
+
_context
|
1156
|
+
else
|
1157
|
+
# change the current context
|
1158
|
+
# TODO: consider doing self._context = ... here
|
1159
|
+
# so we would have DecNum.context = c that assigns a duplicate of c
|
1160
|
+
# and DecNum.context c to set alias c
|
1161
|
+
self.context = define_context(*args)
|
1162
|
+
end
|
1163
|
+
end
|
1164
|
+
|
1165
|
+
# Change the current context (thread-local).
|
1166
|
+
def self.context=(c)
|
1167
|
+
self._context = c.dup
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
# Defines a scope with a local context. A context can be passed which will be
|
1171
|
+
# set a the current context for the scope; also a hash can be passed with
|
1172
|
+
# options to apply to the local scope.
|
1173
|
+
# Changes done to the current context are reversed when the scope is exited.
|
1174
|
+
def self.local_context(*args)
|
1175
|
+
keep = self.context # use this so _context is initialized if necessary
|
1176
|
+
self.context = define_context(*args) # this dups the assigned context
|
1177
|
+
result = yield _context
|
1178
|
+
# TODO: consider the convenience of copying the flags from DecNum.context to keep
|
1179
|
+
# This way a local context does not affect the settings of the previous context,
|
1180
|
+
# but flags are transferred.
|
1181
|
+
# (this could be done always or be controlled by some option)
|
1182
|
+
# keep.flags = DecNum.context.flags
|
1183
|
+
# Another alternative to consider: logically or the flags:
|
1184
|
+
# keep.flags ||= DecNum.context.flags # (this requires implementing || in Flags)
|
1185
|
+
self._context = keep
|
1186
|
+
result
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
class <<self
|
1190
|
+
# This is the thread-local context storage low level interface
|
1191
|
+
protected
|
1192
|
+
def _context #:nodoc:
|
1193
|
+
# TODO: memoize the variable id
|
1194
|
+
Thread.current["Flt::#{self}.context"]
|
1195
|
+
end
|
1196
|
+
def _context=(c) #:nodoc:
|
1197
|
+
Thread.current["Flt::#{self}.context"] = c
|
1198
|
+
end
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
def num_class
|
1202
|
+
self.class
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
class <<self
|
1206
|
+
def num_class
|
1207
|
+
self
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
class << self
|
1212
|
+
# A floating-point number with value zero and the specified sign
|
1213
|
+
def zero(sign=+1)
|
1214
|
+
new [sign, 0, 0]
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
# A floating-point infinite number with the specified sign
|
1218
|
+
def infinity(sign=+1)
|
1219
|
+
new [sign, 0, :inf]
|
1220
|
+
end
|
1221
|
+
|
1222
|
+
# A floating-point NaN (not a number)
|
1223
|
+
def nan()
|
1224
|
+
new [+1, nil, :nan]
|
1225
|
+
end
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
|
1229
|
+
class <<self
|
1230
|
+
def int_radix_power(n)
|
1231
|
+
self.radix**n
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def int_mult_radix_power(x,n)
|
1235
|
+
x * self.radix**n
|
1236
|
+
end
|
1237
|
+
|
1238
|
+
def int_div_radix_power(x,n)
|
1239
|
+
x / self.radix**n
|
1240
|
+
end
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
# A floating point-number value can be defined by:
|
1244
|
+
# * A String containing a text representation of the number
|
1245
|
+
# * An Integer
|
1246
|
+
# * A Rational
|
1247
|
+
# * For binary floating point: a Float
|
1248
|
+
# * A Value of a type for which conversion is defined in the context.
|
1249
|
+
# * Another floating-point value of the same type.
|
1250
|
+
# * A sign, coefficient and exponent (either as separate arguments, as an array or as a Hash with symbolic keys),
|
1251
|
+
# or a signed coefficient and an exponent.
|
1252
|
+
# This is the internal representation of Num, as returned by Num#split.
|
1253
|
+
# The sign is +1 for plus and -1 for minus; the coefficient and exponent are
|
1254
|
+
# integers, except for special values which are defined by :inf, :nan or :snan for the exponent.
|
1255
|
+
#
|
1256
|
+
# An optional Context can be passed after the value-definint argument to override the current context
|
1257
|
+
# and options can be passed in a last hash argument; alternatively context options can be overriden
|
1258
|
+
# by options of the hash argument.
|
1259
|
+
#
|
1260
|
+
# When the number is defined by a numeric literal (a String), it can be followed by a symbol that specifies
|
1261
|
+
# the mode used to convert the literal to a floating-point value:
|
1262
|
+
# * :free is currently the default for all cases. The precision of the input literal (including trailing zeros)
|
1263
|
+
# is preserved and the precision of the context is ignored.
|
1264
|
+
# When the literal is in the same base as the floating-point radix, (which, by default, is the case for
|
1265
|
+
# DecNum only), the literal is preserved exactly in floating-point.
|
1266
|
+
# Otherwise, all significative digits that can be derived from the literal are generanted, significative
|
1267
|
+
# meaning here that if the digit is changed and the value converted back to a literal of the same base and
|
1268
|
+
# precision, the original literal will not be obtained.
|
1269
|
+
# * :short is a variation of :free in which only the minimun number of digits that are necessary to
|
1270
|
+
# produce the original literal when the value is converted back with the same original precision.
|
1271
|
+
# * :fixed will round and normalize the value to the precision specified by the context (normalize meaning
|
1272
|
+
# that exaclty the number of digits specified by the precision will be generated, even if the original
|
1273
|
+
# literal has fewer digits.) This may fail returning NaN (and raising Inexact) if the context precision is
|
1274
|
+
# :exact, but not if the floating-point radix is a multiple of the input base.
|
1275
|
+
#
|
1276
|
+
# Options that can be passed for construction from literal:
|
1277
|
+
# * :base is the numeric base of the input, 10 by default.
|
1278
|
+
def initialize(*args)
|
1279
|
+
options = args.pop if args.last.is_a?(Hash)
|
1280
|
+
context = args.pop if args.size>0 && (args.last.kind_of?(ContextBase) || args.last.nil?)
|
1281
|
+
context ||= options && options.delete(:context)
|
1282
|
+
mode = args.pop if args.last.is_a?(Symbol) && ![:inf, :nan, :snan].include?(args.last)
|
1283
|
+
args = args.first if args.size==1 && args.first.is_a?(Array)
|
1284
|
+
if args.empty? && options
|
1285
|
+
args = [options.delete(:sign)||+1,
|
1286
|
+
options.delete(:coefficient) || 0,
|
1287
|
+
options.delete(:exponent) || 0]
|
1288
|
+
end
|
1289
|
+
mode ||= options && options.delete(:mode)
|
1290
|
+
base = (options && options.delete(:base)) || 10
|
1291
|
+
context = options if context.nil? && options && !options.empty?
|
1292
|
+
context = define_context(context)
|
1293
|
+
|
1294
|
+
case args.size
|
1295
|
+
when 3
|
1296
|
+
# internal representation
|
1297
|
+
@sign, @coeff, @exp = args
|
1298
|
+
# TO DO: validate
|
1299
|
+
|
1300
|
+
when 2
|
1301
|
+
# signed integer and scale
|
1302
|
+
@coeff, @exp = args
|
1303
|
+
if @coeff < 0
|
1304
|
+
@sign = -1
|
1305
|
+
@coeff = -@coeff
|
1306
|
+
else
|
1307
|
+
@sign = +1
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
when 1
|
1311
|
+
arg = args.first
|
1312
|
+
case arg
|
1313
|
+
|
1314
|
+
when num_class
|
1315
|
+
@sign, @coeff, @exp = arg.split
|
1316
|
+
|
1317
|
+
when *context.coercible_types
|
1318
|
+
v = context._coerce(arg)
|
1319
|
+
@sign, @coeff, @exp = v.is_a?(Num) ? v.split : v
|
1320
|
+
|
1321
|
+
when String
|
1322
|
+
if arg.strip != arg
|
1323
|
+
@sign,@coeff,@exp = context.exception(ConversionSyntax, "no trailing or leading whitespace is permitted").split
|
1324
|
+
return
|
1325
|
+
end
|
1326
|
+
m = _parser(arg)
|
1327
|
+
if m.nil?
|
1328
|
+
@sign,@coeff,@exp = context.exception(ConversionSyntax, "Invalid literal for DecNum: #{arg.inspect}").split
|
1329
|
+
return
|
1330
|
+
end
|
1331
|
+
@sign = (m.sign == '-') ? -1 : +1
|
1332
|
+
if m.int || m.onlyfrac
|
1333
|
+
sign = @sign
|
1334
|
+
if m.int
|
1335
|
+
intpart = m.int
|
1336
|
+
fracpart = m.frac
|
1337
|
+
else
|
1338
|
+
intpart = ''
|
1339
|
+
fracpart = m.onlyfrac
|
1340
|
+
end
|
1341
|
+
exp = m.exp.to_i
|
1342
|
+
if fracpart
|
1343
|
+
coeff = (intpart+fracpart).to_i(base)
|
1344
|
+
exp -= fracpart.size
|
1345
|
+
else
|
1346
|
+
coeff = intpart.to_i(base)
|
1347
|
+
end
|
1348
|
+
|
1349
|
+
if false
|
1350
|
+
# Old behaviour: use :fixed format when num_class.radix != base
|
1351
|
+
# Advantages:
|
1352
|
+
# * Behaviour similar to Float: BinFloat(txt) == Float(txt)
|
1353
|
+
mode ||= ((num_class.radix == base) ? :free : :fixed)
|
1354
|
+
else
|
1355
|
+
# New behaviour: the default is always :free
|
1356
|
+
# Advantages:
|
1357
|
+
# * Is coherent with construction of DecNum from decimal literal:
|
1358
|
+
# preserve precision of the literal with independence of context.
|
1359
|
+
mode ||= :free
|
1360
|
+
end
|
1361
|
+
|
1362
|
+
if [:free, :short].include?(mode) && base == num_class.radix
|
1363
|
+
# simple case, the job is already done
|
1364
|
+
else
|
1365
|
+
rounding = context.rounding
|
1366
|
+
reader = Support::Reader.new(:mode=>mode)
|
1367
|
+
ans = reader.read(context, rounding, sign, coeff, exp, base)
|
1368
|
+
context.exception(Inexact,"Inexact decimal to radix #{num_class.radix} conversion") if !reader.exact?
|
1369
|
+
if !reader.exact? && context.exact?
|
1370
|
+
sign, coeff, exp = num_class.nan.split
|
1371
|
+
else
|
1372
|
+
sign, coeff, exp = ans.split
|
1373
|
+
end
|
1374
|
+
end
|
1375
|
+
@sign, @coeff, @exp = sign, coeff, exp
|
1376
|
+
else
|
1377
|
+
if m.diag
|
1378
|
+
# NaN
|
1379
|
+
@coeff = (m.diag.nil? || m.diag.empty?) ? nil : m.diag.to_i
|
1380
|
+
@coeff = nil if @coeff==0
|
1381
|
+
if @coeff
|
1382
|
+
max_diag_len = context.maximum_nan_diagnostic_digits
|
1383
|
+
if max_diag_len && @coeff >= context.int_radix_power(max_diag_len)
|
1384
|
+
@sign,@coeff,@exp = context.exception(ConversionSyntax, "diagnostic info too long in NaN").split
|
1385
|
+
return
|
1386
|
+
end
|
1387
|
+
end
|
1388
|
+
@exp = m.signal ? :snan : :nan
|
1389
|
+
else
|
1390
|
+
# Infinity
|
1391
|
+
@coeff = 0
|
1392
|
+
@exp = :inf
|
1393
|
+
end
|
1394
|
+
end
|
1395
|
+
else
|
1396
|
+
raise TypeError, "invalid argument #{arg.inspect}"
|
1397
|
+
end
|
1398
|
+
else
|
1399
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 1, 2 or 3)"
|
1400
|
+
end
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
# shortcut constructor:
|
1404
|
+
def Num(*args)
|
1405
|
+
self.class.Num(*args)
|
1406
|
+
end
|
1407
|
+
private :Num
|
1408
|
+
|
1409
|
+
class <<self
|
1410
|
+
# Num is the general constructor that can be invoked on specific Flt::Num-derived classes.
|
1411
|
+
def Num(*args)
|
1412
|
+
if args.size==1 && args.first.instance_of?(self)
|
1413
|
+
args.first
|
1414
|
+
else
|
1415
|
+
new(*args)
|
1416
|
+
end
|
1417
|
+
end
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
# Returns the internal representation of the number, composed of:
|
1421
|
+
# * a sign which is +1 for plus and -1 for minus
|
1422
|
+
# * a coefficient (significand) which is a nonnegative integer
|
1423
|
+
# * an exponent (an integer) or :inf, :nan or :snan for special values
|
1424
|
+
# The value of non-special numbers is sign*coefficient*10^exponent
|
1425
|
+
def split
|
1426
|
+
[@sign, @coeff, @exp]
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
# Returns whether the number is a special value (NaN or Infinity).
|
1430
|
+
def special?
|
1431
|
+
@exp.instance_of?(Symbol)
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
# Returns whether the number is not actualy one (NaN, not a number).
|
1435
|
+
def nan?
|
1436
|
+
@exp==:nan || @exp==:snan
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
# Returns whether the number is a quite NaN (non-signaling)
|
1440
|
+
def qnan?
|
1441
|
+
@exp == :nan
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
# Returns whether the number is a signaling NaN
|
1445
|
+
def snan?
|
1446
|
+
@exp == :snan
|
1447
|
+
end
|
1448
|
+
|
1449
|
+
# Returns whether the number is infinite
|
1450
|
+
def infinite?
|
1451
|
+
@exp == :inf
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
# Returns whether the number is finite
|
1455
|
+
def finite?
|
1456
|
+
!special?
|
1457
|
+
end
|
1458
|
+
|
1459
|
+
# Returns whether the number is zero
|
1460
|
+
def zero?
|
1461
|
+
@coeff==0 && !special?
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
# Returns whether the number not zero
|
1465
|
+
def nonzero?
|
1466
|
+
special? || @coeff>0
|
1467
|
+
end
|
1468
|
+
|
1469
|
+
# Returns whether the number is subnormal
|
1470
|
+
def subnormal?(context=nil)
|
1471
|
+
return false if special? || zero?
|
1472
|
+
context = define_context(context)
|
1473
|
+
self.adjusted_exponent < context.emin
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
# Returns whether the number is normal
|
1477
|
+
def normal?(context=nil)
|
1478
|
+
return false if special? || zero?
|
1479
|
+
context = define_context(context)
|
1480
|
+
(context.emin <= self.adjusted_exponent) && (self.adjusted_exponent <= context.emax)
|
1481
|
+
end
|
1482
|
+
|
1483
|
+
# Classifies a number as one of
|
1484
|
+
# 'sNaN', 'NaN', '-Infinity', '-Normal', '-Subnormal', '-Zero',
|
1485
|
+
# '+Zero', '+Subnormal', '+Normal', '+Infinity'
|
1486
|
+
def number_class(context=nil)
|
1487
|
+
return "sNaN" if snan?
|
1488
|
+
return "NaN" if nan?
|
1489
|
+
if infinite?
|
1490
|
+
return '+Infinity' if @sign==+1
|
1491
|
+
return '-Infinity' # if @sign==-1
|
1492
|
+
end
|
1493
|
+
if zero?
|
1494
|
+
return '+Zero' if @sign==+1
|
1495
|
+
return '-Zero' # if @sign==-1
|
1496
|
+
end
|
1497
|
+
define_context(context)
|
1498
|
+
if subnormal?(context)
|
1499
|
+
return '+Subnormal' if @sign==+1
|
1500
|
+
return '-Subnormal' # if @sign==-1
|
1501
|
+
end
|
1502
|
+
return '+Normal' if @sign==+1
|
1503
|
+
return '-Normal' if @sign==-1
|
1504
|
+
end
|
1505
|
+
|
1506
|
+
# Used internally to convert numbers to be used in an operation to a suitable numeric type
|
1507
|
+
def coerce(other)
|
1508
|
+
case other
|
1509
|
+
when *num_class.context.coercible_types_or_num
|
1510
|
+
[Num(other),self]
|
1511
|
+
when Float
|
1512
|
+
[other, self.to_f]
|
1513
|
+
else
|
1514
|
+
super
|
1515
|
+
end
|
1516
|
+
end
|
1517
|
+
|
1518
|
+
# Used internally to define binary operators
|
1519
|
+
def _bin_op(op, meth, other, context=nil)
|
1520
|
+
context = define_context(context)
|
1521
|
+
case other
|
1522
|
+
when *context.coercible_types_or_num
|
1523
|
+
self.send meth, Num(other, context), context
|
1524
|
+
else
|
1525
|
+
x, y = other.coerce(self)
|
1526
|
+
x.send op, y
|
1527
|
+
end
|
1528
|
+
end
|
1529
|
+
private :_bin_op
|
1530
|
+
|
1531
|
+
# Unary minus operator
|
1532
|
+
def -@(context=nil)
|
1533
|
+
#(context || num_class.context).minus(self)
|
1534
|
+
_neg(context)
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
# Unary plus operator
|
1538
|
+
def +@(context=nil)
|
1539
|
+
#(context || num_class.context).plus(self)
|
1540
|
+
_pos(context)
|
1541
|
+
end
|
1542
|
+
|
1543
|
+
# Addition of two decimal numbers
|
1544
|
+
def +(other, context=nil)
|
1545
|
+
_bin_op :+, :add, other, context
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
# Subtraction of two decimal numbers
|
1549
|
+
def -(other, context=nil)
|
1550
|
+
_bin_op :-, :subtract, other, context
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
# Multiplication of two decimal numbers
|
1554
|
+
def *(other, context=nil)
|
1555
|
+
_bin_op :*, :multiply, other, context
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
# Division of two decimal numbers
|
1559
|
+
def /(other, context=nil)
|
1560
|
+
_bin_op :/, :divide, other, context
|
1561
|
+
end
|
1562
|
+
|
1563
|
+
# Modulo of two decimal numbers
|
1564
|
+
def %(other, context=nil)
|
1565
|
+
_bin_op :%, :modulo, other, context
|
1566
|
+
end
|
1567
|
+
|
1568
|
+
# Power
|
1569
|
+
def **(other, context=nil)
|
1570
|
+
_bin_op :**, :power, other, context
|
1571
|
+
end
|
1572
|
+
|
1573
|
+
# Addition
|
1574
|
+
def add(other, context=nil)
|
1575
|
+
|
1576
|
+
context = define_context(context)
|
1577
|
+
other = _convert(other)
|
1578
|
+
|
1579
|
+
if self.special? || other.special?
|
1580
|
+
ans = _check_nans(context,other)
|
1581
|
+
return ans if ans
|
1582
|
+
|
1583
|
+
if self.infinite?
|
1584
|
+
if self.sign != other.sign && other.infinite?
|
1585
|
+
return context.exception(InvalidOperation, '-INF + INF')
|
1586
|
+
end
|
1587
|
+
return Num(self)
|
1588
|
+
end
|
1589
|
+
|
1590
|
+
return Num(other) if other.infinite?
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
exp = [self.exponent, other.exponent].min
|
1594
|
+
negativezero = (context.rounding == ROUND_FLOOR && self.sign != other.sign)
|
1595
|
+
|
1596
|
+
if self.zero? && other.zero?
|
1597
|
+
sign = [self.sign, other.sign].max
|
1598
|
+
sign = -1 if negativezero
|
1599
|
+
ans = Num([sign, 0, exp])._fix(context)
|
1600
|
+
return ans
|
1601
|
+
end
|
1602
|
+
|
1603
|
+
if self.zero?
|
1604
|
+
exp = [exp, other.exponent - context.precision - 1].max unless context.exact?
|
1605
|
+
return other._rescale(exp, context.rounding)._fix(context)
|
1606
|
+
end
|
1607
|
+
|
1608
|
+
if other.zero?
|
1609
|
+
exp = [exp, self.exponent - context.precision - 1].max unless context.exact?
|
1610
|
+
return self._rescale(exp, context.rounding)._fix(context)
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
op1, op2 = _normalize(self, other, context.precision)
|
1614
|
+
|
1615
|
+
result_sign = result_coeff = result_exp = nil
|
1616
|
+
if op1.sign != op2.sign
|
1617
|
+
return ans = Num(negativezero ? -1 : +1, 0, exp)._fix(context) if op1.coefficient == op2.coefficient
|
1618
|
+
op1,op2 = op2,op1 if op1.coefficient < op2.coefficient
|
1619
|
+
result_sign = op1.sign
|
1620
|
+
op1,op2 = op1.copy_negate, op2.copy_negate if result_sign < 0
|
1621
|
+
elsif op1.sign < 0
|
1622
|
+
result_sign = -1
|
1623
|
+
op1,op2 = op1.copy_negate, op2.copy_negate
|
1624
|
+
else
|
1625
|
+
result_sign = +1
|
1626
|
+
end
|
1627
|
+
|
1628
|
+
if op2.sign == +1
|
1629
|
+
result_coeff = op1.coefficient + op2.coefficient
|
1630
|
+
else
|
1631
|
+
result_coeff = op1.coefficient - op2.coefficient
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
result_exp = op1.exponent
|
1635
|
+
|
1636
|
+
return Num(result_sign, result_coeff, result_exp)._fix(context)
|
1637
|
+
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
# Subtraction
|
1641
|
+
def subtract(other, context=nil)
|
1642
|
+
|
1643
|
+
context = define_context(context)
|
1644
|
+
other = _convert(other)
|
1645
|
+
|
1646
|
+
if self.special? || other.special?
|
1647
|
+
ans = _check_nans(context,other)
|
1648
|
+
return ans if ans
|
1649
|
+
end
|
1650
|
+
return add(other.copy_negate, context)
|
1651
|
+
end
|
1652
|
+
|
1653
|
+
# Multiplication
|
1654
|
+
def multiply(other, context=nil)
|
1655
|
+
context = define_context(context)
|
1656
|
+
other = _convert(other)
|
1657
|
+
resultsign = self.sign * other.sign
|
1658
|
+
if self.special? || other.special?
|
1659
|
+
ans = _check_nans(context,other)
|
1660
|
+
return ans if ans
|
1661
|
+
|
1662
|
+
if self.infinite?
|
1663
|
+
return context.exception(InvalidOperation,"(+-)INF * 0") if other.zero?
|
1664
|
+
return num_class.infinity(resultsign)
|
1665
|
+
end
|
1666
|
+
if other.infinite?
|
1667
|
+
return context.exception(InvalidOperation,"0 * (+-)INF") if self.zero?
|
1668
|
+
return num_class.infinity(resultsign)
|
1669
|
+
end
|
1670
|
+
end
|
1671
|
+
|
1672
|
+
resultexp = self.exponent + other.exponent
|
1673
|
+
|
1674
|
+
return Num(resultsign, 0, resultexp)._fix(context) if self.zero? || other.zero?
|
1675
|
+
#return Num(resultsign, other.coefficient, resultexp)._fix(context) if self.coefficient==1
|
1676
|
+
#return Num(resultsign, self.coefficient, resultexp)._fix(context) if other.coefficient==1
|
1677
|
+
|
1678
|
+
return Num(resultsign, other.coefficient*self.coefficient, resultexp)._fix(context)
|
1679
|
+
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
# Division
|
1683
|
+
def divide(other, context=nil)
|
1684
|
+
context = define_context(context)
|
1685
|
+
other = _convert(other)
|
1686
|
+
resultsign = self.sign * other.sign
|
1687
|
+
if self.special? || other.special?
|
1688
|
+
ans = _check_nans(context,other)
|
1689
|
+
return ans if ans
|
1690
|
+
if self.infinite?
|
1691
|
+
return context.exception(InvalidOperation,"(+-)INF/(+-)INF") if other.infinite?
|
1692
|
+
return num_class.infinity(resultsign)
|
1693
|
+
end
|
1694
|
+
if other.infinite?
|
1695
|
+
context.exception(Clamped,"Division by infinity")
|
1696
|
+
return num_class.new([resultsign, 0, context.etiny])
|
1697
|
+
end
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
if other.zero?
|
1701
|
+
return context.exception(DivisionUndefined, '0 / 0') if self.zero?
|
1702
|
+
return context.exception(DivisionByZero, 'x / 0', resultsign)
|
1703
|
+
end
|
1704
|
+
|
1705
|
+
if self.zero?
|
1706
|
+
exp = self.exponent - other.exponent
|
1707
|
+
coeff = 0
|
1708
|
+
else
|
1709
|
+
prec = context.exact? ? self.number_of_digits + 4*other.number_of_digits : context.precision
|
1710
|
+
shift = other.number_of_digits - self.number_of_digits + prec
|
1711
|
+
shift += 1
|
1712
|
+
exp = self.exponent - other.exponent - shift
|
1713
|
+
if shift >= 0
|
1714
|
+
coeff, remainder = (self.coefficient*num_class.int_radix_power(shift)).divmod(other.coefficient)
|
1715
|
+
else
|
1716
|
+
coeff, remainder = self.coefficient.divmod(other.coefficient*num_class.int_radix_power(-shift))
|
1717
|
+
end
|
1718
|
+
if remainder != 0
|
1719
|
+
return context.exception(Inexact) if context.exact?
|
1720
|
+
# result is not exact; adjust to ensure correct rounding
|
1721
|
+
if num_class.radix == 10
|
1722
|
+
# perform 05up rounding so the the final rounding will be correct
|
1723
|
+
coeff += 1 if (coeff%5) == 0
|
1724
|
+
else
|
1725
|
+
# since we will round to less digits and there is a remainder, we just need
|
1726
|
+
# to append some nonzero digit; but we must avoid producing a tie (adding a single
|
1727
|
+
# digit whose value is radix/2), so we append two digits, 01, that will be rounded away
|
1728
|
+
coeff = num_class.int_mult_radix_power(coeff, 2) + 1
|
1729
|
+
exp -= 2
|
1730
|
+
end
|
1731
|
+
else
|
1732
|
+
# result is exact; get as close to idaal exponent as possible
|
1733
|
+
ideal_exp = self.exponent - other.exponent
|
1734
|
+
while (exp < ideal_exp) && ((coeff % num_class.radix)==0)
|
1735
|
+
coeff /= num_class.radix
|
1736
|
+
exp += 1
|
1737
|
+
end
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
end
|
1741
|
+
return Num(resultsign, coeff, exp)._fix(context)
|
1742
|
+
|
1743
|
+
end
|
1744
|
+
|
1745
|
+
# Square root
|
1746
|
+
def sqrt(context=nil)
|
1747
|
+
context = define_context(context)
|
1748
|
+
if special?
|
1749
|
+
ans = _check_nans(context)
|
1750
|
+
return ans if ans
|
1751
|
+
return Num(self) if infinite? && @sign==+1
|
1752
|
+
end
|
1753
|
+
return Num(@sign, 0, @exp/2)._fix(context) if zero?
|
1754
|
+
return context.exception(InvalidOperation, 'sqrt(-x), x>0') if @sign<0
|
1755
|
+
prec = context.precision + 1
|
1756
|
+
|
1757
|
+
# express the number in radix**2 base
|
1758
|
+
e = (@exp >> 1)
|
1759
|
+
if (@exp & 1)!=0
|
1760
|
+
c = @coeff*num_class.radix
|
1761
|
+
l = (number_of_digits >> 1) + 1
|
1762
|
+
else
|
1763
|
+
c = @coeff
|
1764
|
+
l = (number_of_digits+1) >> 1
|
1765
|
+
end
|
1766
|
+
shift = prec - l
|
1767
|
+
if shift >= 0
|
1768
|
+
c = num_class.int_mult_radix_power(c, (shift<<1))
|
1769
|
+
exact = true
|
1770
|
+
else
|
1771
|
+
c, remainder = c.divmod(num_class.int_radix_power((-shift)<<1))
|
1772
|
+
exact = (remainder==0)
|
1773
|
+
end
|
1774
|
+
e -= shift
|
1775
|
+
|
1776
|
+
n = num_class.int_radix_power(prec)
|
1777
|
+
while true
|
1778
|
+
q = c / n
|
1779
|
+
break if n <= q
|
1780
|
+
n = ((n + q) >> 1)
|
1781
|
+
end
|
1782
|
+
exact = exact && (n*n == c)
|
1783
|
+
|
1784
|
+
if exact
|
1785
|
+
if shift >= 0
|
1786
|
+
n = num_class.int_div_radix_power(n, shift)
|
1787
|
+
else
|
1788
|
+
n = num_class.int_mult_radix_power(n, -shift)
|
1789
|
+
end
|
1790
|
+
e += shift
|
1791
|
+
else
|
1792
|
+
return context.exception(Inexact) if context.exact?
|
1793
|
+
# result is not exact; adjust to ensure correct rounding
|
1794
|
+
if num_class.radix == 10
|
1795
|
+
n += 1 if (n%5)==0
|
1796
|
+
else
|
1797
|
+
n = num_class.int_mult_radix_power(n, 2) + 1
|
1798
|
+
e -= 2
|
1799
|
+
end
|
1800
|
+
end
|
1801
|
+
ans = Num(+1,n,e)
|
1802
|
+
num_class.local_context(:rounding=>:half_even) do
|
1803
|
+
ans = ans._fix(context)
|
1804
|
+
end
|
1805
|
+
return ans
|
1806
|
+
end
|
1807
|
+
|
1808
|
+
# Absolute value
|
1809
|
+
def abs(context=nil)
|
1810
|
+
if special?
|
1811
|
+
ans = _check_nans(context)
|
1812
|
+
return ans if ans
|
1813
|
+
end
|
1814
|
+
sign<0 ? _neg(context) : _pos(context)
|
1815
|
+
end
|
1816
|
+
|
1817
|
+
# Unary prefix plus operator
|
1818
|
+
def plus(context=nil)
|
1819
|
+
_pos(context)
|
1820
|
+
end
|
1821
|
+
|
1822
|
+
# Unary prefix minus operator
|
1823
|
+
def minus(context=nil)
|
1824
|
+
_neg(context)
|
1825
|
+
end
|
1826
|
+
|
1827
|
+
# Largest representable number smaller than itself
|
1828
|
+
def next_minus(context=nil)
|
1829
|
+
context = define_context(context)
|
1830
|
+
if special?
|
1831
|
+
ans = _check_nans(context)
|
1832
|
+
return ans if ans
|
1833
|
+
if infinite?
|
1834
|
+
return Num(self) if @sign == -1
|
1835
|
+
# @sign == +1
|
1836
|
+
if context.exact?
|
1837
|
+
return context.exception(InvalidOperation, 'Exact +INF next minus')
|
1838
|
+
else
|
1839
|
+
return Num(+1, context.maximum_coefficient, context.etop)
|
1840
|
+
end
|
1841
|
+
end
|
1842
|
+
end
|
1843
|
+
|
1844
|
+
return context.exception(InvalidOperation, 'Exact next minus') if context.exact?
|
1845
|
+
|
1846
|
+
result = nil
|
1847
|
+
num_class.local_context(context) do |local|
|
1848
|
+
local.rounding = :floor
|
1849
|
+
local.ignore_all_flags
|
1850
|
+
result = self._fix(local)
|
1851
|
+
if result == self
|
1852
|
+
result = self - Num(+1, 1, local.etiny-1)
|
1853
|
+
end
|
1854
|
+
end
|
1855
|
+
result
|
1856
|
+
end
|
1857
|
+
|
1858
|
+
# Smallest representable number larger than itself
|
1859
|
+
def next_plus(context=nil)
|
1860
|
+
context = define_context(context)
|
1861
|
+
|
1862
|
+
if special?
|
1863
|
+
ans = _check_nans(context)
|
1864
|
+
return ans if ans
|
1865
|
+
if infinite?
|
1866
|
+
return Num(self) if @sign == +1
|
1867
|
+
# @sign == -1
|
1868
|
+
if context.exact?
|
1869
|
+
return context.exception(InvalidOperation, 'Exact -INF next plus')
|
1870
|
+
else
|
1871
|
+
return Num(-1, context.maximum_coefficient, context.etop)
|
1872
|
+
end
|
1873
|
+
end
|
1874
|
+
end
|
1875
|
+
|
1876
|
+
return context.exception(InvalidOperation, 'Exact next plus') if context.exact?
|
1877
|
+
|
1878
|
+
result = nil
|
1879
|
+
num_class.local_context(context) do |local|
|
1880
|
+
local.rounding = :ceiling
|
1881
|
+
local.ignore_all_flags
|
1882
|
+
result = self._fix(local)
|
1883
|
+
if result == self
|
1884
|
+
result = self + Num(+1, 1, local.etiny-1)
|
1885
|
+
end
|
1886
|
+
end
|
1887
|
+
result
|
1888
|
+
|
1889
|
+
end
|
1890
|
+
|
1891
|
+
# Returns the number closest to self, in the direction towards other.
|
1892
|
+
def next_toward(other, context=nil)
|
1893
|
+
context = define_context(context)
|
1894
|
+
other = _convert(other)
|
1895
|
+
ans = _check_nans(context,other)
|
1896
|
+
return ans if ans
|
1897
|
+
|
1898
|
+
return context.exception(InvalidOperation, 'Exact next_toward') if context.exact?
|
1899
|
+
|
1900
|
+
comparison = self <=> other
|
1901
|
+
return self.copy_sign(other) if comparison == 0
|
1902
|
+
|
1903
|
+
if comparison == -1
|
1904
|
+
result = self.next_plus(context)
|
1905
|
+
else # comparison == 1
|
1906
|
+
result = self.next_minus(context)
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
# decide which flags to raise using value of ans
|
1910
|
+
if result.infinite?
|
1911
|
+
context.exception Overflow, 'Infinite result from next_toward', result.sign
|
1912
|
+
context.exception Rounded
|
1913
|
+
context.exception Inexact
|
1914
|
+
elsif result.adjusted_exponent < context.emin
|
1915
|
+
context.exception Underflow
|
1916
|
+
context.exception Subnormal
|
1917
|
+
context.exception Rounded
|
1918
|
+
context.exception Inexact
|
1919
|
+
# if precision == 1 then we don't raise Clamped for a
|
1920
|
+
# result 0E-etiny.
|
1921
|
+
context.exception Clamped if result.zero?
|
1922
|
+
end
|
1923
|
+
|
1924
|
+
result
|
1925
|
+
end
|
1926
|
+
|
1927
|
+
# General Decimal Arithmetic Specification integer division and remainder:
|
1928
|
+
# (x/y).truncate, x - y*(x/y).truncate
|
1929
|
+
def divrem(other, context=nil)
|
1930
|
+
context = define_context(context)
|
1931
|
+
other = _convert(other)
|
1932
|
+
|
1933
|
+
ans = _check_nans(context,other)
|
1934
|
+
return [ans,ans] if ans
|
1935
|
+
|
1936
|
+
sign = self.sign * other.sign
|
1937
|
+
|
1938
|
+
if self.infinite?
|
1939
|
+
if other.infinite?
|
1940
|
+
ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
|
1941
|
+
return [ans,ans]
|
1942
|
+
else
|
1943
|
+
return [num_class.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
|
1944
|
+
end
|
1945
|
+
end
|
1946
|
+
|
1947
|
+
if other.zero?
|
1948
|
+
if self.zero?
|
1949
|
+
ans = context.exception(DivisionUndefined, 'divmod(0,0)')
|
1950
|
+
return [ans,ans]
|
1951
|
+
else
|
1952
|
+
return [context.exception(DivisionByZero, 'x // 0', sign),
|
1953
|
+
context.exception(InvalidOperation, 'x % 0')]
|
1954
|
+
end
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
quotient, remainder = self._divide_truncate(other, context)
|
1958
|
+
return [quotient, remainder._fix(context)]
|
1959
|
+
end
|
1960
|
+
|
1961
|
+
# Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
|
1962
|
+
def divmod(other, context=nil)
|
1963
|
+
context = define_context(context)
|
1964
|
+
other = _convert(other)
|
1965
|
+
|
1966
|
+
ans = _check_nans(context,other)
|
1967
|
+
return [ans,ans] if ans
|
1968
|
+
|
1969
|
+
sign = self.sign * other.sign
|
1970
|
+
|
1971
|
+
if self.infinite?
|
1972
|
+
if other.infinite?
|
1973
|
+
ans = context.exception(InvalidOperation, 'divmod(INF,INF)')
|
1974
|
+
return [ans,ans]
|
1975
|
+
else
|
1976
|
+
return [num_class.infinity(sign), context.exception(InvalidOperation, 'INF % x')]
|
1977
|
+
end
|
1978
|
+
end
|
1979
|
+
|
1980
|
+
if other.zero?
|
1981
|
+
if self.zero?
|
1982
|
+
ans = context.exception(DivisionUndefined, 'divmod(0,0)')
|
1983
|
+
return [ans,ans]
|
1984
|
+
else
|
1985
|
+
return [context.exception(DivisionByZero, 'x // 0', sign),
|
1986
|
+
context.exception(InvalidOperation, 'x % 0')]
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
quotient, remainder = self._divide_floor(other, context)
|
1991
|
+
return [quotient, remainder._fix(context)]
|
1992
|
+
end
|
1993
|
+
|
1994
|
+
|
1995
|
+
# General Decimal Arithmetic Specification integer division: (x/y).truncate
|
1996
|
+
def divide_int(other, context=nil)
|
1997
|
+
context = define_context(context)
|
1998
|
+
other = _convert(other)
|
1999
|
+
|
2000
|
+
ans = _check_nans(context,other)
|
2001
|
+
return ans if ans
|
2002
|
+
|
2003
|
+
sign = self.sign * other.sign
|
2004
|
+
|
2005
|
+
if self.infinite?
|
2006
|
+
return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
|
2007
|
+
return num_class.infinity(sign)
|
2008
|
+
end
|
2009
|
+
|
2010
|
+
if other.zero?
|
2011
|
+
if self.zero?
|
2012
|
+
return context.exception(DivisionUndefined, '0 // 0')
|
2013
|
+
else
|
2014
|
+
return context.exception(DivisionByZero, 'x // 0', sign)
|
2015
|
+
end
|
2016
|
+
end
|
2017
|
+
return self._divide_truncate(other, context).first
|
2018
|
+
end
|
2019
|
+
|
2020
|
+
# Ruby-style integer division: (x/y).floor
|
2021
|
+
def div(other, context=nil)
|
2022
|
+
context = define_context(context)
|
2023
|
+
other = _convert(other)
|
2024
|
+
|
2025
|
+
ans = _check_nans(context,other)
|
2026
|
+
return [ans,ans] if ans
|
2027
|
+
|
2028
|
+
sign = self.sign * other.sign
|
2029
|
+
|
2030
|
+
if self.infinite?
|
2031
|
+
return context.exception(InvalidOperation, 'INF // INF') if other.infinite?
|
2032
|
+
return num_class.infinity(sign)
|
2033
|
+
end
|
2034
|
+
|
2035
|
+
if other.zero?
|
2036
|
+
if self.zero?
|
2037
|
+
return context.exception(DivisionUndefined, '0 // 0')
|
2038
|
+
else
|
2039
|
+
return context.exception(DivisionByZero, 'x // 0', sign)
|
2040
|
+
end
|
2041
|
+
end
|
2042
|
+
return self._divide_floor(other, context).first
|
2043
|
+
end
|
2044
|
+
|
2045
|
+
|
2046
|
+
# Ruby-style modulo: x - y*div(x,y)
|
2047
|
+
def modulo(other, context=nil)
|
2048
|
+
context = define_context(context)
|
2049
|
+
other = _convert(other)
|
2050
|
+
|
2051
|
+
ans = _check_nans(context,other)
|
2052
|
+
return ans if ans
|
2053
|
+
|
2054
|
+
#sign = self.sign * other.sign
|
2055
|
+
|
2056
|
+
if self.infinite?
|
2057
|
+
return context.exception(InvalidOperation, 'INF % x')
|
2058
|
+
elsif other.zero?
|
2059
|
+
if self.zero?
|
2060
|
+
return context.exception(DivisionUndefined, '0 % 0')
|
2061
|
+
else
|
2062
|
+
return context.exception(InvalidOperation, 'x % 0')
|
2063
|
+
end
|
2064
|
+
end
|
2065
|
+
|
2066
|
+
return self._divide_floor(other, context).last._fix(context)
|
2067
|
+
end
|
2068
|
+
|
2069
|
+
# General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
|
2070
|
+
def remainder(other, context=nil)
|
2071
|
+
context = define_context(context)
|
2072
|
+
other = _convert(other)
|
2073
|
+
|
2074
|
+
ans = _check_nans(context,other)
|
2075
|
+
return ans if ans
|
2076
|
+
|
2077
|
+
#sign = self.sign * other.sign
|
2078
|
+
|
2079
|
+
if self.infinite?
|
2080
|
+
return context.exception(InvalidOperation, 'INF % x')
|
2081
|
+
elsif other.zero?
|
2082
|
+
if self.zero?
|
2083
|
+
return context.exception(DivisionUndefined, '0 % 0')
|
2084
|
+
else
|
2085
|
+
return context.exception(InvalidOperation, 'x % 0')
|
2086
|
+
end
|
2087
|
+
end
|
2088
|
+
|
2089
|
+
return self._divide_truncate(other, context).last._fix(context)
|
2090
|
+
end
|
2091
|
+
|
2092
|
+
# General Decimal Arithmetic Specification remainder-near:
|
2093
|
+
# x - y*round_half_even(x/y)
|
2094
|
+
def remainder_near(other, context=nil)
|
2095
|
+
context = define_context(context)
|
2096
|
+
other = _convert(other)
|
2097
|
+
|
2098
|
+
ans = _check_nans(context,other)
|
2099
|
+
return ans if ans
|
2100
|
+
|
2101
|
+
sign = self.sign * other.sign
|
2102
|
+
|
2103
|
+
if self.infinite?
|
2104
|
+
return context.exception(InvalidOperation, 'remainder_near(INF,x)')
|
2105
|
+
elsif other.zero?
|
2106
|
+
if self.zero?
|
2107
|
+
return context.exception(DivisionUndefined, 'remainder_near(0,0)')
|
2108
|
+
else
|
2109
|
+
return context.exception(InvalidOperation, 'remainder_near(x,0)')
|
2110
|
+
end
|
2111
|
+
end
|
2112
|
+
|
2113
|
+
if other.infinite?
|
2114
|
+
return Num(self)._fix(context)
|
2115
|
+
end
|
2116
|
+
|
2117
|
+
ideal_exp = [self.exponent, other.exponent].min
|
2118
|
+
if self.zero?
|
2119
|
+
return Num(self.sign, 0, ideal_exp)._fix(context)
|
2120
|
+
end
|
2121
|
+
|
2122
|
+
expdiff = self.adjusted_exponent - other.adjusted_exponent
|
2123
|
+
if (expdiff >= context.precision+1) && !context.exact?
|
2124
|
+
return context.exception(DivisionImpossible)
|
2125
|
+
elsif expdiff <= -2
|
2126
|
+
return self._rescale(ideal_exp, context.rounding)._fix(context)
|
2127
|
+
end
|
2128
|
+
|
2129
|
+
self_coeff = self.coefficient
|
2130
|
+
other_coeff = other.coefficient
|
2131
|
+
de = self.exponent - other.exponent
|
2132
|
+
if de >= 0
|
2133
|
+
self_coeff = num_class.int_mult_radix_power(self_coeff, de)
|
2134
|
+
else
|
2135
|
+
other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
|
2136
|
+
end
|
2137
|
+
q, r = self_coeff.divmod(other_coeff)
|
2138
|
+
if 2*r + (q&1) > other_coeff
|
2139
|
+
r -= other_coeff
|
2140
|
+
q += 1
|
2141
|
+
end
|
2142
|
+
|
2143
|
+
return context.exception(DivisionImpossible) if q >= num_class.int_radix_power(context.precision) && !context.exact?
|
2144
|
+
|
2145
|
+
sign = self.sign
|
2146
|
+
if r < 0
|
2147
|
+
sign = -sign
|
2148
|
+
r = -r
|
2149
|
+
end
|
2150
|
+
|
2151
|
+
return Num(sign, r, ideal_exp)._fix(context)
|
2152
|
+
|
2153
|
+
end
|
2154
|
+
|
2155
|
+
# Reduces an operand to its simplest form
|
2156
|
+
# by removing trailing 0s and incrementing the exponent.
|
2157
|
+
# (formerly called normalize in GDAS)
|
2158
|
+
def reduce(context=nil)
|
2159
|
+
context = define_context(context)
|
2160
|
+
if special?
|
2161
|
+
ans = _check_nans(context)
|
2162
|
+
return ans if ans
|
2163
|
+
end
|
2164
|
+
dup = _fix(context)
|
2165
|
+
return dup if dup.infinite?
|
2166
|
+
|
2167
|
+
return Num(dup.sign, 0, 0) if dup.zero?
|
2168
|
+
|
2169
|
+
exp_max = context.clamp? ? context.etop : context.emax
|
2170
|
+
end_d = nd = dup.number_of_digits
|
2171
|
+
exp = dup.exponent
|
2172
|
+
coeff = dup.coefficient
|
2173
|
+
dgs = dup.digits
|
2174
|
+
while (dgs[end_d-1]==0) && (exp < exp_max)
|
2175
|
+
exp += 1
|
2176
|
+
end_d -= 1
|
2177
|
+
end
|
2178
|
+
return Num(dup.sign, coeff/num_class.int_radix_power(nd-end_d), exp)
|
2179
|
+
end
|
2180
|
+
|
2181
|
+
# Normalizes (changes quantum) so that the coefficient has precision digits, unless it is subnormal.
|
2182
|
+
# For surnormal numbers the Subnormal flag is raised an a subnormal is returned with the smallest
|
2183
|
+
# possible exponent.
|
2184
|
+
#
|
2185
|
+
# This is different from reduce GDAS function which was formerly called normalize, and corresponds
|
2186
|
+
# to the classic meaning of floating-point normalization.
|
2187
|
+
#
|
2188
|
+
# Note that the number is also rounded (precision is reduced) if it had more precision than the context.
|
2189
|
+
def normalize(context=nil)
|
2190
|
+
context = define_context(context)
|
2191
|
+
return Num(self) if self.special? || self.zero? || context.exact?
|
2192
|
+
sign, coeff, exp = self._fix(context).split
|
2193
|
+
if self.subnormal?
|
2194
|
+
context.exception Subnormal
|
2195
|
+
if exp > context.etiny
|
2196
|
+
coeff = num_class.int_mult_radix_power(coeff, exp - context.etiny)
|
2197
|
+
exp = context.etiny
|
2198
|
+
end
|
2199
|
+
else
|
2200
|
+
min_normal_coeff = context.minimum_normalized_coefficient
|
2201
|
+
while coeff < min_normal_coeff
|
2202
|
+
coeff = num_class.int_mult_radix_power(coeff, 1)
|
2203
|
+
exp -= 1
|
2204
|
+
end
|
2205
|
+
end
|
2206
|
+
Num(sign, coeff, exp)
|
2207
|
+
end
|
2208
|
+
|
2209
|
+
# Returns the exponent of the magnitude of the most significant digit.
|
2210
|
+
#
|
2211
|
+
# The result is the integer which is the exponent of the magnitude
|
2212
|
+
# of the most significant digit of the number (as though it were truncated
|
2213
|
+
# to a single digit while maintaining the value of that digit and
|
2214
|
+
# without limiting the resulting exponent).
|
2215
|
+
def logb(context=nil)
|
2216
|
+
context = define_context(context)
|
2217
|
+
ans = _check_nans(context)
|
2218
|
+
return ans if ans
|
2219
|
+
return num_class.infinity if infinite?
|
2220
|
+
return context.exception(DivisionByZero,'logb(0)',-1) if zero?
|
2221
|
+
Num(adjusted_exponent)
|
2222
|
+
end
|
2223
|
+
|
2224
|
+
# Adds a value to the exponent.
|
2225
|
+
def scaleb(other, context=nil)
|
2226
|
+
|
2227
|
+
context = define_context(context)
|
2228
|
+
other = _convert(other)
|
2229
|
+
ans = _check_nans(context, other)
|
2230
|
+
return ans if ans
|
2231
|
+
return context.exception(InvalidOperation) if other.infinite? || other.exponent != 0
|
2232
|
+
unless context.exact?
|
2233
|
+
liminf = -2 * (context.emax + context.precision)
|
2234
|
+
limsup = 2 * (context.emax + context.precision)
|
2235
|
+
i = other.to_i
|
2236
|
+
return context.exception(InvalidOperation) if !((liminf <= i) && (i <= limsup))
|
2237
|
+
end
|
2238
|
+
return Num(self) if infinite?
|
2239
|
+
return Num(@sign, @coeff, @exp+i)._fix(context)
|
2240
|
+
|
2241
|
+
end
|
2242
|
+
|
2243
|
+
# Convert to other numerical type.
|
2244
|
+
def convert_to(type, context=nil)
|
2245
|
+
context = define_context(context)
|
2246
|
+
context.convert_to(type, self)
|
2247
|
+
end
|
2248
|
+
|
2249
|
+
# Ruby-style to integer conversion.
|
2250
|
+
def to_i
|
2251
|
+
if special?
|
2252
|
+
if nan?
|
2253
|
+
#return context.exception(InvalidContext)
|
2254
|
+
num_class.context.exception InvalidContext
|
2255
|
+
return nil
|
2256
|
+
end
|
2257
|
+
raise Error, "Cannot convert infinity to Integer"
|
2258
|
+
end
|
2259
|
+
if @exp >= 0
|
2260
|
+
return @sign*num_class.int_mult_radix_power(@coeff,@exp)
|
2261
|
+
else
|
2262
|
+
return @sign*num_class.int_div_radix_power(@coeff,-@exp)
|
2263
|
+
end
|
2264
|
+
end
|
2265
|
+
|
2266
|
+
# Conversion to Rational.
|
2267
|
+
# Conversion of special values will raise an exception under Ruby 1.9
|
2268
|
+
def to_r
|
2269
|
+
if special?
|
2270
|
+
num = (@exp == :inf) ? @sign : 0
|
2271
|
+
Rational.respond_to?(:new!) ? Rational.new!(num,0) : Rational(num,0)
|
2272
|
+
else
|
2273
|
+
if @exp < 0
|
2274
|
+
Rational(@sign*@coeff, num_class.int_radix_power(-@exp))
|
2275
|
+
else
|
2276
|
+
Rational(num_class.int_mult_radix_power(@sign*@coeff,@exp), 1)
|
2277
|
+
end
|
2278
|
+
end
|
2279
|
+
end
|
2280
|
+
|
2281
|
+
# Conversion to Float
|
2282
|
+
def to_f
|
2283
|
+
if special?
|
2284
|
+
if @exp==:inf
|
2285
|
+
@sign/0.0
|
2286
|
+
else
|
2287
|
+
0.0/0.0
|
2288
|
+
end
|
2289
|
+
else
|
2290
|
+
# to_rational.to_f
|
2291
|
+
# to_s.to_f
|
2292
|
+
(@sign*@coeff*(num_class.radix.to_f**@exp)).to_f
|
2293
|
+
end
|
2294
|
+
end
|
2295
|
+
|
2296
|
+
# ulp (unit in the last place) according to the definition proposed by J.M. Muller in
|
2297
|
+
# "On the definition of ulp(x)" INRIA No. 5504
|
2298
|
+
# If the mode parameter has the value :high the Golberg ulp is computed instead; which is
|
2299
|
+
# different on the powers of the radix (which are the borders between areas of different
|
2300
|
+
# ulp-magnitude)
|
2301
|
+
def ulp(context = nil, mode=:low)
|
2302
|
+
context = define_context(context)
|
2303
|
+
|
2304
|
+
return context.exception(InvalidOperation, "ulp in exact context") if context.exact?
|
2305
|
+
|
2306
|
+
if self.nan?
|
2307
|
+
return Num(self)
|
2308
|
+
elsif self.infinite?
|
2309
|
+
# The ulp here is context.maximum_finite - context.maximum_finite.next_minus
|
2310
|
+
return Num(+1, 1, context.etop)
|
2311
|
+
elsif self.zero? || self.adjusted_exponent <= context.emin
|
2312
|
+
# This is the ulp value for self.abs <= context.minimum_normal*DecNum.context
|
2313
|
+
# Here we use it for self.abs < context.minimum_normal*DecNum.context;
|
2314
|
+
# because of the simple exponent check; the remaining cases are handled below.
|
2315
|
+
return context.minimum_nonzero
|
2316
|
+
else
|
2317
|
+
# The next can compute the ulp value for the values that
|
2318
|
+
# self.abs > context.minimum_normal && self.abs <= context.maximum_finite
|
2319
|
+
# The cases self.abs < context.minimum_normal*DecNum.context have been handled above.
|
2320
|
+
|
2321
|
+
# assert self.normal? && self.abs>context.minimum_nonzero
|
2322
|
+
norm = self.normalize
|
2323
|
+
exp = norm.integral_exponent
|
2324
|
+
sig = norm.integral_significand
|
2325
|
+
|
2326
|
+
# Powers of the radix, r**n, are between areas with different ulp values: r**(n-p-1) and r**(n-p)
|
2327
|
+
# (p is context.precision).
|
2328
|
+
# This method and the ulp definitions by Muller, Kahan and Harrison assign the smaller ulp value
|
2329
|
+
# to r**n; the definition by Goldberg assigns it to the larger ulp (so ulp varies with adjusted_exponent).
|
2330
|
+
# The next line selects the smaller ulp for powers of the radix:
|
2331
|
+
exp -= 1 if sig == num_class.int_radix_power(context.precision-1) if mode == :low
|
2332
|
+
|
2333
|
+
return Num(+1, 1, exp)
|
2334
|
+
end
|
2335
|
+
end
|
2336
|
+
|
2337
|
+
def inspect
|
2338
|
+
class_name = num_class.to_s.split('::').last
|
2339
|
+
if $DEBUG
|
2340
|
+
"#{class_name}('#{self}') [coeff:#{@coeff.inspect} exp:#{@exp.inspect} s:#{@sign.inspect} radix:#{num_class.radix}]"
|
2341
|
+
else
|
2342
|
+
"#{class_name}('#{self}')"
|
2343
|
+
end
|
2344
|
+
end
|
2345
|
+
|
2346
|
+
# Internal comparison operator: returns -1 if the first number is less than the second,
|
2347
|
+
# 0 if both are equal or +1 if the first is greater than the secong.
|
2348
|
+
def <=>(other)
|
2349
|
+
case other
|
2350
|
+
when *num_class.context.coercible_types_or_num
|
2351
|
+
other = Num(other)
|
2352
|
+
if self.special? || other.special?
|
2353
|
+
if self.nan? || other.nan?
|
2354
|
+
1
|
2355
|
+
else
|
2356
|
+
self_v = self.finite? ? 0 : self.sign
|
2357
|
+
other_v = other.finite? ? 0 : other.sign
|
2358
|
+
self_v <=> other_v
|
2359
|
+
end
|
2360
|
+
else
|
2361
|
+
if self.zero?
|
2362
|
+
if other.zero?
|
2363
|
+
0
|
2364
|
+
else
|
2365
|
+
-other.sign
|
2366
|
+
end
|
2367
|
+
elsif other.zero?
|
2368
|
+
self.sign
|
2369
|
+
elsif other.sign < self.sign
|
2370
|
+
+1
|
2371
|
+
elsif self.sign < other.sign
|
2372
|
+
-1
|
2373
|
+
else
|
2374
|
+
self_adjusted = self.adjusted_exponent
|
2375
|
+
other_adjusted = other.adjusted_exponent
|
2376
|
+
if self_adjusted == other_adjusted
|
2377
|
+
self_padded,other_padded = self.coefficient,other.coefficient
|
2378
|
+
d = self.exponent - other.exponent
|
2379
|
+
if d>0
|
2380
|
+
self_padded *= num_class.int_radix_power(d)
|
2381
|
+
else
|
2382
|
+
other_padded *= num_class.int_radix_power(-d)
|
2383
|
+
end
|
2384
|
+
(self_padded <=> other_padded)*self.sign
|
2385
|
+
elsif self_adjusted > other_adjusted
|
2386
|
+
self.sign
|
2387
|
+
else
|
2388
|
+
-self.sign
|
2389
|
+
end
|
2390
|
+
end
|
2391
|
+
end
|
2392
|
+
else
|
2393
|
+
if !self.nan? && defined? other.coerce
|
2394
|
+
x, y = other.coerce(self)
|
2395
|
+
x <=> y
|
2396
|
+
else
|
2397
|
+
nil
|
2398
|
+
end
|
2399
|
+
end
|
2400
|
+
end
|
2401
|
+
def ==(other)
|
2402
|
+
(self<=>other) == 0
|
2403
|
+
end
|
2404
|
+
include Comparable
|
2405
|
+
|
2406
|
+
def hash
|
2407
|
+
([num_class]+reduce.split).hash # TODO: optimize
|
2408
|
+
end
|
2409
|
+
|
2410
|
+
def eql?(other)
|
2411
|
+
return false unless other.is_a?(num_class)
|
2412
|
+
reduce.split == other.reduce.split
|
2413
|
+
end
|
2414
|
+
|
2415
|
+
# Compares like <=> but returns a DecNum value.
|
2416
|
+
def compare(other, context=nil)
|
2417
|
+
|
2418
|
+
other = _convert(other)
|
2419
|
+
|
2420
|
+
if self.special? || other.special?
|
2421
|
+
ans = _check_nans(context, other)
|
2422
|
+
return ans if ans
|
2423
|
+
end
|
2424
|
+
|
2425
|
+
return Num(self <=> other)
|
2426
|
+
|
2427
|
+
end
|
2428
|
+
|
2429
|
+
# Exponent of the magnitude of the most significant digit of the operand
|
2430
|
+
def adjusted_exponent
|
2431
|
+
if special?
|
2432
|
+
0
|
2433
|
+
else
|
2434
|
+
@exp + number_of_digits - 1
|
2435
|
+
end
|
2436
|
+
end
|
2437
|
+
|
2438
|
+
# Synonym for DecNum#adjusted_exponent()
|
2439
|
+
def scientific_exponent
|
2440
|
+
adjusted_exponent
|
2441
|
+
end
|
2442
|
+
|
2443
|
+
# Exponent as though the significand were a fraction (the decimal point before its first digit)
|
2444
|
+
def fractional_exponent
|
2445
|
+
scientific_exponent + 1
|
2446
|
+
end
|
2447
|
+
|
2448
|
+
# Number of digits in the significand
|
2449
|
+
def number_of_digits
|
2450
|
+
# digits.size
|
2451
|
+
@coeff.is_a?(Integer) ? @coeff.to_s(num_class.radix).size : 0
|
2452
|
+
end
|
2453
|
+
|
2454
|
+
# Digits of the significand as an array of integers
|
2455
|
+
def digits
|
2456
|
+
@coeff.to_s(num_class.radix).split('').map{|d| d.to_i} # TODO: optimize in derivided classes
|
2457
|
+
end
|
2458
|
+
|
2459
|
+
# Significand as an integer, unsigned. Synonym of coefficient
|
2460
|
+
def integral_significand
|
2461
|
+
@coeff
|
2462
|
+
end
|
2463
|
+
|
2464
|
+
# Exponent of the significand as an integer. Synonym of exponent
|
2465
|
+
def integral_exponent
|
2466
|
+
# fractional_exponent - number_of_digits
|
2467
|
+
@exp
|
2468
|
+
end
|
2469
|
+
|
2470
|
+
# Sign of the number: +1 for plus / -1 for minus.
|
2471
|
+
def sign
|
2472
|
+
@sign
|
2473
|
+
end
|
2474
|
+
|
2475
|
+
# Significand as an integer, unsigned
|
2476
|
+
def coefficient
|
2477
|
+
@coeff
|
2478
|
+
end
|
2479
|
+
|
2480
|
+
# Exponent of the significand as an integer.
|
2481
|
+
def exponent
|
2482
|
+
@exp
|
2483
|
+
end
|
2484
|
+
|
2485
|
+
# Return the value of the number as an signed integer and a scale.
|
2486
|
+
def to_int_scale
|
2487
|
+
if special?
|
2488
|
+
nil
|
2489
|
+
else
|
2490
|
+
[@sign*integral_significand, integral_exponent]
|
2491
|
+
end
|
2492
|
+
end
|
2493
|
+
|
2494
|
+
# Returns a copy of with the sign set to +
|
2495
|
+
def copy_abs
|
2496
|
+
Num(+1,@coeff,@exp)
|
2497
|
+
end
|
2498
|
+
|
2499
|
+
# Returns a copy of with the sign inverted
|
2500
|
+
def copy_negate
|
2501
|
+
Num(-@sign,@coeff,@exp)
|
2502
|
+
end
|
2503
|
+
|
2504
|
+
# Returns a copy of with the sign of other
|
2505
|
+
def copy_sign(other)
|
2506
|
+
sign = other.respond_to?(:sign) ? other.sign : ((other < 0) ? -1 : +1)
|
2507
|
+
Num(sign, @coeff, @exp)
|
2508
|
+
end
|
2509
|
+
|
2510
|
+
# Returns true if the value is an integer
|
2511
|
+
def integral?
|
2512
|
+
if finite?
|
2513
|
+
if @exp>=0 || @coeff==0
|
2514
|
+
true
|
2515
|
+
else
|
2516
|
+
if @exp <= -number_of_digits
|
2517
|
+
false
|
2518
|
+
else
|
2519
|
+
m = num_class.int_radix_power(-@exp)
|
2520
|
+
(@coeff % m) == 0
|
2521
|
+
end
|
2522
|
+
end
|
2523
|
+
else
|
2524
|
+
false
|
2525
|
+
end
|
2526
|
+
end
|
2527
|
+
|
2528
|
+
# returns true if is an even integer
|
2529
|
+
def even?
|
2530
|
+
# integral? && ((to_i%2)==0)
|
2531
|
+
if finite?
|
2532
|
+
if @exp>0 || @coeff==0
|
2533
|
+
true
|
2534
|
+
else
|
2535
|
+
if @exp <= -number_of_digits
|
2536
|
+
false
|
2537
|
+
else
|
2538
|
+
m = num_class.int_radix_power(-@exp)
|
2539
|
+
if (@coeff % m) == 0
|
2540
|
+
# ((@coeff / m) % 2) == 0
|
2541
|
+
((@coeff / m) & 1) == 0
|
2542
|
+
else
|
2543
|
+
false
|
2544
|
+
end
|
2545
|
+
end
|
2546
|
+
end
|
2547
|
+
else
|
2548
|
+
false
|
2549
|
+
end
|
2550
|
+
end
|
2551
|
+
|
2552
|
+
# returns true if is an odd integer
|
2553
|
+
def odd?
|
2554
|
+
# integral? && ((to_i%2)==1)
|
2555
|
+
# integral? && !even?
|
2556
|
+
if finite?
|
2557
|
+
if @exp>0 || @coeff==0
|
2558
|
+
false
|
2559
|
+
else
|
2560
|
+
if @exp <= -number_of_digits
|
2561
|
+
false
|
2562
|
+
else
|
2563
|
+
m = num_class.int_radix_power(-@exp)
|
2564
|
+
if (@coeff % m) == 0
|
2565
|
+
# ((@coeff / m) % 2) == 1
|
2566
|
+
((@coeff / m) & 1) == 1
|
2567
|
+
else
|
2568
|
+
false
|
2569
|
+
end
|
2570
|
+
end
|
2571
|
+
end
|
2572
|
+
else
|
2573
|
+
false
|
2574
|
+
end
|
2575
|
+
end
|
2576
|
+
|
2577
|
+
# Rescale so that the exponent is exp, either by padding with zeros
|
2578
|
+
# or by truncating digits.
|
2579
|
+
def rescale(exp, context=nil, watch_exp=true)
|
2580
|
+
context = define_context(context)
|
2581
|
+
exp = _convert(exp)
|
2582
|
+
if self.special? || exp.special?
|
2583
|
+
ans = _check_nans(context, exp)
|
2584
|
+
return ans if ans
|
2585
|
+
if exp.infinite? || self.infinite?
|
2586
|
+
return Num(self) if exp.infinite? && self.infinite?
|
2587
|
+
return context.exception(InvalidOperation, 'rescale with one INF')
|
2588
|
+
end
|
2589
|
+
end
|
2590
|
+
return context.exception(InvalidOperation,"exponent of rescale is not integral") unless exp.integral?
|
2591
|
+
exp = exp.to_i
|
2592
|
+
_watched_rescale(exp, context, watch_exp)
|
2593
|
+
end
|
2594
|
+
|
2595
|
+
# Quantize so its exponent is the same as that of y.
|
2596
|
+
def quantize(exp, context=nil, watch_exp=true)
|
2597
|
+
exp = _convert(exp)
|
2598
|
+
context = define_context(context)
|
2599
|
+
if self.special? || exp.special?
|
2600
|
+
ans = _check_nans(context, exp)
|
2601
|
+
return ans if ans
|
2602
|
+
if exp.infinite? || self.infinite?
|
2603
|
+
return Num(self) if exp.infinite? && self.infinite?
|
2604
|
+
return context.exception(InvalidOperation, 'quantize with one INF')
|
2605
|
+
end
|
2606
|
+
end
|
2607
|
+
exp = exp.exponent
|
2608
|
+
_watched_rescale(exp, context, watch_exp)
|
2609
|
+
end
|
2610
|
+
|
2611
|
+
# Return true if has the same exponent as other.
|
2612
|
+
#
|
2613
|
+
# If either operand is a special value, the following rules are used:
|
2614
|
+
# * return true if both operands are infinities
|
2615
|
+
# * return true if both operands are NaNs
|
2616
|
+
# * otherwise, return false.
|
2617
|
+
def same_quantum?(other)
|
2618
|
+
other = _convert(other)
|
2619
|
+
if self.special? || other.special?
|
2620
|
+
return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
|
2621
|
+
end
|
2622
|
+
return self.exponent == other.exponent
|
2623
|
+
end
|
2624
|
+
|
2625
|
+
# Rounds to a nearby integer. May raise Inexact or Rounded.
|
2626
|
+
def to_integral_exact(context=nil)
|
2627
|
+
context = define_context(context)
|
2628
|
+
if special?
|
2629
|
+
ans = _check_nans(context)
|
2630
|
+
return ans if ans
|
2631
|
+
return Num(self)
|
2632
|
+
end
|
2633
|
+
return Num(self) if @exp >= 0
|
2634
|
+
return Num(@sign, 0, 0) if zero?
|
2635
|
+
context.exception Rounded
|
2636
|
+
ans = _rescale(0, context.rounding)
|
2637
|
+
context.exception Inexact if ans != self
|
2638
|
+
return ans
|
2639
|
+
end
|
2640
|
+
|
2641
|
+
# Rounds to a nearby integer. Doesn't raise Inexact or Rounded.
|
2642
|
+
def to_integral_value(context=nil)
|
2643
|
+
context = define_context(context)
|
2644
|
+
if special?
|
2645
|
+
ans = _check_nans(context)
|
2646
|
+
return ans if ans
|
2647
|
+
return Num(self)
|
2648
|
+
end
|
2649
|
+
return Num(self) if @exp >= 0
|
2650
|
+
return _rescale(0, context.rounding)
|
2651
|
+
end
|
2652
|
+
|
2653
|
+
# General rounding.
|
2654
|
+
#
|
2655
|
+
# With an integer argument this acts like Float#round: the parameter specifies the number
|
2656
|
+
# of fractional digits (or digits to the left of the decimal point if negative).
|
2657
|
+
#
|
2658
|
+
# Options can be passed as a Hash instead; valid options are:
|
2659
|
+
# * :rounding method for rounding (see Context#new())
|
2660
|
+
# The precision can be specified as:
|
2661
|
+
# * :places number of fractional digits as above.
|
2662
|
+
# * :exponent specifies the exponent corresponding to the
|
2663
|
+
# digit to be rounded (exponent == -places)
|
2664
|
+
# * :precision or :significan_digits is the number of digits
|
2665
|
+
# * :power 10^exponent, value of the digit to be rounded,
|
2666
|
+
# should be passed as a type convertible to DecNum.
|
2667
|
+
# * :index 0-based index of the digit to be rounded
|
2668
|
+
# * :rindex right 0-based index of the digit to be rounded
|
2669
|
+
#
|
2670
|
+
# The default is :places=>0 (round to integer).
|
2671
|
+
#
|
2672
|
+
# Example: ways of specifiying the rounding position
|
2673
|
+
# number: 1 2 3 4 . 5 6 7 8
|
2674
|
+
# :places -3 -2 -1 0 1 2 3 4
|
2675
|
+
# :exponent 3 2 1 0 -1 -2 -3 -4
|
2676
|
+
# :precision 1 2 3 4 5 6 7 8
|
2677
|
+
# :power 1E3 1E2 10 1 0.1 1E-2 1E-3 1E-4
|
2678
|
+
# :index 0 1 2 3 4 5 6 7
|
2679
|
+
# :index 7 6 5 4 3 2 1 0
|
2680
|
+
def round(opt={})
|
2681
|
+
opt = { :places=>opt } if opt.kind_of?(Integer)
|
2682
|
+
r = opt[:rounding] || :half_up
|
2683
|
+
as_int = false
|
2684
|
+
if v=(opt[:precision] || opt[:significant_digits])
|
2685
|
+
prec = v
|
2686
|
+
elsif v=(opt[:places])
|
2687
|
+
prec = adjusted_exponent + 1 + v
|
2688
|
+
elsif v=(opt[:exponent])
|
2689
|
+
prec = adjusted_exponent + 1 - v
|
2690
|
+
elsif v=(opt[:power])
|
2691
|
+
prec = adjusted_exponent + 1 - DecNum(v).adjusted_exponent
|
2692
|
+
elsif v=(opt[:index])
|
2693
|
+
prec = i+1
|
2694
|
+
elsif v=(opt[:rindex])
|
2695
|
+
prec = number_of_digits - v
|
2696
|
+
else
|
2697
|
+
prec = adjusted_exponent + 1
|
2698
|
+
as_int = true
|
2699
|
+
end
|
2700
|
+
dg = number_of_digits-prec
|
2701
|
+
changed = _round(r, dg)
|
2702
|
+
coeff = num_class.int_div_radix_power(@coeff, dg)
|
2703
|
+
exp = @exp + dg
|
2704
|
+
coeff += 1 if changed==1
|
2705
|
+
result = Num(@sign, coeff, exp)
|
2706
|
+
return as_int ? result.to_i : result
|
2707
|
+
end
|
2708
|
+
|
2709
|
+
# General ceiling operation (as for Float) with same options for precision
|
2710
|
+
# as Flt::Num#round()
|
2711
|
+
def ceil(opt={})
|
2712
|
+
opt[:rounding] = :ceiling
|
2713
|
+
round opt
|
2714
|
+
end
|
2715
|
+
|
2716
|
+
# General floor operation (as for Float) with same options for precision
|
2717
|
+
# as Flt::Num#round()
|
2718
|
+
def floor(opt={})
|
2719
|
+
opt[:rounding] = :floor
|
2720
|
+
round opt
|
2721
|
+
end
|
2722
|
+
|
2723
|
+
# General truncate operation (as for Float) with same options for precision
|
2724
|
+
# as Flt::Num#round()
|
2725
|
+
def truncate(opt={})
|
2726
|
+
opt[:rounding] = :down
|
2727
|
+
round opt
|
2728
|
+
end
|
2729
|
+
|
2730
|
+
# Fused multiply-add.
|
2731
|
+
#
|
2732
|
+
# Computes (self*other+third) with no rounding of the intermediate product self*other.
|
2733
|
+
def fma(other, third, context=nil)
|
2734
|
+
context =define_context(context)
|
2735
|
+
other = _convert(other)
|
2736
|
+
third = _convert(third)
|
2737
|
+
if self.special? || other.special?
|
2738
|
+
return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
|
2739
|
+
return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
|
2740
|
+
if self.nan?
|
2741
|
+
product = self
|
2742
|
+
elsif other.nan?
|
2743
|
+
product = other
|
2744
|
+
elsif self.infinite?
|
2745
|
+
return context.exception(InvalidOperation, 'INF * 0 in fma') if other.zero?
|
2746
|
+
product = num_class.infinity(self.sign*other.sign)
|
2747
|
+
elsif other.infinite?
|
2748
|
+
return context.exception(InvalidOperation, '0 * INF in fma') if self.zero?
|
2749
|
+
product = num_class.infinity(self.sign*other.sign)
|
2750
|
+
end
|
2751
|
+
else
|
2752
|
+
product = Num(self.sign*other.sign,self.coefficient*other.coefficient, self.exponent+other.exponent)
|
2753
|
+
end
|
2754
|
+
return product.add(third, context)
|
2755
|
+
end
|
2756
|
+
|
2757
|
+
# Convert to a text literal in the specified base (10 by default).
|
2758
|
+
#
|
2759
|
+
# If the output base is the floating-point radix, the rendered value is the exact value of the number,
|
2760
|
+
# showing trailing zeros up to the stored precision.
|
2761
|
+
#
|
2762
|
+
# With bases different from the radix, the floating-point number is treated
|
2763
|
+
# as an approximation with a precision of number_of_digits, representing any value
|
2764
|
+
# within its rounding range. In that case, this method always renders
|
2765
|
+
# that aproximated value in other base without introducing additional precision.
|
2766
|
+
#
|
2767
|
+
# The resulting text numeral is such that it has as few digits as possible while
|
2768
|
+
# preserving the original while if converted back to the same type of floating-point value with
|
2769
|
+
# the same context precision that the original number had (number_of_digits).
|
2770
|
+
#
|
2771
|
+
# To render the exact value of a Num x in a different base b this can be used
|
2772
|
+
# Flt::Num.convert_exact(x, b).to_s(:base=>b)
|
2773
|
+
# Or, to represent a BinNum x in decimal:
|
2774
|
+
# x.to_decimal_exact(:exact=>true).to_s
|
2775
|
+
#
|
2776
|
+
# Options:
|
2777
|
+
# :base output base, 10 by default
|
2778
|
+
#
|
2779
|
+
# :rounding is used to override the context rounding, but it's main use is specify :nearest
|
2780
|
+
# as the rounding-mode, which means that the text literal will have enough digits to be
|
2781
|
+
# converted back to self in any round-to_nearest rounding mode. Otherwise only enough
|
2782
|
+
# digits for conversion in a specific rounding mode are produced.
|
2783
|
+
#
|
2784
|
+
# :all_digits if true all significant digits are shown. A digit
|
2785
|
+
# is considered as significant here if when used on input, cannot
|
2786
|
+
# arbitrarily change its value and preserve the parsed value of the
|
2787
|
+
# floating point number.
|
2788
|
+
# Using all_digits will show trailing zeros up to the precision of the floating-point, so
|
2789
|
+
# the output will preserve the input precision. With all_digits and the :down rounding-mod
|
2790
|
+
# (truncation), the result will be the exact value floating-point value in the output base
|
2791
|
+
# (if it is conmensurable with the floating-point base).
|
2792
|
+
def to_s(*args)
|
2793
|
+
eng=false
|
2794
|
+
context=nil
|
2795
|
+
|
2796
|
+
# admit legacy arguments eng, context in that order
|
2797
|
+
if [true,false].include?(args.first)
|
2798
|
+
eng = args.shift
|
2799
|
+
end
|
2800
|
+
if args.first.is_a?(Num::ContextBase)
|
2801
|
+
context = args.shift
|
2802
|
+
end
|
2803
|
+
# admit also :eng to specify the eng mode
|
2804
|
+
if args.first == :eng
|
2805
|
+
eng = true
|
2806
|
+
args.shift
|
2807
|
+
end
|
2808
|
+
raise TypeError, "Invalid arguments to #{num_class}#to_s" if args.size>1 || (args.size==1 && !args.first.is_a?(Hash))
|
2809
|
+
# an admit arguments through a final parameters Hash
|
2810
|
+
options = args.first || {}
|
2811
|
+
context = options.delete(:context) if options.has_key?(:context)
|
2812
|
+
eng = options.delete(:eng) if options.has_key?(:eng)
|
2813
|
+
|
2814
|
+
format(context, options.merge(:eng=>eng))
|
2815
|
+
end
|
2816
|
+
|
2817
|
+
# Raises to the power of x.
|
2818
|
+
#
|
2819
|
+
# If self is negative then other
|
2820
|
+
# must be integral. The result will be inexact unless other is
|
2821
|
+
# integral and the result is finite and can be expressed exactly
|
2822
|
+
# in 'precision' digits.
|
2823
|
+
def power(other, context=nil)
|
2824
|
+
|
2825
|
+
context = num_class.define_context(context)
|
2826
|
+
other = _convert(other)
|
2827
|
+
|
2828
|
+
ans = _check_nans(context, other)
|
2829
|
+
return ans if ans
|
2830
|
+
|
2831
|
+
# 0**0 = NaN (!), x**0 = 1 for nonzero x (including +/-Infinity)
|
2832
|
+
if other.zero?
|
2833
|
+
if self.zero?
|
2834
|
+
return context.exception(InvalidOperation, '0 ** 0')
|
2835
|
+
else
|
2836
|
+
return Num(1)
|
2837
|
+
end
|
2838
|
+
end
|
2839
|
+
|
2840
|
+
# result has sign -1 iff self.sign is -1 and other is an odd integer
|
2841
|
+
result_sign = +1
|
2842
|
+
_self = self
|
2843
|
+
if _self.sign == -1
|
2844
|
+
if other.integral?
|
2845
|
+
result_sign = -1 if !other.even?
|
2846
|
+
else
|
2847
|
+
# -ve**noninteger = NaN
|
2848
|
+
# (-0)**noninteger = 0**noninteger
|
2849
|
+
unless self.zero?
|
2850
|
+
return context.exception(InvalidOperation, 'x ** y with x negative and y not an integer')
|
2851
|
+
end
|
2852
|
+
end
|
2853
|
+
# negate self, without doing any unwanted rounding
|
2854
|
+
_self = self.copy_negate
|
2855
|
+
end
|
2856
|
+
|
2857
|
+
# 0**(+ve or Inf)= 0; 0**(-ve or -Inf) = Infinity
|
2858
|
+
if _self.zero?
|
2859
|
+
return (other.sign == +1) ? Num(result_sign, 0, 0) : num_class.infinity(result_sign)
|
2860
|
+
end
|
2861
|
+
|
2862
|
+
# Inf**(+ve or Inf) = Inf; Inf**(-ve or -Inf) = 0
|
2863
|
+
if _self.infinite?
|
2864
|
+
return (other.sign == +1) ? num_class.infinity(result_sign) : Num(result_sign, 0, 0)
|
2865
|
+
end
|
2866
|
+
|
2867
|
+
# 1**other = 1, but the choice of exponent and the flags
|
2868
|
+
# depend on the exponent of self, and on whether other is a
|
2869
|
+
# positive integer, a negative integer, or neither
|
2870
|
+
if _self == Num(1)
|
2871
|
+
return _self if context.exact?
|
2872
|
+
if other.integral?
|
2873
|
+
# exp = max(self._exp*max(int(other), 0),
|
2874
|
+
# 1-context.prec) but evaluating int(other) directly
|
2875
|
+
# is dangerous until we know other is small (other
|
2876
|
+
# could be 1e999999999)
|
2877
|
+
if other.sign == -1
|
2878
|
+
multiplier = 0
|
2879
|
+
elsif other > context.precision
|
2880
|
+
multiplier = context.precision
|
2881
|
+
else
|
2882
|
+
multiplier = other.to_i
|
2883
|
+
end
|
2884
|
+
|
2885
|
+
exp = _self.exponent * multiplier
|
2886
|
+
if exp < 1-context.precision
|
2887
|
+
exp = 1-context.precision
|
2888
|
+
context.exception Rounded
|
2889
|
+
end
|
2890
|
+
else
|
2891
|
+
context.exception Rounded
|
2892
|
+
context.exception Inexact
|
2893
|
+
exp = 1-context.precision
|
2894
|
+
end
|
2895
|
+
|
2896
|
+
return Num(result_sign, num_class.int_radix_power(-exp), exp)
|
2897
|
+
end
|
2898
|
+
|
2899
|
+
# compute adjusted exponent of self
|
2900
|
+
self_adj = _self.adjusted_exponent
|
2901
|
+
|
2902
|
+
# self ** infinity is infinity if self > 1, 0 if self < 1
|
2903
|
+
# self ** -infinity is infinity if self < 1, 0 if self > 1
|
2904
|
+
if other.infinite?
|
2905
|
+
if (other.sign == +1) == (self_adj < 0)
|
2906
|
+
return Num(result_sign, 0, 0)
|
2907
|
+
else
|
2908
|
+
return num_class.infinity(result_sign)
|
2909
|
+
end
|
2910
|
+
end
|
2911
|
+
|
2912
|
+
# from here on, the result always goes through the call
|
2913
|
+
# to _fix at the end of this function.
|
2914
|
+
ans = nil
|
2915
|
+
|
2916
|
+
# crude test to catch cases of extreme overflow/underflow. If
|
2917
|
+
# log_radix(self)*other >= radix**bound and bound >= len(str(Emax))
|
2918
|
+
# then radixs**bound >= radix**len(str(Emax)) >= Emax+1 and hence
|
2919
|
+
# self**other >= radix**(Emax+1), so overflow occurs. The test
|
2920
|
+
# for underflow is similar.
|
2921
|
+
bound = _self._log_radix_exp_bound + other.adjusted_exponent
|
2922
|
+
if (self_adj >= 0) == (other.sign == +1)
|
2923
|
+
# self > 1 and other +ve, or self < 1 and other -ve
|
2924
|
+
# possibility of overflow
|
2925
|
+
if bound >= _number_of_digits(context.emax)
|
2926
|
+
ans = Num(result_sign, 1, context.emax+1)
|
2927
|
+
end
|
2928
|
+
else
|
2929
|
+
# self > 1 and other -ve, or self < 1 and other +ve
|
2930
|
+
# possibility of underflow to 0
|
2931
|
+
etiny = context.etiny
|
2932
|
+
if bound >= _number_of_digits(-etiny)
|
2933
|
+
ans = Num(result_sign, 1, etiny-1)
|
2934
|
+
end
|
2935
|
+
end
|
2936
|
+
|
2937
|
+
# try for an exact result with precision +1
|
2938
|
+
if ans.nil?
|
2939
|
+
if context.exact?
|
2940
|
+
if other.adjusted_exponent < 100 # ???? 4 ? ...
|
2941
|
+
test_precision = _self.number_of_digits*other.to_i+1
|
2942
|
+
else
|
2943
|
+
test_precision = _self.number_of_digits+1
|
2944
|
+
end
|
2945
|
+
else
|
2946
|
+
test_precision = context.precision + 1
|
2947
|
+
end
|
2948
|
+
ans = _self._power_exact(other, test_precision)
|
2949
|
+
if !ans.nil? && (result_sign == -1)
|
2950
|
+
ans = Num(-1, ans.coefficient, ans.exponent)
|
2951
|
+
end
|
2952
|
+
end
|
2953
|
+
|
2954
|
+
# usual case: inexact result, x**y computed directly as exp(y*log(x))
|
2955
|
+
if !ans.nil?
|
2956
|
+
return ans if context.exact?
|
2957
|
+
else
|
2958
|
+
return context.exception(Inexact, "Inexact power") if context.exact?
|
2959
|
+
|
2960
|
+
p = context.precision
|
2961
|
+
xc = _self.coefficient
|
2962
|
+
xe = _self.exponent
|
2963
|
+
yc = other.coefficient
|
2964
|
+
ye = other.exponent
|
2965
|
+
yc = -yc if other.sign == -1
|
2966
|
+
|
2967
|
+
# compute correctly rounded result: start with precision +3,
|
2968
|
+
# then increase precision until result is unambiguously roundable
|
2969
|
+
extra = 3
|
2970
|
+
coeff, exp = nil, nil
|
2971
|
+
loop do
|
2972
|
+
coeff, exp = _power(xc, xe, yc, ye, p+extra)
|
2973
|
+
break if (coeff % (num_class.int_radix_power(_number_of_digits(coeff)-p)/2)) != 0 # base 2: (coeff % (10**(_number_of_digits(coeff)-p-1))) != 0
|
2974
|
+
extra += 3
|
2975
|
+
end
|
2976
|
+
ans = Num(result_sign, coeff, exp)
|
2977
|
+
end
|
2978
|
+
|
2979
|
+
# the specification says that for non-integer other we need to
|
2980
|
+
# raise Inexact, even when the result is actually exact. In
|
2981
|
+
# the same way, we need to raise Underflow here if the result
|
2982
|
+
# is subnormal. (The call to _fix will take care of raising
|
2983
|
+
# Rounded and Subnormal, as usual.)
|
2984
|
+
if !other.integral?
|
2985
|
+
context.exception Inexact
|
2986
|
+
# pad with zeros up to length context.precision+1 if necessary
|
2987
|
+
if ans.number_of_digits <= context.precision
|
2988
|
+
expdiff = context.precision+1 - ans.number_of_digits
|
2989
|
+
ans = Num(ans.sign, num_class.int_mult_radix_power(ans.coefficient, expdiff), ans.exponent-expdiff)
|
2990
|
+
end
|
2991
|
+
context.exception Underflow if ans.adjusted_exponent < context.emin
|
2992
|
+
end
|
2993
|
+
# unlike exp, ln and log10, the power function respects the
|
2994
|
+
# rounding mode; no need to use ROUND_HALF_EVEN here
|
2995
|
+
ans._fix(context)
|
2996
|
+
end
|
2997
|
+
|
2998
|
+
# Check if the number or other is NaN, signal if sNaN or return NaN;
|
2999
|
+
# return nil if none is NaN.
|
3000
|
+
def _check_nans(context=nil, other=nil)
|
3001
|
+
#self_is_nan = self.nan?
|
3002
|
+
#other_is_nan = other.nil? ? false : other.nan?
|
3003
|
+
if self.nan? || (other && other.nan?)
|
3004
|
+
context = define_context(context)
|
3005
|
+
return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
|
3006
|
+
return context.exception(InvalidOperation, 'sNaN', other) if other && other.snan?
|
3007
|
+
return self._fix_nan(context) if self.nan?
|
3008
|
+
return other._fix_nan(context)
|
3009
|
+
else
|
3010
|
+
return nil
|
3011
|
+
end
|
3012
|
+
end
|
3013
|
+
|
3014
|
+
# Rescale so that the exponent is exp, either by padding with zeros
|
3015
|
+
# or by truncating digits, using the given rounding mode.
|
3016
|
+
#
|
3017
|
+
# Specials are returned without change. This operation is
|
3018
|
+
# quiet: it raises no flags, and uses no information from the
|
3019
|
+
# context.
|
3020
|
+
#
|
3021
|
+
# exp = exp to scale to (an integer)
|
3022
|
+
# rounding = rounding mode
|
3023
|
+
def _rescale(exp, rounding)
|
3024
|
+
|
3025
|
+
return Num(self) if special?
|
3026
|
+
return Num(sign, 0, exp) if zero?
|
3027
|
+
return Num(sign, @coeff*num_class.int_radix_power(self.exponent - exp), exp) if self.exponent > exp
|
3028
|
+
#nd = number_of_digits + self.exponent - exp
|
3029
|
+
nd = exp - self.exponent
|
3030
|
+
if number_of_digits < nd
|
3031
|
+
slf = Num(sign, 1, exp-1)
|
3032
|
+
nd = number_of_digits
|
3033
|
+
else
|
3034
|
+
slf = num_class.new(self)
|
3035
|
+
end
|
3036
|
+
|
3037
|
+
changed = slf._round(rounding, nd)
|
3038
|
+
coeff = num_class.int_div_radix_power(@coeff, nd)
|
3039
|
+
coeff += 1 if changed==1
|
3040
|
+
Num(slf.sign, coeff, exp)
|
3041
|
+
|
3042
|
+
end
|
3043
|
+
|
3044
|
+
def _watched_rescale(exp, context, watch_exp)
|
3045
|
+
if !watch_exp
|
3046
|
+
ans = _rescale(exp, context.rounding)
|
3047
|
+
context.exception(Rounded) if ans.exponent > self.exponent
|
3048
|
+
context.exception(Inexact) if ans != self
|
3049
|
+
return ans
|
3050
|
+
end
|
3051
|
+
|
3052
|
+
if exp < context.etiny || exp > context.emax
|
3053
|
+
return context.exception(InvalidOperation, "target operation out of bounds in quantize/rescale")
|
3054
|
+
end
|
3055
|
+
|
3056
|
+
return Num(@sign, 0, exp)._fix(context) if zero?
|
3057
|
+
|
3058
|
+
self_adjusted = adjusted_exponent
|
3059
|
+
return context.exception(InvalidOperation,"exponent of quantize/rescale result too large for current context") if self_adjusted > context.emax
|
3060
|
+
return context.exception(InvalidOperation,"quantize/rescale has too many digits for current context") if (self_adjusted - exp + 1 > context.precision) && !context.exact?
|
3061
|
+
|
3062
|
+
ans = _rescale(exp, context.rounding)
|
3063
|
+
return context.exception(InvalidOperation,"exponent of rescale result too large for current context") if ans.adjusted_exponent > context.emax
|
3064
|
+
return context.exception(InvalidOperation,"rescale result has too many digits for current context") if (ans.number_of_digits > context.precision) && !context.exact?
|
3065
|
+
if ans.exponent > self.exponent
|
3066
|
+
context.exception(Rounded)
|
3067
|
+
context.exception(Inexact) if ans!=self
|
3068
|
+
end
|
3069
|
+
context.exception(Subnormal) if !ans.zero? && (ans.adjusted_exponent < context.emin)
|
3070
|
+
return ans._fix(context)
|
3071
|
+
end
|
3072
|
+
|
3073
|
+
# Returns copy with sign inverted
|
3074
|
+
def _neg(context=nil)
|
3075
|
+
if special?
|
3076
|
+
ans = _check_nans(context)
|
3077
|
+
return ans if ans
|
3078
|
+
end
|
3079
|
+
if zero?
|
3080
|
+
ans = copy_abs
|
3081
|
+
else
|
3082
|
+
ans = copy_negate
|
3083
|
+
end
|
3084
|
+
context = define_context(context)
|
3085
|
+
ans._fix(context)
|
3086
|
+
end
|
3087
|
+
|
3088
|
+
# Returns a copy with precision adjusted
|
3089
|
+
def _pos(context=nil)
|
3090
|
+
if special?
|
3091
|
+
ans = _check_nans(context)
|
3092
|
+
return ans if ans
|
3093
|
+
end
|
3094
|
+
if zero?
|
3095
|
+
ans = copy_abs
|
3096
|
+
else
|
3097
|
+
ans = Num(self)
|
3098
|
+
end
|
3099
|
+
context = define_context(context)
|
3100
|
+
ans._fix(context)
|
3101
|
+
end
|
3102
|
+
|
3103
|
+
# Returns a copy with positive sign
|
3104
|
+
def _abs(round=true, context=nil)
|
3105
|
+
return copy_abs if not round
|
3106
|
+
|
3107
|
+
if special?
|
3108
|
+
ans = _check_nans(context)
|
3109
|
+
return ans if ans
|
3110
|
+
end
|
3111
|
+
if sign>0
|
3112
|
+
ans = _neg(context)
|
3113
|
+
else
|
3114
|
+
ans = _pos(context)
|
3115
|
+
end
|
3116
|
+
ans
|
3117
|
+
end
|
3118
|
+
|
3119
|
+
# Round if it is necessary to keep within precision.
|
3120
|
+
def _fix(context)
|
3121
|
+
return self if context.exact?
|
3122
|
+
|
3123
|
+
if special?
|
3124
|
+
if nan?
|
3125
|
+
return _fix_nan(context)
|
3126
|
+
else
|
3127
|
+
return Num(self)
|
3128
|
+
end
|
3129
|
+
end
|
3130
|
+
|
3131
|
+
etiny = context.etiny
|
3132
|
+
etop = context.etop
|
3133
|
+
if zero?
|
3134
|
+
exp_max = context.clamp? ? etop : context.emax
|
3135
|
+
new_exp = [[@exp, etiny].max, exp_max].min
|
3136
|
+
if new_exp!=@exp
|
3137
|
+
context.exception Clamped
|
3138
|
+
return Num(sign,0,new_exp)
|
3139
|
+
else
|
3140
|
+
return Num(self)
|
3141
|
+
end
|
3142
|
+
end
|
3143
|
+
|
3144
|
+
nd = number_of_digits
|
3145
|
+
exp_min = nd + @exp - context.precision
|
3146
|
+
if exp_min > etop
|
3147
|
+
context.exception Inexact
|
3148
|
+
context.exception Rounded
|
3149
|
+
return context.exception(Overflow, 'above Emax', sign)
|
3150
|
+
end
|
3151
|
+
|
3152
|
+
self_is_subnormal = exp_min < etiny
|
3153
|
+
|
3154
|
+
if self_is_subnormal
|
3155
|
+
context.exception Subnormal
|
3156
|
+
exp_min = etiny
|
3157
|
+
end
|
3158
|
+
|
3159
|
+
if @exp < exp_min
|
3160
|
+
context.exception Rounded
|
3161
|
+
# dig is the digits number from 0 (MS) to number_of_digits-1 (LS)
|
3162
|
+
# dg = numberof_digits-dig is from 1 (LS) to number_of_digits (MS)
|
3163
|
+
dg = exp_min - @exp # dig = number_of_digits + exp - exp_min
|
3164
|
+
if dg > number_of_digits # dig<0
|
3165
|
+
d = Num(sign,1,exp_min-1)
|
3166
|
+
dg = number_of_digits # dig = 0
|
3167
|
+
else
|
3168
|
+
d = Num(self)
|
3169
|
+
end
|
3170
|
+
changed = d._round(context.rounding, dg)
|
3171
|
+
coeff = num_class.int_div_radix_power(d.coefficient, dg)
|
3172
|
+
coeff += 1 if changed==1
|
3173
|
+
ans = Num(sign, coeff, exp_min)
|
3174
|
+
if changed!=0
|
3175
|
+
context.exception Inexact
|
3176
|
+
if self_is_subnormal
|
3177
|
+
context.exception Underflow
|
3178
|
+
if ans.zero?
|
3179
|
+
context.exception Clamped
|
3180
|
+
end
|
3181
|
+
elsif ans.number_of_digits == context.precision+1
|
3182
|
+
if ans.exponent< etop
|
3183
|
+
ans = Num(ans.sign, num_class.int_div_radix_power(ans.coefficient,1), ans.exponent+1)
|
3184
|
+
else
|
3185
|
+
ans = context.exception(Overflow, 'above Emax', d.sign)
|
3186
|
+
end
|
3187
|
+
end
|
3188
|
+
end
|
3189
|
+
return ans
|
3190
|
+
end
|
3191
|
+
|
3192
|
+
if context.clamp? && @exp>etop
|
3193
|
+
context.exception Clamped
|
3194
|
+
self_padded = num_class.int_mult_radix_power(@coeff, @exp-etop)
|
3195
|
+
return Num(sign,self_padded,etop)
|
3196
|
+
end
|
3197
|
+
|
3198
|
+
return Num(self)
|
3199
|
+
|
3200
|
+
end
|
3201
|
+
|
3202
|
+
# adjust payload of a NaN to the context
|
3203
|
+
def _fix_nan(context)
|
3204
|
+
if !context.exact?
|
3205
|
+
payload = @coeff
|
3206
|
+
payload = nil if payload==0
|
3207
|
+
|
3208
|
+
max_payload_len = context.maximum_nan_diagnostic_digits
|
3209
|
+
|
3210
|
+
if number_of_digits > max_payload_len
|
3211
|
+
payload = payload.to_s[-max_payload_len..-1].to_i
|
3212
|
+
return DecNum([@sign, payload, @exp])
|
3213
|
+
end
|
3214
|
+
end
|
3215
|
+
Num(self)
|
3216
|
+
end
|
3217
|
+
|
3218
|
+
protected
|
3219
|
+
|
3220
|
+
def _divide_truncate(other, context)
|
3221
|
+
context = define_context(context)
|
3222
|
+
sign = self.sign * other.sign
|
3223
|
+
if other.infinite?
|
3224
|
+
ideal_exp = self.exponent
|
3225
|
+
else
|
3226
|
+
ideal_exp = [self.exponent, other.exponent].min
|
3227
|
+
end
|
3228
|
+
|
3229
|
+
expdiff = self.adjusted_exponent - other.adjusted_exponent
|
3230
|
+
if self.zero? || other.infinite? || (expdiff <= -2)
|
3231
|
+
return [Num(sign, 0, 0), _rescale(ideal_exp, context.rounding)]
|
3232
|
+
end
|
3233
|
+
if (expdiff <= context.precision) || context.exact?
|
3234
|
+
self_coeff = self.coefficient
|
3235
|
+
other_coeff = other.coefficient
|
3236
|
+
de = self.exponent - other.exponent
|
3237
|
+
if de >= 0
|
3238
|
+
self_coeff = num_class.int_mult_radix_power(self_coeff, de)
|
3239
|
+
else
|
3240
|
+
other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
|
3241
|
+
end
|
3242
|
+
q, r = self_coeff.divmod(other_coeff)
|
3243
|
+
if (q < num_class.int_radix_power(context.precision)) || context.exact?
|
3244
|
+
return [Num(sign, q, 0),Num(self.sign, r, ideal_exp)]
|
3245
|
+
end
|
3246
|
+
end
|
3247
|
+
# Here the quotient is too large to be representable
|
3248
|
+
ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
|
3249
|
+
return [ans, ans]
|
3250
|
+
|
3251
|
+
end
|
3252
|
+
|
3253
|
+
def _divide_floor(other, context)
|
3254
|
+
context = define_context(context)
|
3255
|
+
sign = self.sign * other.sign
|
3256
|
+
if other.infinite?
|
3257
|
+
ideal_exp = self.exponent
|
3258
|
+
else
|
3259
|
+
ideal_exp = [self.exponent, other.exponent].min
|
3260
|
+
end
|
3261
|
+
|
3262
|
+
expdiff = self.adjusted_exponent - other.adjusted_exponent
|
3263
|
+
if self.zero? || other.infinite? || (expdiff <= -2)
|
3264
|
+
return [Num(sign, 0, 0), _rescale(ideal_exp, context.rounding)]
|
3265
|
+
end
|
3266
|
+
if (expdiff <= context.precision) || context.exact?
|
3267
|
+
self_coeff = self.coefficient*self.sign
|
3268
|
+
other_coeff = other.coefficient*other.sign
|
3269
|
+
de = self.exponent - other.exponent
|
3270
|
+
if de >= 0
|
3271
|
+
self_coeff = num_class.int_mult_radix_power(self_coeff, de)
|
3272
|
+
else
|
3273
|
+
other_coeff = num_class.int_mult_radix_power(other_coeff, -de)
|
3274
|
+
end
|
3275
|
+
q, r = self_coeff.divmod(other_coeff)
|
3276
|
+
if r<0
|
3277
|
+
r = -r
|
3278
|
+
rs = -1
|
3279
|
+
else
|
3280
|
+
rs = +1
|
3281
|
+
end
|
3282
|
+
if q<0
|
3283
|
+
q = -q
|
3284
|
+
qs = -1
|
3285
|
+
else
|
3286
|
+
qs = +1
|
3287
|
+
end
|
3288
|
+
if (q < num_class.int_radix_power(context.precision)) || context.exact?
|
3289
|
+
return [Num(qs, q, 0),Num(rs, r, ideal_exp)]
|
3290
|
+
end
|
3291
|
+
end
|
3292
|
+
# Here the quotient is too large to be representable
|
3293
|
+
ans = context.exception(DivisionImpossible, 'quotient too large in //, % or divmod')
|
3294
|
+
return [ans, ans]
|
3295
|
+
|
3296
|
+
end
|
3297
|
+
|
3298
|
+
# Convert to a text literal in the specified base. If the result is
|
3299
|
+
# converted to BinNum with the specified context rounding and the
|
3300
|
+
# same precision that self has (self.number_of_digits), the same
|
3301
|
+
# number will be produced.
|
3302
|
+
#
|
3303
|
+
# Options:
|
3304
|
+
# :base output base, 10 by default
|
3305
|
+
#
|
3306
|
+
# :rounding is used to override the context rounding, but it's main use is specify :nearest
|
3307
|
+
# as the rounding-mode, which means that the text literal will have enough digits to be
|
3308
|
+
# converted back to self in any round-to_nearest rounding mode. Otherwise only enough
|
3309
|
+
# digits for conversion in a specific rounding mode are produced.
|
3310
|
+
#
|
3311
|
+
# :all_digits if true all significant digits are shown. A digit
|
3312
|
+
# is considere as significant here if when used on input, cannot
|
3313
|
+
# arbitrarily change its value and preserve the parsed value of the
|
3314
|
+
# floating point number.
|
3315
|
+
#
|
3316
|
+
# :output_rounding implies :all_digits; it defines the rounding mode for the output,
|
3317
|
+
# that will show all significant digits rounded.
|
3318
|
+
# If it is not passed and :all_digits is true, then :rounding or the context rounding mode
|
3319
|
+
# will be used.
|
3320
|
+
#
|
3321
|
+
# Note that when :base=>10 (the default) we're regarding the binary number x
|
3322
|
+
# as an approximation with x.number_of_digits precision and showing that
|
3323
|
+
# inexact value in decimal without introducing additional precision.
|
3324
|
+
# If the exact value of the number expressed in decimal is desired (we consider
|
3325
|
+
# the Flt an exact number), this can be done with Num.convert_exact.
|
3326
|
+
def format(num_context, options={})
|
3327
|
+
# TODO: support options (base, all_digits, any_rounding, eng) and context options in the same hash
|
3328
|
+
output_radix = options[:base] || 10
|
3329
|
+
rounding = options[:rounding]
|
3330
|
+
all_digits = options[:all_digits]
|
3331
|
+
eng = options[:eng]
|
3332
|
+
output_rounding = options[:output_rounding]
|
3333
|
+
all_digits ||= output_rounding
|
3334
|
+
|
3335
|
+
sgn = @sign<0 ? '-' : ''
|
3336
|
+
if special?
|
3337
|
+
if @exp==:inf
|
3338
|
+
return "#{sgn}Infinity"
|
3339
|
+
elsif @exp==:nan
|
3340
|
+
return "#{sgn}NaN#{@coeff}"
|
3341
|
+
else # exp==:snan
|
3342
|
+
return "#{sgn}sNaN#{@coeff}"
|
3343
|
+
end
|
3344
|
+
end
|
3345
|
+
|
3346
|
+
context = define_context(num_context)
|
3347
|
+
inexact = true
|
3348
|
+
rounding ||= context.rounding
|
3349
|
+
output_rounding ||= rounding
|
3350
|
+
|
3351
|
+
if output_radix == num_class.radix && !all_digits
|
3352
|
+
# show exactly inner representation and precision
|
3353
|
+
ds = @coeff.to_s(output_radix)
|
3354
|
+
n_ds = ds.size
|
3355
|
+
exp = integral_exponent
|
3356
|
+
leftdigits = exp + n_ds
|
3357
|
+
else
|
3358
|
+
p = self.number_of_digits # context.precision
|
3359
|
+
formatter = Flt::Support::Formatter.new(num_class.radix, context.etiny, output_radix)
|
3360
|
+
formatter.format(self, @coeff, @exp, rounding, p, all_digits)
|
3361
|
+
dec_pos,digits = formatter.adjusted_digits(output_rounding)
|
3362
|
+
|
3363
|
+
ds = digits.map{|d| d.to_s(output_radix)}.join
|
3364
|
+
n_ds = ds.size
|
3365
|
+
exp = dec_pos - n_ds
|
3366
|
+
leftdigits = dec_pos
|
3367
|
+
end
|
3368
|
+
|
3369
|
+
# TODO: DRY (this code is duplicated in DecNum#format)
|
3370
|
+
if exp<=0 && leftdigits>-6
|
3371
|
+
dotplace = leftdigits
|
3372
|
+
elsif !eng
|
3373
|
+
dotplace = 1
|
3374
|
+
elsif @coeff==0
|
3375
|
+
dotplace = (leftdigits+1)%3 - 1
|
3376
|
+
else
|
3377
|
+
dotplace = (leftdigits-1)%3 + 1
|
3378
|
+
end
|
3379
|
+
|
3380
|
+
if dotplace <=0
|
3381
|
+
intpart = '0'
|
3382
|
+
fracpart = '.' + '0'*(-dotplace) + ds
|
3383
|
+
elsif dotplace >= n_ds
|
3384
|
+
intpart = ds + '0'*(dotplace - n_ds)
|
3385
|
+
fracpart = ''
|
3386
|
+
else
|
3387
|
+
intpart = ds[0...dotplace]
|
3388
|
+
fracpart = '.' + ds[dotplace..-1]
|
3389
|
+
end
|
3390
|
+
|
3391
|
+
if leftdigits == dotplace
|
3392
|
+
e = ''
|
3393
|
+
else
|
3394
|
+
e = (context.capitals ? 'E' : 'e') + "%+d"%(leftdigits-dotplace)
|
3395
|
+
end
|
3396
|
+
|
3397
|
+
sgn + intpart + fracpart + e
|
3398
|
+
|
3399
|
+
end
|
3400
|
+
|
3401
|
+
# Auxiliar Methods
|
3402
|
+
|
3403
|
+
# Round to i digits using the specified method
|
3404
|
+
def _round(rounding, i)
|
3405
|
+
send("_round_#{rounding}", i)
|
3406
|
+
end
|
3407
|
+
|
3408
|
+
# Round down (toward 0, truncate) to i digits
|
3409
|
+
def _round_down(i)
|
3410
|
+
(@coeff % num_class.int_radix_power(i))==0 ? 0 : -1
|
3411
|
+
end
|
3412
|
+
|
3413
|
+
# Round up (away from 0) to i digits
|
3414
|
+
def _round_up(i)
|
3415
|
+
-_round_down(i)
|
3416
|
+
end
|
3417
|
+
|
3418
|
+
# Round to closest i-digit number with ties down (rounds 5 toward 0)
|
3419
|
+
def _round_half_down(i)
|
3420
|
+
m = num_class.int_radix_power(i)
|
3421
|
+
if (m>1) && ((@coeff%m) == m/2)
|
3422
|
+
-1
|
3423
|
+
else
|
3424
|
+
_round_half_up(i)
|
3425
|
+
end
|
3426
|
+
end
|
3427
|
+
|
3428
|
+
# Round to closest i-digit number with ties up (rounds 5 away from 0)
|
3429
|
+
def _round_half_up(i)
|
3430
|
+
m = num_class.int_radix_power(i)
|
3431
|
+
if (m>1) && ((@coeff % m) >= m/2)
|
3432
|
+
1
|
3433
|
+
else
|
3434
|
+
(@coeff % m)==0 ? 0 : -1
|
3435
|
+
end
|
3436
|
+
end
|
3437
|
+
|
3438
|
+
# Round to closest i-digit number with ties (5) to an even digit
|
3439
|
+
def _round_half_even(i)
|
3440
|
+
m = num_class.int_radix_power(i)
|
3441
|
+
if (m>1) && ((@coeff%m) == m/2 && ((@coeff/m)%2)==0)
|
3442
|
+
-1
|
3443
|
+
else
|
3444
|
+
_round_half_up(i)
|
3445
|
+
end
|
3446
|
+
end
|
3447
|
+
|
3448
|
+
# Round up (not away from 0 if negative) to i digits
|
3449
|
+
def _round_ceiling(i)
|
3450
|
+
sign<0 ? _round_down(i) : -_round_down(i)
|
3451
|
+
end
|
3452
|
+
|
3453
|
+
# Round down (not toward 0 if negative) to i digits
|
3454
|
+
def _round_floor(i)
|
3455
|
+
sign>0 ? _round_down(i) : -_round_down(i)
|
3456
|
+
end
|
3457
|
+
|
3458
|
+
# Round down unless digit i-1 is 0 or 5
|
3459
|
+
def _round_up05(i)
|
3460
|
+
if ((@coeff/num_class.int_radix_power(i))%(num_class.radix/2))==0
|
3461
|
+
-_round_down(i)
|
3462
|
+
else
|
3463
|
+
_round_down(i)
|
3464
|
+
end
|
3465
|
+
end
|
3466
|
+
|
3467
|
+
# Compute a lower bound for the adjusted exponent of self.log10()
|
3468
|
+
# In other words, find r such that self.log10() >= 10**r.
|
3469
|
+
# Assumes that self is finite and positive and that self != 1.
|
3470
|
+
def _log_radix_exp_bound
|
3471
|
+
# For x >= radix or x < 1/radix we only need a bound on the integer
|
3472
|
+
# part of log_radix(self), and this comes directly from the
|
3473
|
+
# exponent of x. For 1/radix <= x <= radix we use the inequalities
|
3474
|
+
# 1-1/x <= log(x) <= x-1. If x > 1 we have |log_radix(x)| >
|
3475
|
+
# (1-1/x)/k > 0. If x < 1 then |log_radix(x)| > (1-x)/k > 0
|
3476
|
+
# with k = floor(log(radix)*radix**m)/radix**m (m = 3 for radix=10)
|
3477
|
+
#
|
3478
|
+
# The original Python cod used lexical order (having converted to strings) for (num < den) and (num < 231)
|
3479
|
+
# so the results would be different e.g. for num = 9; Can this happen? What is the correct way?
|
3480
|
+
|
3481
|
+
adj = self.exponent + number_of_digits - 1
|
3482
|
+
return _number_of_digits(adj) - 1 if adj >= 1 # self >= radix
|
3483
|
+
return _number_of_digits(-1-adj)-1 if adj <= -2 # self < 1/radix
|
3484
|
+
|
3485
|
+
k, m = {
|
3486
|
+
10 => [231, 3],
|
3487
|
+
2 => [89, 7]
|
3488
|
+
}[num_class.radix]
|
3489
|
+
raise InvalidOperation, "Base #{num_class.radix} not supported for _log_radix_exp_bound" if k.nil?
|
3490
|
+
|
3491
|
+
c = self.coefficient
|
3492
|
+
e = self.exponent
|
3493
|
+
if adj == 0
|
3494
|
+
# 1 < self < 10
|
3495
|
+
num = (c - num_class.int_radix_power(-e))
|
3496
|
+
den = (k*c)
|
3497
|
+
return _number_of_digits(num) - _number_of_digits(den) - ((num < den) ? 1 : 0) + (m-1)
|
3498
|
+
end
|
3499
|
+
# adj == -1, 0.1 <= self < 1
|
3500
|
+
num = (num_class.int_radix_power(-e)-c)
|
3501
|
+
return _number_of_digits(num.to_i) + e - ((num < k) ? 1 : 0) - (m-2)
|
3502
|
+
end
|
3503
|
+
|
3504
|
+
# Attempt to compute self**other exactly
|
3505
|
+
# Given Decimals self and other and an integer p, attempt to
|
3506
|
+
# compute an exact result for the power self**other, with p
|
3507
|
+
# digits of precision. Return nil if self**other is not
|
3508
|
+
# exactly representable in p digits.
|
3509
|
+
#
|
3510
|
+
# Assumes that elimination of special cases has already been
|
3511
|
+
# performed: self and other must both be nonspecial; self must
|
3512
|
+
# be positive and not numerically equal to 1; other must be
|
3513
|
+
# nonzero. For efficiency, other.exponent should not be too large,
|
3514
|
+
# so that 10**other.exponent.abs is a feasible calculation.
|
3515
|
+
def _power_exact(other, p)
|
3516
|
+
|
3517
|
+
# In the comments below, we write x for the value of self and
|
3518
|
+
# y for the value of other. Write x = xc*10**xe and y =
|
3519
|
+
# yc*10**ye.
|
3520
|
+
|
3521
|
+
# The main purpose of this method is to identify the *failure*
|
3522
|
+
# of x**y to be exactly representable with as little effort as
|
3523
|
+
# possible. So we look for cheap and easy tests that
|
3524
|
+
# eliminate the possibility of x**y being exact. Only if all
|
3525
|
+
# these tests are passed do we go on to actually compute x**y.
|
3526
|
+
|
3527
|
+
# Here's the main idea. First normalize both x and y. We
|
3528
|
+
# express y as a rational m/n, with m and n relatively prime
|
3529
|
+
# and n>0. Then for x**y to be exactly representable (at
|
3530
|
+
# *any* precision), xc must be the nth power of a positive
|
3531
|
+
# integer and xe must be divisible by n. If m is negative
|
3532
|
+
# then additionally xc must be a power of either 2 or 5, hence
|
3533
|
+
# a power of 2**n or 5**n.
|
3534
|
+
#
|
3535
|
+
# There's a limit to how small |y| can be: if y=m/n as above
|
3536
|
+
# then:
|
3537
|
+
#
|
3538
|
+
# (1) if xc != 1 then for the result to be representable we
|
3539
|
+
# need xc**(1/n) >= 2, and hence also xc**|y| >= 2. So
|
3540
|
+
# if |y| <= 1/nbits(xc) then xc < 2**nbits(xc) <=
|
3541
|
+
# 2**(1/|y|), hence xc**|y| < 2 and the result is not
|
3542
|
+
# representable.
|
3543
|
+
#
|
3544
|
+
# (2) if xe != 0, |xe|*(1/n) >= 1, so |xe|*|y| >= 1. Hence if
|
3545
|
+
# |y| < 1/|xe| then the result is not representable.
|
3546
|
+
#
|
3547
|
+
# Note that since x is not equal to 1, at least one of (1) and
|
3548
|
+
# (2) must apply. Now |y| < 1/nbits(xc) iff |yc|*nbits(xc) <
|
3549
|
+
# 10**-ye iff len(str(|yc|*nbits(xc)) <= -ye.
|
3550
|
+
#
|
3551
|
+
# There's also a limit to how large y can be, at least if it's
|
3552
|
+
# positive: the normalized result will have coefficient xc**y,
|
3553
|
+
# so if it's representable then xc**y < 10**p, and y <
|
3554
|
+
# p/log10(xc). Hence if y*log10(xc) >= p then the result is
|
3555
|
+
# not exactly representable.
|
3556
|
+
|
3557
|
+
# if len(str(abs(yc*xe)) <= -ye then abs(yc*xe) < 10**-ye,
|
3558
|
+
# so |y| < 1/xe and the result is not representable.
|
3559
|
+
# Similarly, len(str(abs(yc)*xc_bits)) <= -ye implies |y|
|
3560
|
+
# < 1/nbits(xc).
|
3561
|
+
|
3562
|
+
xc = self.coefficient
|
3563
|
+
xe = self.exponent
|
3564
|
+
while (xc % num_class.radix) == 0
|
3565
|
+
xc /= num_class.radix
|
3566
|
+
xe += 1
|
3567
|
+
end
|
3568
|
+
|
3569
|
+
yc = other.coefficient
|
3570
|
+
ye = other.exponent
|
3571
|
+
while (yc % num_class.radix) == 0
|
3572
|
+
yc /= num_class.radix
|
3573
|
+
ye += 1
|
3574
|
+
end
|
3575
|
+
|
3576
|
+
# case where xc == 1: result is 10**(xe*y), with xe*y
|
3577
|
+
# required to be an integer
|
3578
|
+
if xc == 1
|
3579
|
+
if ye >= 0
|
3580
|
+
exponent = xe*yc*num_class.int_radix_power(ye)
|
3581
|
+
else
|
3582
|
+
exponent, remainder = (xe*yc).divmod(num_class.int_radix_power(-ye))
|
3583
|
+
return nil if remainder!=0
|
3584
|
+
end
|
3585
|
+
exponent = -exponent if other.sign == -1
|
3586
|
+
# if other is a nonnegative integer, use ideal exponent
|
3587
|
+
if other.integral? and (other.sign == +1)
|
3588
|
+
ideal_exponent = self.exponent*other.to_i
|
3589
|
+
zeros = [exponent-ideal_exponent, p-1].min
|
3590
|
+
else
|
3591
|
+
zeros = 0
|
3592
|
+
end
|
3593
|
+
return Num(+1, num_class.int_radix_power(zeros), exponent-zeros)
|
3594
|
+
end
|
3595
|
+
|
3596
|
+
# case where y is negative: xc must be either a power
|
3597
|
+
# of 2 or a power of 5.
|
3598
|
+
if other.sign == -1
|
3599
|
+
# TODO: detect powers of 2 or 5
|
3600
|
+
return nil
|
3601
|
+
end
|
3602
|
+
|
3603
|
+
# now y is positive; find m and n such that y = m/n
|
3604
|
+
if ye >= 0
|
3605
|
+
m, n = num_class.int_mult_radix_power(yc,ye), 1
|
3606
|
+
else
|
3607
|
+
return nil if (xe != 0) and (_number_of_digits((yc*xe).abs) <= -ye)
|
3608
|
+
xc_bits = _nbits(xc)
|
3609
|
+
return nil if (xc != 1) and (_number_of_digits(yc.abs*xc_bits) <= -ye)
|
3610
|
+
m, n = yc, num_class.int_radix_power(-ye)
|
3611
|
+
while ((m % 2) == 0) && ((n % 2) == 0)
|
3612
|
+
m /= 2
|
3613
|
+
n /= 2
|
3614
|
+
end
|
3615
|
+
while ((m % 5) == 0) && ((n % 5) == 0)
|
3616
|
+
m /= 5
|
3617
|
+
n /= 5
|
3618
|
+
end
|
3619
|
+
end
|
3620
|
+
|
3621
|
+
# compute nth root of xc*radix**xe
|
3622
|
+
if n > 1
|
3623
|
+
# if 1 < xc < 2**n then xc isn't an nth power
|
3624
|
+
return nil if xc != 1 and xc_bits <= n
|
3625
|
+
|
3626
|
+
xe, rem = xe.divmod(n)
|
3627
|
+
return nil if rem != 0
|
3628
|
+
|
3629
|
+
# compute nth root of xc using Newton's method
|
3630
|
+
a = 1 << -(-_nbits(xc)/n) # initial estimate
|
3631
|
+
q = r = nil
|
3632
|
+
loop do
|
3633
|
+
q, r = xc.divmod(a**(n-1))
|
3634
|
+
break if a <= q
|
3635
|
+
a = (a*(n-1) + q)/n
|
3636
|
+
end
|
3637
|
+
return nil if !((a == q) and (r == 0))
|
3638
|
+
xc = a
|
3639
|
+
end
|
3640
|
+
|
3641
|
+
# now xc*radix**xe is the nth root of the original xc*radix**xe
|
3642
|
+
# compute mth power of xc*radix**xe
|
3643
|
+
|
3644
|
+
# if m > p*_log_radix_mult/_log_radix_lb(xc) then m > p/log_radix(xc),
|
3645
|
+
# hence xc**m > radix**p and the result is not representable.
|
3646
|
+
#return nil if (xc > 1) and (m > p*100/_log10_lb(xc))
|
3647
|
+
return nil if (xc > 1) and (m > p*_log_radix_mult/_log_radix_lb(xc))
|
3648
|
+
xc = xc**m
|
3649
|
+
xe *= m
|
3650
|
+
return nil if xc > num_class.int_radix_power(p)
|
3651
|
+
|
3652
|
+
# by this point the result *is* exactly representable
|
3653
|
+
# adjust the exponent to get as close as possible to the ideal
|
3654
|
+
# exponent, if necessary
|
3655
|
+
if other.integral? && other.sign == +1
|
3656
|
+
ideal_exponent = self.exponent*other.to_i
|
3657
|
+
zeros = [xe-ideal_exponent, p-_number_of_digits(xc)].min
|
3658
|
+
else
|
3659
|
+
zeros = 0
|
3660
|
+
end
|
3661
|
+
return Num(+1, num_class.int_mult_radix_power(xc, zeros), xe-zeros)
|
3662
|
+
end
|
3663
|
+
|
3664
|
+
module AuxiliarFunctions
|
3665
|
+
|
3666
|
+
module_function
|
3667
|
+
|
3668
|
+
# Convert a numeric value to decimal (internal use)
|
3669
|
+
def _convert(x, error=true)
|
3670
|
+
case x
|
3671
|
+
when num_class
|
3672
|
+
x
|
3673
|
+
when *num_class.context.coercible_types
|
3674
|
+
num_class.new(x)
|
3675
|
+
else
|
3676
|
+
raise TypeError, "Unable to convert #{x.class} to #{num_class}" if error
|
3677
|
+
nil
|
3678
|
+
end
|
3679
|
+
end
|
3680
|
+
|
3681
|
+
# Parse numeric text literals (internal use)
|
3682
|
+
def _parser(txt)
|
3683
|
+
md = /^\s*([-+])?(?:(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([-+]?\d+))?|Inf(?:inity)?|(s)?NaN(\d*))\s*$/i.match(txt)
|
3684
|
+
if md
|
3685
|
+
OpenStruct.new :sign=>md[1], :int=>md[2], :frac=>md[3], :onlyfrac=>md[4], :exp=>md[5],
|
3686
|
+
:signal=>md[6], :diag=>md[7]
|
3687
|
+
end
|
3688
|
+
end
|
3689
|
+
|
3690
|
+
# Normalizes op1, op2 to have the same exp and length of coefficient. Used for addition.
|
3691
|
+
def _normalize(op1, op2, prec=0)
|
3692
|
+
if op1.exponent < op2.exponent
|
3693
|
+
swap = true
|
3694
|
+
tmp,other = op2,op1
|
3695
|
+
else
|
3696
|
+
swap = false
|
3697
|
+
tmp,other = op1,op2
|
3698
|
+
end
|
3699
|
+
tmp_len = tmp.number_of_digits
|
3700
|
+
other_len = other.number_of_digits
|
3701
|
+
exp = tmp.exponent + [-1, tmp_len - prec - 2].min
|
3702
|
+
if (other_len+other.exponent-1 < exp) && prec>0
|
3703
|
+
other = num_class.new([other.sign, 1, exp])
|
3704
|
+
end
|
3705
|
+
tmp = Num(tmp.sign,
|
3706
|
+
num_class.int_mult_radix_power(tmp.coefficient, tmp.exponent-other.exponent),
|
3707
|
+
other.exponent)
|
3708
|
+
return swap ? [other, tmp] : [tmp, other]
|
3709
|
+
end
|
3710
|
+
|
3711
|
+
# Given integers xc, xe, yc and ye representing Num x = xc*radix**xe and
|
3712
|
+
# y = yc*radix**ye, compute x**y. Returns a pair of integers (c, e) such that:
|
3713
|
+
#
|
3714
|
+
# radix**(p-1) <= c <= radix**p, and
|
3715
|
+
# (c-1)*radix**e < x**y < (c+1)*radix**e
|
3716
|
+
#
|
3717
|
+
# in other words, c*radix**e is an approximation to x**y with p digits
|
3718
|
+
# of precision, and with an error in c of at most 1. (This is
|
3719
|
+
# almost, but not quite, the same as the error being < 1ulp: when c
|
3720
|
+
# == radix**(p-1) we can only guarantee error < radix ulp.)
|
3721
|
+
#
|
3722
|
+
# We assume that: x is positive and not equal to 1, and y is nonzero.
|
3723
|
+
def _power(xc, xe, yc, ye, p)
|
3724
|
+
# Find b such that radix**(b-1) <= |y| <= radix**b
|
3725
|
+
b = _number_of_digits(yc.abs) + ye
|
3726
|
+
|
3727
|
+
# log(x) = lxc*radix**(-p-b-1), to p+b+1 places after the decimal point
|
3728
|
+
lxc = _log(xc, xe, p+b+1)
|
3729
|
+
|
3730
|
+
# compute product y*log(x) = yc*lxc*radix**(-p-b-1+ye) = pc*radix**(-p-1)
|
3731
|
+
shift = ye-b
|
3732
|
+
if shift >= 0
|
3733
|
+
pc = lxc*yc*num_class.int_radix_power(shift)
|
3734
|
+
else
|
3735
|
+
pc = _div_nearest(lxc*yc, num_class.int_radix_power(-shift))
|
3736
|
+
end
|
3737
|
+
|
3738
|
+
if pc == 0
|
3739
|
+
# we prefer a result that isn't exactly 1; this makes it
|
3740
|
+
# easier to compute a correctly rounded result in __pow__
|
3741
|
+
if (_number_of_digits(xc) + xe >= 1) == (yc > 0) # if x**y > 1:
|
3742
|
+
coeff, exp = num_class.int_radix_power(p-1)+1, 1-p
|
3743
|
+
else
|
3744
|
+
coeff, exp = num_class.int_radix_power(p)-1, -p
|
3745
|
+
end
|
3746
|
+
else
|
3747
|
+
coeff, exp = _exp(pc, -(p+1), p+1)
|
3748
|
+
coeff = _div_nearest(coeff, num_class.radix)
|
3749
|
+
exp += 1
|
3750
|
+
end
|
3751
|
+
|
3752
|
+
return coeff, exp
|
3753
|
+
end
|
3754
|
+
|
3755
|
+
EXP_INC = 4
|
3756
|
+
# Compute an approximation to exp(c*radix**e), with p decimal places of precision.
|
3757
|
+
# Returns integers d, f such that:
|
3758
|
+
#
|
3759
|
+
# radix**(p-1) <= d <= radix**p, and
|
3760
|
+
# (d-1)*radix**f < exp(c*radix**e) < (d+1)*radix**f
|
3761
|
+
#
|
3762
|
+
# In other words, d*radix**f is an approximation to exp(c*radix**e) with p
|
3763
|
+
# digits of precision, and with an error in d of at most 1. This is
|
3764
|
+
# almost, but not quite, the same as the error being < 1ulp: when d
|
3765
|
+
# = radix**(p-1) the error could be up to radix ulp.
|
3766
|
+
def _exp(c, e, p)
|
3767
|
+
# we'll call iexp with M = radix**(p+2), giving p+3 digits of precision
|
3768
|
+
p += EXP_INC
|
3769
|
+
|
3770
|
+
# compute log(radix) with extra precision = adjusted exponent of c*radix**e
|
3771
|
+
# TODO: without the .abs tests fail because c is negative: c should not be negative!!
|
3772
|
+
extra = [0, e + _number_of_digits(c.abs) - 1].max
|
3773
|
+
q = p + extra
|
3774
|
+
|
3775
|
+
# compute quotient c*radix**e/(log(radix)) = c*radix**(e+q)/(log(radix)*radix**q),
|
3776
|
+
# rounding down
|
3777
|
+
shift = e+q
|
3778
|
+
if shift >= 0
|
3779
|
+
cshift = c*num_class.int_radix_power(shift)
|
3780
|
+
else
|
3781
|
+
cshift = c/num_class.int_radix_power(-shift)
|
3782
|
+
end
|
3783
|
+
quot, rem = cshift.divmod(_log_radix_digits(q))
|
3784
|
+
|
3785
|
+
# reduce remainder back to original precision
|
3786
|
+
rem = _div_nearest(rem, num_class.int_radix_power(extra))
|
3787
|
+
|
3788
|
+
# for radix=10: error in result of _iexp < 120; error after division < 0.62
|
3789
|
+
r = _div_nearest(_iexp(rem, num_class.int_radix_power(p)), num_class.int_radix_power(EXP_INC+1)), quot - p + (EXP_INC+1)
|
3790
|
+
return r
|
3791
|
+
end
|
3792
|
+
|
3793
|
+
LOG_PREC_INC = 4
|
3794
|
+
# Given integers c, e and p with c > 0, compute an integer
|
3795
|
+
# approximation to radix**p * log(c*radix**e), with an absolute error of
|
3796
|
+
# at most 1. Assumes that c*radix**e is not exactly 1.
|
3797
|
+
def _log(c, e, p)
|
3798
|
+
# Increase precision by 2. The precision increase is compensated
|
3799
|
+
# for at the end with a division
|
3800
|
+
p += LOG_PREC_INC
|
3801
|
+
|
3802
|
+
# rewrite c*radix**e as d*radix**f with either f >= 0 and 1 <= d <= radix,
|
3803
|
+
# or f <= 0 and 1/radix <= d <= 1. Then we can compute radix**p * log(c*radix**e)
|
3804
|
+
# as radix**p * log(d) + radix**p*f * log(radix).
|
3805
|
+
l = _number_of_digits(c)
|
3806
|
+
f = e+l - ((e+l >= 1) ? 1 : 0)
|
3807
|
+
|
3808
|
+
# compute approximation to radix**p*log(d), with error < 27 for radix=10
|
3809
|
+
if p > 0
|
3810
|
+
k = e+p-f
|
3811
|
+
if k >= 0
|
3812
|
+
c *= num_class.int_radix_power(k)
|
3813
|
+
else
|
3814
|
+
c = _div_nearest(c, num_class.int_radix_power(-k)) # error of <= 0.5 in c for radix=10
|
3815
|
+
end
|
3816
|
+
|
3817
|
+
# _ilog magnifies existing error in c by a factor of at most radix
|
3818
|
+
log_d = _ilog(c, num_class.int_radix_power(p)) # error < 5 + 22 = 27 for radix=10
|
3819
|
+
else
|
3820
|
+
# p <= 0: just approximate the whole thing by 0; error < 2.31 for radix=10
|
3821
|
+
log_d = 0
|
3822
|
+
end
|
3823
|
+
|
3824
|
+
# compute approximation to f*radix**p*log(radix), with error < 11 for radix=10.
|
3825
|
+
if f
|
3826
|
+
extra = _number_of_digits(f.abs) - 1
|
3827
|
+
if p + extra >= 0
|
3828
|
+
# for radix=10:
|
3829
|
+
# error in f * _log10_digits(p+extra) < |f| * 1 = |f|
|
3830
|
+
# after division, error < |f|/10**extra + 0.5 < 10 + 0.5 < 11
|
3831
|
+
f_log_r = _div_nearest(f*_log_radix_digits(p+extra), num_class.int_radix_power(extra))
|
3832
|
+
else
|
3833
|
+
f_log_r = 0
|
3834
|
+
end
|
3835
|
+
else
|
3836
|
+
f_log_r = 0
|
3837
|
+
end
|
3838
|
+
|
3839
|
+
# error in sum < 11+27 = 38; error after division < 0.38 + 0.5 < 1 for radix=10
|
3840
|
+
return _div_nearest(f_log_r + log_d, num_class.int_radix_power(LOG_PREC_INC)) # extra radix factor for base 2 ???
|
3841
|
+
end
|
3842
|
+
|
3843
|
+
# Given integers x and M, M > 0, such that x/M is small in absolute
|
3844
|
+
# value, compute an integer approximation to M*exp(x/M).
|
3845
|
+
# For redix=10, and 0 <= x/M <= 2.4, the absolute error in the result is bounded by 60 (and
|
3846
|
+
# is usually much smaller).
|
3847
|
+
def _iexp(x, m, l=8)
|
3848
|
+
|
3849
|
+
# Algorithm: to compute exp(z) for a real number z, first divide z
|
3850
|
+
# by a suitable power R of 2 so that |z/2**R| < 2**-L. Then
|
3851
|
+
# compute expm1(z/2**R) = exp(z/2**R) - 1 using the usual Taylor
|
3852
|
+
# series
|
3853
|
+
#
|
3854
|
+
# expm1(x) = x + x**2/2! + x**3/3! + ...
|
3855
|
+
#
|
3856
|
+
# Now use the identity
|
3857
|
+
#
|
3858
|
+
# expm1(2x) = expm1(x)*(expm1(x)+2)
|
3859
|
+
#
|
3860
|
+
# R times to compute the sequence expm1(z/2**R),
|
3861
|
+
# expm1(z/2**(R-1)), ... , exp(z/2), exp(z).
|
3862
|
+
|
3863
|
+
# Find R such that x/2**R/M <= 2**-L
|
3864
|
+
r = _nbits((x<<l)/m)
|
3865
|
+
|
3866
|
+
# Taylor series. (2**L)**T > M
|
3867
|
+
t = -(-num_class.radix*_number_of_digits(m)/(3*l)).to_i
|
3868
|
+
y = _div_nearest(x, t)
|
3869
|
+
mshift = m<<r
|
3870
|
+
(1...t).to_a.reverse.each do |i|
|
3871
|
+
y = _div_nearest(x*(mshift + y), mshift * i)
|
3872
|
+
end
|
3873
|
+
|
3874
|
+
# Expansion
|
3875
|
+
(0...r).to_a.reverse.each do |k|
|
3876
|
+
mshift = m<<(k+2)
|
3877
|
+
y = _div_nearest(y*(y+mshift), mshift)
|
3878
|
+
end
|
3879
|
+
|
3880
|
+
return m+y
|
3881
|
+
end
|
3882
|
+
|
3883
|
+
# Integer approximation to M*log(x/M), with absolute error boundable
|
3884
|
+
# in terms only of x/M.
|
3885
|
+
#
|
3886
|
+
# Given positive integers x and M, return an integer approximation to
|
3887
|
+
# M * log(x/M). For radix=10, L = 8 and 0.1 <= x/M <= 10 the difference
|
3888
|
+
# between the approximation and the exact result is at most 22. For
|
3889
|
+
# L = 8 and 1.0 <= x/M <= 10.0 the difference is at most 15. In
|
3890
|
+
# both cases these are upper bounds on the error; it will usually be
|
3891
|
+
# much smaller.
|
3892
|
+
def _ilog(x, m, l = 8)
|
3893
|
+
# The basic algorithm is the following: let log1p be the function
|
3894
|
+
# log1p(x) = log(1+x). Then log(x/M) = log1p((x-M)/M). We use
|
3895
|
+
# the reduction
|
3896
|
+
#
|
3897
|
+
# log1p(y) = 2*log1p(y/(1+sqrt(1+y)))
|
3898
|
+
#
|
3899
|
+
# repeatedly until the argument to log1p is small (< 2**-L in
|
3900
|
+
# absolute value). For small y we can use the Taylor series
|
3901
|
+
# expansion
|
3902
|
+
#
|
3903
|
+
# log1p(y) ~ y - y**2/2 + y**3/3 - ... - (-y)**T/T
|
3904
|
+
#
|
3905
|
+
# truncating at T such that y**T is small enough. The whole
|
3906
|
+
# computation is carried out in a form of fixed-point arithmetic,
|
3907
|
+
# with a real number z being represented by an integer
|
3908
|
+
# approximation to z*M. To avoid loss of precision, the y below
|
3909
|
+
# is actually an integer approximation to 2**R*y*M, where R is the
|
3910
|
+
# number of reductions performed so far.
|
3911
|
+
|
3912
|
+
y = x-m
|
3913
|
+
# argument reduction; R = number of reductions performed
|
3914
|
+
r = 0
|
3915
|
+
# while (r <= l && y.abs << l-r >= m ||
|
3916
|
+
# r > l and y.abs>> r-l >= m)
|
3917
|
+
while (((r <= l) && ((y.abs << (l-r)) >= m)) ||
|
3918
|
+
((r > l) && ((y.abs>>(r-l)) >= m)))
|
3919
|
+
y = _div_nearest((m*y) << 1,
|
3920
|
+
m + _sqrt_nearest(m*(m+_rshift_nearest(y, r)), m))
|
3921
|
+
r += 1
|
3922
|
+
end
|
3923
|
+
|
3924
|
+
# Taylor series with T terms
|
3925
|
+
t = -(-10*_number_of_digits(m)/(3*l)).to_i
|
3926
|
+
yshift = _rshift_nearest(y, r)
|
3927
|
+
w = _div_nearest(m, t)
|
3928
|
+
# (1...t).reverse_each do |k| # Ruby 1.9
|
3929
|
+
(1...t).to_a.reverse.each do |k|
|
3930
|
+
w = _div_nearest(m, k) - _div_nearest(yshift*w, m)
|
3931
|
+
end
|
3932
|
+
|
3933
|
+
return _div_nearest(w*y, m)
|
3934
|
+
end
|
3935
|
+
|
3936
|
+
# Closest integer to the square root of the positive integer n. a is
|
3937
|
+
# an initial approximation to the square root. Any positive integer
|
3938
|
+
# will do for a, but the closer a is to the square root of n the
|
3939
|
+
# faster convergence will be.
|
3940
|
+
def _sqrt_nearest(n, a)
|
3941
|
+
|
3942
|
+
if n <= 0 or a <= 0
|
3943
|
+
raise ArgumentError, "Both arguments to _sqrt_nearest should be positive."
|
3944
|
+
end
|
3945
|
+
|
3946
|
+
b=0
|
3947
|
+
while a != b
|
3948
|
+
b, a = a, a--n/a>>1 # ??
|
3949
|
+
end
|
3950
|
+
return a
|
3951
|
+
end
|
3952
|
+
|
3953
|
+
# Given an integer x and a nonnegative integer shift, return closest
|
3954
|
+
# integer to x / 2**shift; use round-to-even in case of a tie.
|
3955
|
+
def _rshift_nearest(x, shift)
|
3956
|
+
b, q = (1 << shift), (x >> shift)
|
3957
|
+
return q + (((2*(x & (b-1)) + (q&1)) > b) ? 1 : 0)
|
3958
|
+
#return q + (2*(x & (b-1)) + (((q&1) > b) ? 1 : 0))
|
3959
|
+
end
|
3960
|
+
|
3961
|
+
# Closest integer to a/b, a and b positive integers; rounds to even
|
3962
|
+
# in the case of a tie.
|
3963
|
+
def _div_nearest(a, b)
|
3964
|
+
q, r = a.divmod(b)
|
3965
|
+
q + (((2*r + (q&1)) > b) ? 1 : 0)
|
3966
|
+
end
|
3967
|
+
|
3968
|
+
# We'll memoize the digits of log(10):
|
3969
|
+
@log_radix_digits = {
|
3970
|
+
# 10=>"23025850929940456840179914546843642076011014886",
|
3971
|
+
2=>""
|
3972
|
+
}
|
3973
|
+
class <<self
|
3974
|
+
attr_reader :log_radix_digits
|
3975
|
+
end
|
3976
|
+
LOG_RADIX_INC = 2
|
3977
|
+
LOG_RADIX_EXTRA = 3
|
3978
|
+
|
3979
|
+
# Given an integer p >= 0, return floor(radix**p)*log(radix).
|
3980
|
+
def _log_radix_digits(p)
|
3981
|
+
# digits are stored as a string, for quick conversion to
|
3982
|
+
# integer in the case that we've already computed enough
|
3983
|
+
# digits; the stored digits should always bge correct
|
3984
|
+
# (truncated, not rounded to nearest).
|
3985
|
+
raise ArgumentError, "p should be nonnegative" if p<0
|
3986
|
+
stored_digits = (AuxiliarFunctions.log_radix_digits[num_class.radix] || "")
|
3987
|
+
if p >= stored_digits.length
|
3988
|
+
digits = nil
|
3989
|
+
# compute p+3, p+6, p+9, ... digits; continue until at
|
3990
|
+
# least one of the extra digits is nonzero
|
3991
|
+
extra = LOG_RADIX_EXTRA
|
3992
|
+
loop do
|
3993
|
+
# compute p+extra digits, correct to within 1ulp
|
3994
|
+
m = num_class.int_radix_power(p+extra+LOG_RADIX_INC)
|
3995
|
+
digits = _div_nearest(_ilog(num_class.radix*m, m), num_class.int_radix_power(LOG_RADIX_INC)).to_s(num_class.radix)
|
3996
|
+
break if digits[-extra..-1] != '0'*extra
|
3997
|
+
extra += LOG_RADIX_EXTRA
|
3998
|
+
end
|
3999
|
+
# if the radix < e (i.e. only for radix==2), we must prefix with a 0 because log(radix)<1
|
4000
|
+
# BUT THIS REDUCES PRECISION BY ONE? : may be avoid prefix and adjust scaling in the caller
|
4001
|
+
prefix = num_class.radix==2 ? '0' : ''
|
4002
|
+
# keep all reliable digits so far; remove trailing zeros
|
4003
|
+
# and next nonzero digit
|
4004
|
+
AuxiliarFunctions.log_radix_digits[num_class.radix] = prefix + digits.sub(/0*$/,'')[0...-1]
|
4005
|
+
end
|
4006
|
+
return (AuxiliarFunctions.log_radix_digits[num_class.radix][0..p]).to_i(num_class.radix)
|
4007
|
+
end
|
4008
|
+
|
4009
|
+
LOG2_MULT = 100 # TODO: K=100? K=64? ...
|
4010
|
+
LOG2_LB_CORRECTION = [ # (1..15).map{|i| (LOG2_MULT*Math.log(16.0/i)/Math.log(2)).ceil}
|
4011
|
+
400, 300, 242, 200, 168, 142, 120, 100, 84, 68, 55, 42, 30, 20, 10
|
4012
|
+
# for LOG2_MULT=64: 256, 192, 155, 128, 108, 91, 77, 64, 54, 44, 35, 27, 20, 13, 6
|
4013
|
+
]
|
4014
|
+
# Compute a lower bound for LOG2_MULT*log10(c) for a positive integer c.
|
4015
|
+
def log2_lb(c)
|
4016
|
+
raise ArgumentError, "The argument to _log2_lb should be nonnegative." if c <= 0
|
4017
|
+
str_c = c.to_s(16)
|
4018
|
+
return LOG2_MULT*4*str_c.length - LOG2_LB_CORRECTION[str_c[0,1].to_i(16)]
|
4019
|
+
end
|
4020
|
+
|
4021
|
+
LOG10_MULT = 100
|
4022
|
+
LOG10_LB_CORRECTION = { # (1..9).map_hash{|i| LOG10_MULT - (LOG10_MULT*Math.log10(i)).floor}
|
4023
|
+
'1'=> 100, '2'=> 70, '3'=> 53, '4'=> 40, '5'=> 31,
|
4024
|
+
'6'=> 23, '7'=> 16, '8'=> 10, '9'=> 5
|
4025
|
+
}
|
4026
|
+
# Compute a lower bound for LOG10_MULT*log10(c) for a positive integer c.
|
4027
|
+
def log10_lb(c)
|
4028
|
+
raise ArgumentError, "The argument to _log10_lb should be nonnegative." if c <= 0
|
4029
|
+
str_c = c.to_s
|
4030
|
+
return LOG10_MULT*str_c.length - LOG10_LB_CORRECTION[str_c[0,1]]
|
4031
|
+
end
|
4032
|
+
|
4033
|
+
def _log_radix_mult
|
4034
|
+
case num_class.radix
|
4035
|
+
when 10
|
4036
|
+
LOG10_MULT
|
4037
|
+
when 2
|
4038
|
+
LOG2_MULT
|
4039
|
+
else
|
4040
|
+
raise ArgumentError, "_log_radix_mult not implemented for base #{num_class.radix}"
|
4041
|
+
end
|
4042
|
+
end
|
4043
|
+
|
4044
|
+
def _log_radix_lb(c)
|
4045
|
+
case num_class.radix
|
4046
|
+
when 10
|
4047
|
+
log10_lb(c)
|
4048
|
+
when 2
|
4049
|
+
log2_lb(c)
|
4050
|
+
else
|
4051
|
+
raise ArgumentError, "_log_radix_lb not implemented for base #{num_class.radix}"
|
4052
|
+
end
|
4053
|
+
end
|
4054
|
+
|
4055
|
+
def _number_of_digits(v)
|
4056
|
+
_ndigits(v, num_class.radix)
|
4057
|
+
end
|
4058
|
+
|
4059
|
+
end # AuxiliarFunctions
|
4060
|
+
|
4061
|
+
include AuxiliarFunctions
|
4062
|
+
extend AuxiliarFunctions
|
4063
|
+
|
4064
|
+
class <<self
|
4065
|
+
# Num[base] can be use to obtain a floating-point numeric class with radix base, so that, for example,
|
4066
|
+
# Num[2] is equivalent to BinNum and Num[10] to DecNum.
|
4067
|
+
#
|
4068
|
+
# If the base does not correspond to one of the predefined classes (DecNum, BinNum), a new class
|
4069
|
+
# is dynamically generated.
|
4070
|
+
def [](base)
|
4071
|
+
case base
|
4072
|
+
when 10
|
4073
|
+
DecNum
|
4074
|
+
when 2
|
4075
|
+
BinNum
|
4076
|
+
else
|
4077
|
+
class_name = "Base#{base}Num"
|
4078
|
+
unless Flt.const_defined?(class_name)
|
4079
|
+
cls = Flt.const_set class_name, Class.new(Num) {
|
4080
|
+
def initialize(*args)
|
4081
|
+
super(*args)
|
4082
|
+
end
|
4083
|
+
}
|
4084
|
+
meta_cls = class <<cls;self;end
|
4085
|
+
meta_cls.send :define_method, :radix do
|
4086
|
+
base
|
4087
|
+
end
|
4088
|
+
|
4089
|
+
cls.const_set :Context, Class.new(Num::ContextBase)
|
4090
|
+
cls::Context.send :define_method, :initialize do |*options|
|
4091
|
+
super(cls, *options)
|
4092
|
+
end
|
4093
|
+
|
4094
|
+
default_digits = 10
|
4095
|
+
default_elimit = 100
|
4096
|
+
|
4097
|
+
cls.const_set :DefaultContext, cls::Context.new(
|
4098
|
+
:exact=>false, :precision=>default_digits, :rounding=>:half_even,
|
4099
|
+
:elimit=>default_elimit,
|
4100
|
+
:flags=>[],
|
4101
|
+
:traps=>[DivisionByZero, Overflow, InvalidOperation],
|
4102
|
+
:ignored_flags=>[],
|
4103
|
+
:capitals=>true,
|
4104
|
+
:clamp=>true
|
4105
|
+
)
|
4106
|
+
|
4107
|
+
end
|
4108
|
+
Flt.const_get class_name
|
4109
|
+
|
4110
|
+
end
|
4111
|
+
end
|
4112
|
+
end
|
4113
|
+
|
4114
|
+
# Exact base conversion: preserve x value.
|
4115
|
+
#
|
4116
|
+
# Convert x to a Flt::Num of the specified base or class
|
4117
|
+
# If the dest_context is exact, this may raise the Inexact flag (and return NaN), for some cases
|
4118
|
+
# (e.g. converting DecNum('0.1') to BinNum)
|
4119
|
+
#
|
4120
|
+
# The current destination context (overriden by dest_context) determines the valid range and the precision
|
4121
|
+
# (if its is not :exact the result will be rounded)
|
4122
|
+
def self.convert_exact(x, dest_base_or_class, dest_context=nil)
|
4123
|
+
num_class = dest_base_or_class.is_a?(Integer) ? Num[dest_base_or_class] : dest_base_or_class
|
4124
|
+
if x.special?
|
4125
|
+
if x.nan?
|
4126
|
+
num_class.nan
|
4127
|
+
else # x.infinite?
|
4128
|
+
num_class.infinity(x.sign)
|
4129
|
+
end
|
4130
|
+
elsif x.zero?
|
4131
|
+
num_class.zero(x.sign)
|
4132
|
+
else
|
4133
|
+
if dest_base_or_class == Float
|
4134
|
+
float = true
|
4135
|
+
num_class = BinNum
|
4136
|
+
dest_context = BinNum::FloatContext
|
4137
|
+
end
|
4138
|
+
y = num_class.context(dest_context) do
|
4139
|
+
sign, coeff, exp = x.split
|
4140
|
+
y = num_class.Num(sign*coeff)
|
4141
|
+
if exp < 0
|
4142
|
+
y /= x.num_class.int_radix_power(-exp)
|
4143
|
+
else
|
4144
|
+
y *= x.num_class.int_radix_power(exp)
|
4145
|
+
end
|
4146
|
+
# y.reduce
|
4147
|
+
end
|
4148
|
+
y = y.to_f if float
|
4149
|
+
y
|
4150
|
+
end
|
4151
|
+
end
|
4152
|
+
|
4153
|
+
# Approximate base conversion.
|
4154
|
+
#
|
4155
|
+
# Convert x to another Flt::Num class, so that if the result is converted to back to
|
4156
|
+
# the original class with the same precision and rounding mode, the value is preserved,
|
4157
|
+
# but use as few decimal digits as possible.
|
4158
|
+
#
|
4159
|
+
# Optional parameters: a context and/or an options hash can be passed.
|
4160
|
+
#
|
4161
|
+
# The context should be a context for the type of x, and is used to specified the precision and rounding mode
|
4162
|
+
# requiered to restore the original value from the converted value.
|
4163
|
+
#
|
4164
|
+
# The options are:
|
4165
|
+
# * :rounding used to specify the rounding required for back conversion with precedence over the context;
|
4166
|
+
# the value :nearest means any round-to-nearest.
|
4167
|
+
# * :all_digits to preserve the input precision by using all significant digits in the output, not
|
4168
|
+
# just the minimum required
|
4169
|
+
# * :minimum_precision to specify a minimum for the precision
|
4170
|
+
#
|
4171
|
+
# To increment the result number of digits x can be normalized or its precision (quantum) changed,
|
4172
|
+
# or use the :minimum_precision option.
|
4173
|
+
def self.convert(x, dest_base_or_class, *args)
|
4174
|
+
origin_context = args.shift if args.first.is_a?(ContextBase)
|
4175
|
+
raise ArgumentError,"Invalid parameters for Num.convert" unless args.size<=1 && (args.empty? || args.first.is_a?(Hash))
|
4176
|
+
options = args.first || {}
|
4177
|
+
|
4178
|
+
rounding = options[:rounding]
|
4179
|
+
all_digits = options[:all_digits] # :all_digits ? :shortest/:significative
|
4180
|
+
minimum_precision = options[:minimum_precision]
|
4181
|
+
|
4182
|
+
num_class = dest_base_or_class.is_a?(Integer) ? Num[dest_base_or_class] : dest_base_or_class
|
4183
|
+
if x.special?
|
4184
|
+
if x.nan?
|
4185
|
+
num_class.nan
|
4186
|
+
else # x.infinite?
|
4187
|
+
num_class.infinite(x.sign)
|
4188
|
+
end
|
4189
|
+
elsif x.zero?
|
4190
|
+
num_class.zero(x.sign)
|
4191
|
+
else
|
4192
|
+
context = x.num_class.define_context(origin_context)
|
4193
|
+
|
4194
|
+
p = x.number_of_digits
|
4195
|
+
p = minimum_precision if minimum_precision && p<minimum_precision
|
4196
|
+
s,f,e = x.split
|
4197
|
+
rounding ||= context.rounding unless
|
4198
|
+
formatter = Flt::Support::Formatter.new(x.num_class.radix, num_class.context.etiny, num_class.radix)
|
4199
|
+
formatter.format(x, f, e, rounding, p, all_digits)
|
4200
|
+
dec_pos,digits = formatter.adjusted_digits(rounding)
|
4201
|
+
|
4202
|
+
# f = digits.map{|d| d.to_s(num_class.radix)}.join.to_i(num_class.radix)
|
4203
|
+
f = digits.inject(0){|a,b| a*num_class.radix + b}
|
4204
|
+
e = dec_pos - digits.size
|
4205
|
+
num_class.Num(s, f, e)
|
4206
|
+
end
|
4207
|
+
end
|
4208
|
+
|
4209
|
+
end # Num
|
4210
|
+
|
4211
|
+
end # Flt
|