long-decimal 0.00.14 → 0.00.15
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/README +6 -5
- data/VERSION +1 -1
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.html +6 -6
- data/doc/classes/LongDecimalRoundingMode.html +3 -2
- data/doc/classes/LongMath.html +137 -191
- data/doc/created.rid +1 -1
- data/doc/dot/f_0.dot +44 -44
- data/doc/dot/f_0.png +0 -0
- data/doc/dot/m_0_0.dot +7 -50
- data/doc/dot/m_0_0.png +0 -0
- data/doc/files/lib/long-decimal_rb.html +58 -6
- data/doc/fr_class_index.html +3 -3
- data/doc/fr_method_index.html +136 -135
- data/lib/long-decimal.rb +1658 -1601
- data/test/testlongdecimal.rb +317 -12
- metadata +2 -2
data/lib/long-decimal.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#
|
2
2
|
# long-decimal.rb -- Arbitrary precision decimals with fixed decimal point
|
3
3
|
#
|
4
|
-
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.
|
5
|
-
# CVS-Label: $Name:
|
4
|
+
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.6 2006/03/20 21:38:32 bk1 Exp $
|
5
|
+
# CVS-Label: $Name: PRE_ALPHA_0_15 $
|
6
6
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
7
7
|
#
|
8
8
|
require "complex"
|
@@ -53,1553 +53,1322 @@ module LongDecimalRoundingMode
|
|
53
53
|
end # LongDecimalRoundingMode
|
54
54
|
|
55
55
|
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
# In addition LongMath provides methods like those in Math, but for
|
60
|
-
# LongDecimal instead of Float.
|
56
|
+
# class for holding fixed point long decimal numbers
|
57
|
+
# these can be considered as a pair of two integer. One contains the
|
58
|
+
# digits and the other one the position of the decimal point.
|
61
59
|
#
|
62
|
-
|
60
|
+
class LongDecimal < Numeric
|
61
|
+
@RCS_ID='-$Id: long-decimal.rb,v 1.6 2006/03/20 21:38:32 bk1 Exp $-'
|
63
62
|
|
64
63
|
include LongDecimalRoundingMode
|
65
64
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
# MINUS_ONE = LongDecimal(-1)
|
66
|
+
# ZERO = LongDecimal(0)
|
67
|
+
# ONE = LongDecimal(1)
|
68
|
+
# TWO = LongDecimal(2)
|
69
|
+
# TEN = LongDecimal(10)
|
70
70
|
|
71
71
|
#
|
72
|
-
#
|
73
|
-
#
|
72
|
+
# initialization
|
73
|
+
# parameters:
|
74
|
+
# 1. LongDecimal.new!(x) where x is a string or a number
|
75
|
+
# the resulting LongDecimal holds the number x, possibly rounded
|
76
|
+
# 2. LongDecimal.new!(x, s) where x is a string or a number and s is the scale
|
77
|
+
# the resulting LongDecimal holds the number x / 10**s
|
74
78
|
#
|
75
|
-
def
|
76
|
-
|
77
|
-
word_len
|
79
|
+
def LongDecimal.new!(x, s = 0)
|
80
|
+
new(x, s)
|
78
81
|
end
|
79
82
|
|
80
83
|
#
|
81
|
-
#
|
84
|
+
# creates a LongDecimal representing zero with the given number of
|
85
|
+
# digits after the decimal point (scale=s)
|
82
86
|
#
|
83
|
-
def
|
84
|
-
|
87
|
+
def LongDecimal.zero!(s = 0)
|
88
|
+
new(0, s)
|
85
89
|
end
|
86
90
|
|
87
|
-
#
|
88
|
-
# helper method for internal use: checks if parameter x is a LongDecimal
|
89
|
-
#
|
90
|
-
def LongMath.check_is_ld(x, name="x")
|
91
|
-
raise TypeError, "x=#{x.inspect} must be LongDecimal" unless x.kind_of? LongDecimal
|
92
|
-
end
|
93
91
|
|
94
92
|
#
|
95
|
-
#
|
96
|
-
#
|
93
|
+
# creates a LongDecimal representing one with the given number of
|
94
|
+
# digits after the decimal point (scale=s)
|
97
95
|
#
|
98
|
-
def
|
99
|
-
|
100
|
-
raise TypeError, "#{name}=#{prec.inspect} must be >= 0" unless prec >= 0
|
96
|
+
def LongDecimal.one!(s = 0)
|
97
|
+
new(10**s, s)
|
101
98
|
end
|
102
99
|
|
100
|
+
|
103
101
|
#
|
104
|
-
#
|
105
|
-
#
|
102
|
+
# creates a LongDecimal representing two with the given number of
|
103
|
+
# digits after the decimal point (scale=s)
|
106
104
|
#
|
107
|
-
def
|
108
|
-
|
105
|
+
def LongDecimal.two!(s = 0)
|
106
|
+
new(2*10**s, s)
|
109
107
|
end
|
110
108
|
|
109
|
+
|
111
110
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
# (the opposite of merge_from_words)
|
111
|
+
# creates a LongDecimal representing ten with the given number of
|
112
|
+
# digits after the decimal point (scale=s)
|
115
113
|
#
|
116
|
-
def
|
117
|
-
|
118
|
-
check_is_int(x, "x")
|
119
|
-
m = x.abs
|
120
|
-
s = (x <=> 0)
|
121
|
-
bit_pattern = (1 << word_len) - 1
|
122
|
-
words = []
|
123
|
-
while (m != 0 || words.length == 0) do
|
124
|
-
w = m & bit_pattern
|
125
|
-
m = m >> word_len
|
126
|
-
words.unshift(w)
|
127
|
-
end
|
128
|
-
if (s < 0) then
|
129
|
-
words[0] = -words[0]
|
130
|
-
end
|
131
|
-
words
|
114
|
+
def LongDecimal.ten!(s = 0)
|
115
|
+
new(10**(s+1), s)
|
132
116
|
end
|
133
117
|
|
118
|
+
|
134
119
|
#
|
135
|
-
#
|
136
|
-
#
|
120
|
+
# creates a LongDecimal representing minus one with the given number of
|
121
|
+
# digits after the decimal point (scale=s)
|
137
122
|
#
|
138
|
-
def
|
139
|
-
|
140
|
-
raise TypeError, "words must be array of length > 0" unless (words.kind_of? Array) && words.length > 0
|
141
|
-
y = 0
|
142
|
-
s = (words[0] <=> 0)
|
143
|
-
if (s < 0) then
|
144
|
-
words[0] = -words[0]
|
145
|
-
end
|
146
|
-
words.each do |w|
|
147
|
-
y = y << word_len
|
148
|
-
y += w
|
149
|
-
end
|
150
|
-
if (s < 0) then
|
151
|
-
y = -y
|
152
|
-
end
|
153
|
-
y
|
123
|
+
def LongDecimal.minus_one!(s = 0)
|
124
|
+
new(-1*10**s, s)
|
154
125
|
end
|
155
126
|
|
156
|
-
#
|
157
127
|
|
158
|
-
# calculate the square root of an integer x using bitwise algorithm
|
159
|
-
# the result is rounded to an integer y such that
|
160
|
-
# y**2�<=�x�<�(y+1)**2
|
161
128
|
#
|
162
|
-
|
163
|
-
|
164
|
-
|
129
|
+
# creates a LongDecimal representing a power of ten with the given
|
130
|
+
# exponent e and with the given number of digits after the decimal
|
131
|
+
# point (scale=s)
|
132
|
+
#
|
133
|
+
def LongDecimal.power_of_ten!(e, s = 0)
|
134
|
+
LongMath.check_is_int(e, "e")
|
135
|
+
raise TypeError, "negative 1st arg \"#{e.inspect}\"" if e < 0
|
136
|
+
new(10**(s+e), s)
|
165
137
|
end
|
166
138
|
|
139
|
+
|
167
140
|
#
|
168
|
-
|
169
|
-
|
170
|
-
#
|
171
|
-
#
|
141
|
+
# initialization
|
142
|
+
# parameters:
|
143
|
+
# LongDecimal.new(x, s) where x is a string or a number and s is the scale
|
144
|
+
# the resulting LongDecimal holds the number x / 10**s
|
172
145
|
#
|
173
|
-
def
|
174
|
-
check_is_int(x, "x")
|
146
|
+
def initialize(x, s)
|
175
147
|
|
176
|
-
|
177
|
-
if (
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
return [ Complex(0, a[0]), a[1]]
|
182
|
-
end
|
148
|
+
# handle some obvious errors with x first
|
149
|
+
raise TypeError, "non numeric 1st arg \"#{x.inspect}\"" if ! (x.kind_of? Numeric) && ! (x.kind_of? String)
|
150
|
+
# we could maybe even work with complex number, if their imaginary part is zero.
|
151
|
+
# but this is not so important to deal with, so we raise an error anyway.
|
152
|
+
raise TypeError, "complex numbers not supported \"#{x.inspect}\"" if x.kind_of? Complex
|
183
153
|
|
184
|
-
|
185
|
-
|
186
|
-
|
154
|
+
# handle some obvious errors with optional second parameter, if present
|
155
|
+
raise TypeError, "non integer 2nd arg \"#{s.inspect}\"" if ! s.kind_of? Integer
|
156
|
+
raise TypeError, "negative 2nd arg \"#{s.inspect}\"" if s < 0
|
187
157
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
b = 0
|
193
|
-
if (r >= 0) then
|
194
|
-
b = 1
|
195
|
-
xi = r
|
196
|
-
end
|
197
|
-
yi = (yi << 1) + b
|
198
|
-
end
|
199
|
-
return [yi, xi]
|
200
|
-
end
|
158
|
+
# scale is the second parameter or 0 if it is missing
|
159
|
+
scale = s
|
160
|
+
# int_val is the integral value that is multiplied by some 10**-n
|
161
|
+
int_val = 0
|
201
162
|
|
202
|
-
|
163
|
+
if x.kind_of? Integer then
|
164
|
+
# integers are trivial to handle
|
165
|
+
int_val = x
|
203
166
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
167
|
+
elsif x.kind_of? Rational then
|
168
|
+
# rationals are rounded somehow
|
169
|
+
# we need to come up with a better rule here.
|
170
|
+
# if denominator is any product of powers of 2 and 5, we do not need to round
|
171
|
+
denom = x.denominator
|
172
|
+
mul_2 = LongMath.multiplicity_of_factor(denom, 2)
|
173
|
+
mul_5 = LongMath.multiplicity_of_factor(denom, 5)
|
174
|
+
iscale = [mul_2, mul_5].max
|
175
|
+
scale += iscale
|
176
|
+
denom /= 2 ** mul_2
|
177
|
+
denom /= 5 ** mul_5
|
178
|
+
iscale2 = Math.log10(denom).ceil
|
179
|
+
scale += iscale2
|
180
|
+
# int_val = (x * 10 ** scale).to_i
|
181
|
+
int_val = (x * 10 ** (iscale2+iscale)).to_i
|
216
182
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
def LongMath.sqrtw_with_remainder(x, n = 16)
|
226
|
-
check_is_int(x, "x")
|
227
|
-
check_is_int(n, "n")
|
228
|
-
n2 = n<<1
|
229
|
-
n1 = n+1
|
230
|
-
check_word_len(n2, "2*n")
|
183
|
+
else
|
184
|
+
# we assume a string or a floating point number
|
185
|
+
# floating point number or BigDecimal is converted to string, so
|
186
|
+
# we only deal with strings
|
187
|
+
# this operation is not so common, so there is no urgent need to
|
188
|
+
# optimize it
|
189
|
+
num_str = x.to_s
|
190
|
+
len = num_str.length
|
231
191
|
|
232
|
-
|
233
|
-
|
234
|
-
return [0, 0]
|
235
|
-
elsif (s < 0)
|
236
|
-
a = sqrtw_with_remainder(-x)
|
237
|
-
return [ Complex(0, a[0]), a[1]]
|
238
|
-
end
|
192
|
+
# handle the obvious error that string is empty
|
193
|
+
raise TypeError, "1st arg must not be empty string. \"#{num_str.inspect}\"" if len == 0
|
239
194
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
end
|
195
|
+
# remove spaces and underscores
|
196
|
+
num_str.gsub! /\s/, ""
|
197
|
+
num_str.gsub! /_/, ""
|
244
198
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
end
|
199
|
+
# handle sign
|
200
|
+
num_str.gsub! /^\+/, ""
|
201
|
+
negative = false
|
202
|
+
if num_str.gsub! /^-/, "" then
|
203
|
+
negative = true
|
204
|
+
end
|
252
205
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
if (r < 0) then
|
267
|
-
was_negative = true
|
268
|
-
q = q-1
|
269
|
-
else
|
270
|
-
q = q+1
|
271
|
-
end
|
272
|
-
j += 1
|
273
|
-
if (j > 10) then
|
274
|
-
# puts("i=#{i} j=#{j} q=#{q} q0=#{q0} d0=#{d0} d=#{d} r=#{r} yi=#{yi} xi=#{xi}\n")
|
275
|
-
break
|
276
|
-
end
|
206
|
+
# split in parts before and after decimal point
|
207
|
+
num_arr = num_str.split /\./
|
208
|
+
if num_arr.length > 2 then
|
209
|
+
raise TypeError, "1st arg contains more than one . \"#{num_str.inspect}\""
|
210
|
+
end
|
211
|
+
num_int = num_arr[0]
|
212
|
+
num_rem = num_arr[1]
|
213
|
+
num_frac = nil
|
214
|
+
num_exp = nil
|
215
|
+
unless num_rem.nil? then
|
216
|
+
num_arr = num_rem.split /[Ee]/
|
217
|
+
num_frac = num_arr[0]
|
218
|
+
num_exp = num_arr[1]
|
277
219
|
end
|
278
|
-
xi = r
|
279
|
-
yi = (yi << n) + q
|
280
|
-
end
|
281
|
-
return [ yi, xi ]
|
282
|
-
end
|
283
220
|
|
284
|
-
|
221
|
+
if num_frac.nil? then
|
222
|
+
num_frac = ""
|
223
|
+
end
|
285
224
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
exponent = 1
|
297
|
-
b = b.abs
|
298
|
-
if (b < s && s < MAX_FLOATABLE)
|
299
|
-
exponent = (Math.log(s) / Math.log(b)).ceil
|
225
|
+
if num_exp.nil? || num_exp.empty? then
|
226
|
+
num_exp = "0"
|
227
|
+
end
|
228
|
+
num_exp = num_exp.to_i
|
229
|
+
iscale = num_frac.length - num_exp
|
230
|
+
scale += iscale
|
231
|
+
int_val = (num_int + num_frac).to_i
|
232
|
+
if negative then
|
233
|
+
int_val = -int_val
|
234
|
+
end
|
300
235
|
end
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end while f > 1
|
308
|
-
result
|
309
|
-
end
|
236
|
+
@scale = scale
|
237
|
+
@int_val = int_val
|
238
|
+
|
239
|
+
end # initialize
|
240
|
+
|
241
|
+
attr_reader :int_val, :scale
|
310
242
|
|
311
243
|
#
|
312
|
-
#
|
313
|
-
# the Integer x. Only works for prime numbers p (parameter prime_number).
|
314
|
-
# The caller has to make sure that p (parameter prime_number) is
|
315
|
-
# actually a prime number, because checks for primality actually cost
|
316
|
-
# something and should not be duplicated more than necessary.
|
317
|
-
# This method works even for numbers x that exceed the range of Float
|
244
|
+
# alter scale (changes self)
|
318
245
|
#
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
246
|
+
# only for internal use:
|
247
|
+
# use round_to_scale instead
|
248
|
+
#
|
249
|
+
def scale=(s)
|
250
|
+
raise TypeError, "non integer arg \"#{s.inspect}\"" if ! s.kind_of? Integer
|
251
|
+
raise TypeError, "negative arg \"#{s.inspect}\"" if s < 0
|
325
252
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
253
|
+
# do not work too hard, if scale does not really change.
|
254
|
+
unless @scale == s then
|
255
|
+
# multiply int_val by a power of 10 in order to compensate for
|
256
|
+
# the change of scale and to keep number in the same order of magnitude.
|
257
|
+
d = s - @scale
|
258
|
+
f = 10 ** (d.abs)
|
259
|
+
if (d >= 0) then
|
260
|
+
@int_val = (@int_val * f).to_i
|
330
261
|
else
|
331
|
-
|
262
|
+
# here we actually do rounding
|
263
|
+
@int_val = (@int_val / f).to_i
|
332
264
|
end
|
265
|
+
@scale = s
|
266
|
+
end
|
267
|
+
end
|
333
268
|
|
334
|
-
|
269
|
+
protected :scale=
|
335
270
|
|
336
|
-
|
337
|
-
|
338
|
-
|
271
|
+
#
|
272
|
+
# create copy of self with different scale
|
273
|
+
# param1: new_scale new scale for result
|
274
|
+
# param2: mode rounding mode to be applied when information is
|
275
|
+
# lost. defaults to ROUND_UNNECESSARY, which
|
276
|
+
# means that an exception is thrown if rounding
|
277
|
+
# would actually loose any information.
|
278
|
+
#
|
279
|
+
def round_to_scale(new_scale, mode = ROUND_UNNECESSARY)
|
280
|
+
|
281
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
282
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
283
|
+
raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
|
284
|
+
if @scale == new_scale then
|
285
|
+
self
|
286
|
+
else
|
287
|
+
diff = new_scale - scale
|
288
|
+
factor = 10 ** (diff.abs)
|
289
|
+
if (diff > 0) then
|
290
|
+
# we become more precise, no rounding issues
|
291
|
+
new_int_val = int_val * factor
|
339
292
|
else
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
293
|
+
quot, rem = int_val.divmod(factor)
|
294
|
+
if (rem == 0) then
|
295
|
+
new_int_val = quot
|
296
|
+
elsif (mode == ROUND_UNNECESSARY) then
|
297
|
+
raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
|
298
|
+
else
|
299
|
+
return LongDecimalQuot(self, LongDecimal(1)).round_to_scale(new_scale, mode)
|
346
300
|
end
|
347
|
-
result += (Math.log(power) / Math.log(prime_number)).round
|
348
301
|
end
|
349
|
-
|
350
|
-
else
|
351
|
-
raise TypeError, "type of x is not supported #{x.class} #{x.inpect}"
|
302
|
+
LongDecimal(new_int_val, new_scale)
|
352
303
|
end
|
353
304
|
end
|
354
305
|
|
355
306
|
#
|
356
|
-
#
|
357
|
-
#
|
358
|
-
# It works fine for 1000 or 2000 digits or so.
|
359
|
-
# This method could be optimized more, but if you really want to go
|
360
|
-
# for more digits, you will find a specialized and optimized program
|
361
|
-
# for this specific purpose, probably written in C or C++.
|
362
|
-
# Since calculation of pi is not what should typically be done with
|
363
|
-
# LongDecimal, you may consider this method to be the easter egg of
|
364
|
-
# LongDecimal. ;-)
|
365
|
-
#
|
366
|
-
def LongMath.calc_pi(prec, final_mode = LongDecimal::ROUND_HALF_DOWN)
|
367
|
-
mode = LongDecimal::ROUND_HALF_DOWN
|
368
|
-
iprec = 5*(prec+1)
|
369
|
-
sprec = (iprec >> 1) + 1
|
370
|
-
dprec = (prec+1) << 1
|
371
|
-
|
372
|
-
a = LongDecimal(1)
|
373
|
-
b = (1 / LongDecimal(2).sqrt(iprec,mode)).round_to_scale(iprec, mode)
|
374
|
-
c = LongDecimal(5,1)
|
375
|
-
k = 1
|
376
|
-
pow_k = 2
|
377
|
-
|
378
|
-
pi = 0
|
379
|
-
last_pi = 0
|
380
|
-
last_diff = 1
|
307
|
+
# convert self into String, which is the decimal representation.
|
308
|
+
# Use trailing zeros, if int_val has them.
|
381
309
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
310
|
+
# optional parameter shown_scale is the number of digits after the
|
311
|
+
# decimal point. Defaults to the scale of self.
|
312
|
+
# optional parameter mode ist the rounding mode to be applied.
|
313
|
+
# Defaults to ROUND_UNNECESSARY, in which case an exception is
|
314
|
+
# thrown if rounding is actually necessary.
|
315
|
+
# optional parameter base is the base to be used when expressing
|
316
|
+
# self as string. defaults to 10.
|
317
|
+
#
|
318
|
+
def to_s(shown_scale = @scale, mode = ROUND_UNNECESSARY, base = 10)
|
319
|
+
if (base == 10) then
|
320
|
+
if (shown_scale == @scale)
|
321
|
+
to_s_10
|
322
|
+
else
|
323
|
+
s = self.round_to_scale(shown_scale, mode)
|
324
|
+
s.to_s_10
|
389
325
|
end
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
326
|
+
else
|
327
|
+
# base is not 10
|
328
|
+
unless (base.kind_of? Integer) && 2 <= base && base <= 36 then
|
329
|
+
raise TypeError, "base must be integer between 2 and 36"
|
330
|
+
end
|
331
|
+
quot = (self.move_point_right(scale) * base ** shown_scale) / 10 ** scale
|
332
|
+
# p(quot)
|
333
|
+
rounded = quot.round_to_scale(0, mode)
|
334
|
+
# p(rounded)
|
335
|
+
rounded.to_s_internal(base, shown_scale)
|
395
336
|
end
|
396
|
-
pi.round_to_scale(prec, final_mode)
|
397
337
|
end
|
398
338
|
|
399
339
|
#
|
400
|
-
#
|
401
|
-
#
|
402
|
-
# fits into a float (x <= 709). This limitation is somewhat
|
403
|
-
# arbitrary, but it is enforced in order to avoid producing numbers
|
404
|
-
# with the exponential function that exceed the memory. It may be
|
405
|
-
# removed in future versions.
|
340
|
+
# internal helper method, converts self to string in decimal system
|
341
|
+
# with default settings.
|
406
342
|
#
|
407
|
-
def
|
408
|
-
|
409
|
-
raise TypeError, "x=#{x.inspect} must not be greater #{MAX_EXP_ABLE}" unless x <= MAX_EXP_ABLE
|
410
|
-
check_is_prec(prec, "prec")
|
411
|
-
check_is_mode(mode, "mode")
|
412
|
-
exp_internal(x, prec, mode)
|
343
|
+
def to_s_10
|
344
|
+
to_s_internal(10, scale)
|
413
345
|
end
|
414
346
|
|
415
347
|
#
|
416
|
-
#
|
417
|
-
# calculate internal precision
|
348
|
+
# internal helper method, converts self to string in any number system
|
418
349
|
#
|
419
|
-
def
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
350
|
+
def to_s_internal(b, sc)
|
351
|
+
sg = sgn
|
352
|
+
i = int_val.abs
|
353
|
+
str = i.to_s(b)
|
354
|
+
if sc > 0 then
|
355
|
+
missing = sc - str.length + 1
|
356
|
+
if missing > 0 then
|
357
|
+
str = ("0" * missing) + str
|
358
|
+
end
|
359
|
+
str[-sc, 0] = "."
|
428
360
|
end
|
429
|
-
|
430
|
-
|
361
|
+
str = "-" + str if sg < 0
|
362
|
+
str
|
431
363
|
end
|
432
364
|
|
433
|
-
|
365
|
+
protected :to_s_10
|
366
|
+
protected :to_s_internal
|
434
367
|
|
435
368
|
#
|
436
|
-
#
|
437
|
-
#
|
438
|
-
#
|
439
|
-
# create a bug report, if the default settings for the parameters do
|
440
|
-
# not work correctly
|
369
|
+
# convert self into Rational
|
370
|
+
# this works quite straitforward. use int_val as numerator and a
|
371
|
+
# power of 10 as denominator
|
441
372
|
#
|
442
|
-
def
|
443
|
-
|
444
|
-
|
445
|
-
prec = x.scale
|
446
|
-
end
|
447
|
-
check_is_prec(prec, "prec")
|
448
|
-
|
449
|
-
if (final_mode == nil)
|
450
|
-
final_mode = LongDecimal::ROUND_HALF_DOWN
|
451
|
-
end
|
452
|
-
check_is_mode(final_mode, "final_mode")
|
453
|
-
check_is_mode(mode, "mode")
|
454
|
-
|
455
|
-
# if the result would come out to zero anyway, cut the work
|
456
|
-
xi = x.to_i
|
457
|
-
if (xi < -LongMath::MAX_FLOATABLE) || -((xi.to_f - 1) / LOG10) > prec+1 then
|
458
|
-
return LongDecimal(25, prec+2).round_to_scale(prec, final_mode)
|
459
|
-
end
|
460
|
-
|
461
|
-
if j == nil || k == nil then
|
462
|
-
s1 = (prec * LOG10 / LOG2) ** (1.0/3.0)
|
463
|
-
if (j == nil) then
|
464
|
-
j = s1.round
|
465
|
-
end
|
466
|
-
if (k == nil) then
|
467
|
-
k = (s1 + Math.log([1, prec].max) / LOG2).round
|
468
|
-
end
|
469
|
-
if (x > 1) then
|
470
|
-
k += (Math.log(x.to_f) / LOG2).abs.round
|
471
|
-
end
|
472
|
-
end
|
473
|
-
if (j <= 0) then
|
474
|
-
j = 1
|
475
|
-
end
|
476
|
-
if (k < 0) then
|
477
|
-
k = 0
|
478
|
-
end
|
479
|
-
check_is_int(j, "j")
|
480
|
-
check_is_int(k, "k")
|
481
|
-
|
482
|
-
if (iprec == nil) then
|
483
|
-
iprec = calc_iprec_for_exp(x, prec)
|
484
|
-
end
|
485
|
-
check_is_prec(iprec, "iprec")
|
486
|
-
# puts("exp_internal: x=#{x} prec=#{prec} iprec=#{iprec}\n")
|
487
|
-
|
488
|
-
dprec = [ iprec, (prec + 1) << 1 ].min
|
373
|
+
def to_r
|
374
|
+
Rational(numerator, denominator)
|
375
|
+
end
|
489
376
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
break if (tr <= tu && last_t <= tu)
|
508
|
-
last_t = tr
|
509
|
-
end
|
510
|
-
x_i = 1
|
511
|
-
y_k = LongDecimal(0)
|
512
|
-
j.times do |i|
|
513
|
-
if (i > 0) then
|
514
|
-
x_i = (x_i * x_k).round_to_scale(iprec, mode)
|
377
|
+
#
|
378
|
+
# convert self into Float
|
379
|
+
# this works straitforward by dividing int_val by power of 10 in
|
380
|
+
# float-arithmetic, in all cases where numerator and denominator are
|
381
|
+
# within the ranges expressable as Floats. Goes via string
|
382
|
+
# representation otherwise.
|
383
|
+
#
|
384
|
+
def to_f
|
385
|
+
divisor = denominator
|
386
|
+
if (divisor == 1) then
|
387
|
+
return numerator.to_f
|
388
|
+
elsif int_val.abs <= LongMath::MAX_FLOATABLE then
|
389
|
+
if (divisor.abs > LongMath::MAX_FLOATABLE) then
|
390
|
+
return 0.0
|
391
|
+
else
|
392
|
+
f = int_val.to_f
|
393
|
+
return f / divisor
|
515
394
|
end
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
395
|
+
elsif numerator.abs < divisor
|
396
|
+
# self is between -1 and 1
|
397
|
+
# factor = numerator.abs.div(LongMath::MAX_FLOATABLE)
|
398
|
+
# digits = factor.to_ld.int_digits10
|
399
|
+
# return LongDecimal(numerator.div(10**digits), scale -digits).to_f
|
400
|
+
return self.to_s.to_f
|
401
|
+
else
|
402
|
+
# s2 = [scale.div(2), 1].max
|
403
|
+
# return LongDecimal(numerator.div(10**s2), scale - s2).to_f
|
404
|
+
return self.to_s.to_f
|
523
405
|
end
|
524
|
-
y = y_k.round_to_scale(prec, final_mode)
|
525
|
-
y
|
526
406
|
end
|
527
407
|
|
528
408
|
#
|
529
|
-
#
|
530
|
-
#
|
409
|
+
# convert self into Integer
|
410
|
+
# This may loose information. In most cases it is preferred to
|
411
|
+
# control this by calling round_to_scale first and then applying
|
412
|
+
# to_i when the number represented by self is actually an integer.
|
531
413
|
#
|
532
|
-
def
|
533
|
-
|
534
|
-
check_is_prec(prec, "prec")
|
535
|
-
check_is_mode(mode, "mode")
|
536
|
-
log_internal(x, prec, mode)
|
414
|
+
def to_i
|
415
|
+
numerator.div(denominator)
|
537
416
|
end
|
538
417
|
|
539
418
|
#
|
540
|
-
#
|
541
|
-
# LongDecimal.
|
419
|
+
# convert self into LongDecimal (returns self)
|
542
420
|
#
|
543
|
-
def
|
544
|
-
|
545
|
-
check_is_prec(prec, "prec")
|
546
|
-
if (x.one?) then
|
547
|
-
return LongDecimal.zero!(prec)
|
548
|
-
end
|
549
|
-
check_is_mode(mode, "mode")
|
550
|
-
iprec = prec + 2
|
551
|
-
id = x.int_digits10
|
552
|
-
xx = x.move_point_left(id)
|
553
|
-
# puts("x=#{x} xx=#{xx} id=#{id} iprec=#{iprec}\n")
|
554
|
-
lnxx = log_internal(xx, iprec, mode)
|
555
|
-
ln10 = log_internal(10.to_ld, iprec, mode)
|
556
|
-
y = id + (lnxx / ln10).round_to_scale(prec, mode)
|
557
|
-
return y
|
421
|
+
def to_ld
|
422
|
+
self
|
558
423
|
end
|
559
424
|
|
560
425
|
#
|
561
|
-
#
|
562
|
-
# LongDecimal.
|
426
|
+
# convert selt into BigDecimal
|
563
427
|
#
|
564
|
-
def
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
return LongDecimal.zero!(prec)
|
569
|
-
end
|
570
|
-
check_is_mode(mode, "mode")
|
571
|
-
iprec = prec + 2
|
572
|
-
id = x.int_digits2
|
573
|
-
xx = (x / (1 << id)).round_to_scale(x.scale+id)
|
574
|
-
# puts("x=#{x} xx=#{xx} id=#{id} iprec=#{iprec}\n")
|
575
|
-
lnxx = log_internal(xx, iprec, mode)
|
576
|
-
ln2 = log_internal(2.to_ld, iprec, mode)
|
577
|
-
y = id + (lnxx / ln2).round_to_scale(prec, mode)
|
578
|
-
return y
|
428
|
+
def to_bd
|
429
|
+
# this operation is probably not used so heavily, so we can live with a
|
430
|
+
# string as an intermediate step.
|
431
|
+
BigDecimal(self.to_s)
|
579
432
|
end
|
580
433
|
|
581
434
|
#
|
582
|
-
#
|
583
|
-
#
|
584
|
-
#
|
585
|
-
#
|
586
|
-
# not
|
435
|
+
# LongDecimals can be seen as a fraction with a power of 10 as
|
436
|
+
# denominator for compatibility with other numeric classes this
|
437
|
+
# method is included, returning 10**scale.
|
438
|
+
# Please observe that there may be common factors of numerator and
|
439
|
+
# denominator in case of LongDecimal, which does not occur in case
|
440
|
+
# of Rational
|
587
441
|
#
|
588
|
-
def
|
589
|
-
|
590
|
-
|
591
|
-
if (prec == nil) then
|
592
|
-
prec = x.scale
|
593
|
-
end
|
594
|
-
check_is_prec(prec, "prec")
|
595
|
-
if (x.one?) then
|
596
|
-
return LongDecimal.zero!(prec)
|
597
|
-
end
|
442
|
+
def denominator
|
443
|
+
10**scale
|
444
|
+
end
|
598
445
|
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
446
|
+
#
|
447
|
+
# LongDecimals can be seen as a fraction with its int_val as its
|
448
|
+
# numerator
|
449
|
+
# Please observe that there may be common factors of numerator and
|
450
|
+
# denominator in case of LongDecimal, which does not occur in case
|
451
|
+
# of Rational
|
452
|
+
#
|
453
|
+
alias numerator int_val
|
604
454
|
|
605
|
-
|
606
|
-
|
455
|
+
#
|
456
|
+
# number of binary digits before the decimal point, not counting a single 0.
|
457
|
+
# 0.xxx -> 0
|
458
|
+
# 1.xxx -> 1
|
459
|
+
# 2.xxx -> 2
|
460
|
+
# 4.xxx -> 3
|
461
|
+
# 8.xxx -> 4
|
462
|
+
# ...
|
463
|
+
#
|
464
|
+
def int_digits2
|
465
|
+
int_part = self.abs.to_i
|
466
|
+
if int_part.zero? then
|
467
|
+
return 0
|
607
468
|
end
|
608
|
-
|
609
|
-
|
469
|
+
|
470
|
+
n = int_part.size * 8 - 31
|
471
|
+
int_part = int_part >> n
|
472
|
+
until int_part.zero? do
|
473
|
+
int_part = int_part >> 1
|
474
|
+
n += 1
|
610
475
|
end
|
611
|
-
|
476
|
+
n
|
477
|
+
end
|
612
478
|
|
613
|
-
|
614
|
-
|
479
|
+
#
|
480
|
+
# number of decimal digits before the decimal point, not counting a
|
481
|
+
# single 0.
|
482
|
+
# 0.xxx -> 0
|
483
|
+
# 1.xxx -> 1
|
484
|
+
# 10.xxx -> 2
|
485
|
+
# ...
|
486
|
+
#
|
487
|
+
def int_digits10
|
488
|
+
int_part = self.abs.to_i
|
489
|
+
if int_part.zero? then
|
490
|
+
return 0
|
491
|
+
end
|
615
492
|
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
493
|
+
id = 1
|
494
|
+
powers = []
|
495
|
+
power = 10
|
496
|
+
idx = 0
|
497
|
+
until int_part.zero? do
|
498
|
+
expon = 1 << idx
|
499
|
+
powers[idx] = power
|
500
|
+
break if int_part < power
|
501
|
+
id += expon
|
502
|
+
int_part = (int_part / power).to_i
|
503
|
+
idx += 1
|
504
|
+
power = power * power
|
623
505
|
end
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
if (s < 0) then
|
633
|
-
y -= estimate
|
634
|
-
else
|
635
|
-
y += estimate
|
506
|
+
until int_part < 10 do
|
507
|
+
idx -= 1
|
508
|
+
expon = 1 << idx
|
509
|
+
power = powers[idx]
|
510
|
+
# puts("i=#{int_part} p=#{power}\n")
|
511
|
+
while int_part >= power
|
512
|
+
id += expon
|
513
|
+
int_part = (int_part / power).to_i
|
636
514
|
end
|
637
515
|
end
|
516
|
+
id
|
517
|
+
end
|
638
518
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
#
|
649
|
-
|
650
|
-
|
651
|
-
if (s < 0) then
|
652
|
-
y -= estimate
|
519
|
+
#
|
520
|
+
# before adding or subtracting two LongDecimal numbers
|
521
|
+
# it is mandatory to set them to the same scale. The maximum of the
|
522
|
+
# two summands is used, in order to avoid loosing any information.
|
523
|
+
# this method is mostly for internal use
|
524
|
+
#
|
525
|
+
def equalize_scale(other)
|
526
|
+
o, s = coerce(other)
|
527
|
+
if (s.kind_of? LongDecimal) then
|
528
|
+
# make sure Floats do not mess up our number of significant digits when adding
|
529
|
+
if (other.kind_of? Float) then
|
530
|
+
o = o.round_to_scale(s.scale, ROUND_HALF_UP)
|
653
531
|
else
|
654
|
-
|
532
|
+
new_scale = [s.scale, o.scale].max
|
533
|
+
s = s.round_to_scale(new_scale)
|
534
|
+
o = o.round_to_scale(new_scale)
|
655
535
|
end
|
656
|
-
# puts("y=#{y} s=#{s} est=#{estimate} part=#{exp_part} x=#{x}\n")
|
657
536
|
end
|
537
|
+
return s, o
|
538
|
+
end
|
539
|
+
|
540
|
+
#
|
541
|
+
# before dividing two LongDecimal numbers, it is mandatory to set
|
542
|
+
# make them both to integers, so the result is simply expressable as
|
543
|
+
# a rational
|
544
|
+
# this method is mostly for internal use
|
545
|
+
#
|
546
|
+
def anti_equalize_scale(other)
|
547
|
+
o, s = coerce(other)
|
548
|
+
if (s.kind_of? LongDecimal) then
|
549
|
+
exponent = [s.scale, o.scale].max
|
550
|
+
factor = 10**exponent
|
551
|
+
s *= factor
|
552
|
+
o *= factor
|
553
|
+
s = s.round_to_scale(0)
|
554
|
+
o = o.round_to_scale(0)
|
555
|
+
end
|
556
|
+
return s, o
|
557
|
+
end
|
658
558
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
559
|
+
#
|
560
|
+
# successor as needed for using LongDecimal in ranges
|
561
|
+
# it needs to be observed that this is usually not an increment by
|
562
|
+
# 1, but by 1/10**scale.
|
563
|
+
#
|
564
|
+
def succ
|
565
|
+
LongDecimal(int_val + 1, scale)
|
566
|
+
end
|
665
567
|
|
666
|
-
|
667
|
-
z = 1 - x
|
668
|
-
i = 1
|
669
|
-
p = 1.to_ld
|
670
|
-
d = 1.to_ld
|
671
|
-
until p.abs.round_to_scale(dprec, LongDecimal::ROUND_DOWN).zero? do
|
672
|
-
p = (p * z).round_to_scale(iprec, mode)
|
673
|
-
d = (p / i).round_to_scale(iprec, mode)
|
674
|
-
i += 1
|
675
|
-
sum += d
|
568
|
+
alias next succ
|
676
569
|
|
677
|
-
|
678
|
-
|
570
|
+
#
|
571
|
+
# predecessor (opposite of successor)
|
572
|
+
# it needs to be observed that this is usually not an decrement by
|
573
|
+
# 1, but by 1/10**scale.
|
574
|
+
#
|
575
|
+
def pred
|
576
|
+
LongDecimal(int_val - 1, scale)
|
577
|
+
end
|
679
578
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
579
|
+
#
|
580
|
+
# self + 1
|
581
|
+
#
|
582
|
+
def inc
|
583
|
+
self + 1
|
584
|
+
end
|
684
585
|
|
586
|
+
#
|
587
|
+
# self - 1
|
588
|
+
#
|
589
|
+
def dec
|
590
|
+
self - 1
|
685
591
|
end
|
686
592
|
|
687
593
|
#
|
688
|
-
#
|
689
|
-
# LongDecimal. Only supports values of y such that exp(y) still
|
690
|
-
# fits into a float (y <= 709)
|
594
|
+
# self += 1
|
691
595
|
#
|
692
|
-
def
|
693
|
-
|
694
|
-
check_is_ld(y, "y")
|
695
|
-
raise TypeError, "y=#{y.inspect} must not be greater #{MAX_EXP_ABLE}" unless y <= MAX_EXP_ABLE
|
696
|
-
raise TypeError, "x=#{x.inspect} must not be greater #{MAX_FLOATABLE}" unless x <= MAX_FLOATABLE
|
697
|
-
raise TypeError, "x=#{x.inspect} must not positive" unless x > 0
|
698
|
-
check_is_prec(prec, "prec")
|
699
|
-
check_is_mode(mode, "mode")
|
700
|
-
LongMath.power_internal(x, y, prec, mode)
|
596
|
+
def inc!
|
597
|
+
@int_val += denominator
|
701
598
|
end
|
702
599
|
|
703
600
|
#
|
704
|
-
#
|
705
|
-
# should usually be set to defaut values, in order to allow better testing.
|
706
|
-
# do not actually call this method unless you are testing exp.
|
707
|
-
# create a bug report, if the default settings for the parameters do
|
708
|
-
# not work correctly
|
601
|
+
# self -= 1
|
709
602
|
#
|
710
|
-
def
|
711
|
-
|
712
|
-
|
713
|
-
prec = x.scale
|
714
|
-
end
|
715
|
-
check_is_prec(prec, "prec")
|
603
|
+
def dec!
|
604
|
+
@int_val -= denominator
|
605
|
+
end
|
716
606
|
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
607
|
+
#
|
608
|
+
# return the unit by which self is incremented by succ
|
609
|
+
#
|
610
|
+
def unit
|
611
|
+
LongDecimal(1, scale)
|
612
|
+
end
|
722
613
|
|
723
|
-
|
614
|
+
#
|
615
|
+
# apply unary +
|
616
|
+
# (returns self)
|
617
|
+
#
|
618
|
+
def +@
|
619
|
+
self
|
620
|
+
end
|
724
621
|
|
725
|
-
|
726
|
-
|
727
|
-
|
622
|
+
#
|
623
|
+
# apply unary -
|
624
|
+
# (returns negated self)
|
625
|
+
#
|
626
|
+
def -@
|
627
|
+
if self.zero? then
|
628
|
+
self
|
629
|
+
else
|
630
|
+
LongDecimal(-int_val, scale)
|
728
631
|
end
|
729
|
-
# puts("power_internal: x=#{x} y=#{y} logx_y=#{logx_y_f} iprec=#{iprec} prec=#{prec}\n")
|
730
|
-
logx = log(x, iprec, mode)
|
731
|
-
logx_y = logx*y
|
732
|
-
xy = exp_internal(logx_y, prec + 1, mode)
|
733
|
-
# puts("power_internal: x=#{x} logx=#{logx} y=#{y} logx_y=#{logx_y} xy=#{xy} iprec=#{iprec} prec=#{prec}\n")
|
734
|
-
xy.round_to_scale(prec, final_mode)
|
735
632
|
end
|
736
633
|
|
737
|
-
|
738
|
-
|
739
|
-
#
|
740
|
-
#
|
741
|
-
#
|
742
|
-
#
|
743
|
-
#
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
634
|
+
#
|
635
|
+
# add two numbers
|
636
|
+
# if both can immediately be expressed as LongDecimal, the result is
|
637
|
+
# a LongDecimal as well. The number of digits after the decimal
|
638
|
+
# point is the max of the scales of the summands
|
639
|
+
# if LongDecimal does not cover the two summands, call addition of
|
640
|
+
# Complex, Float or LongRationalQuot
|
641
|
+
#
|
642
|
+
def +(other)
|
643
|
+
s, o = equalize_scale(other)
|
644
|
+
if s.kind_of? LongDecimal then
|
645
|
+
LongDecimal(s.int_val + o.int_val, s.scale)
|
646
|
+
else
|
647
|
+
s + o
|
648
|
+
end
|
649
|
+
end
|
748
650
|
|
749
|
-
#
|
750
|
-
#
|
751
|
-
#
|
752
|
-
#
|
753
|
-
#
|
651
|
+
#
|
652
|
+
# subtract two numbers
|
653
|
+
# if both can immediately be expressed as LongDecimal, the result is
|
654
|
+
# a LongDecimal as well. The number of digits after the decimal
|
655
|
+
# point is the max of the scales of self and other.
|
656
|
+
# if LongDecimal does not cover self and other, the subtraction of
|
657
|
+
# Complex, Float or LongRationalQuot is used
|
658
|
+
#
|
659
|
+
def -(other)
|
660
|
+
s, o = equalize_scale(other)
|
661
|
+
if s.kind_of? LongDecimal then
|
662
|
+
LongDecimal(s.int_val - o.int_val, s.scale)
|
663
|
+
else
|
664
|
+
s - o
|
665
|
+
end
|
666
|
+
end
|
754
667
|
|
755
668
|
#
|
756
|
-
#
|
757
|
-
#
|
758
|
-
#
|
759
|
-
#
|
760
|
-
#
|
761
|
-
#
|
669
|
+
# multiply two numbers
|
670
|
+
# if both can immediately be expressed as LongDecimal, the result is
|
671
|
+
# a LongDecimal as well. The number of digits after the decimal
|
672
|
+
# point is the sum of the scales of both factors.
|
673
|
+
# if LongDecimal does not cover self and other, the multiplication of
|
674
|
+
# Complex, Float or LongRationalQuot is used
|
762
675
|
#
|
763
|
-
def
|
764
|
-
|
676
|
+
def *(other)
|
677
|
+
o, s = coerce(other)
|
678
|
+
if s.kind_of? LongDecimal then
|
679
|
+
LongDecimal(s.int_val * o.int_val, s.scale + o.scale)
|
680
|
+
else
|
681
|
+
s * o
|
682
|
+
end
|
765
683
|
end
|
766
684
|
|
767
685
|
#
|
768
|
-
#
|
769
|
-
#
|
686
|
+
# divide self by other and round result to scale of self using the
|
687
|
+
# given rounding mode
|
770
688
|
#
|
771
|
-
def
|
772
|
-
|
689
|
+
def divide(other, rounding_mode)
|
690
|
+
divide_s(other, nil, rounding_mode)
|
773
691
|
end
|
774
692
|
|
693
|
+
#
|
694
|
+
# divide self by other and round result to new_scale using the
|
695
|
+
# given rounding mode. If new_scale is nil, use scale of self.
|
696
|
+
#
|
697
|
+
def divide_s(other, new_scale, rounding_mode)
|
698
|
+
q = self / other
|
699
|
+
if (q.kind_of? Float) then
|
700
|
+
q = LongDecimal(q)
|
701
|
+
end
|
702
|
+
if (q.kind_of? LongDecimal) || (q.kind_of? LongDecimalQuot) then
|
703
|
+
if (new_scale.nil?) then
|
704
|
+
new_scale = q.scale
|
705
|
+
end
|
706
|
+
q.round_to_scale(new_scale, rounding_mode)
|
707
|
+
else
|
708
|
+
q
|
709
|
+
end
|
710
|
+
end
|
775
711
|
|
776
712
|
#
|
777
|
-
#
|
778
|
-
#
|
713
|
+
# divide self by other and return result as Rational, if other
|
714
|
+
# allowed exact calculations.
|
779
715
|
#
|
780
|
-
def
|
781
|
-
|
716
|
+
def rdiv(other)
|
717
|
+
q = self / other
|
718
|
+
if (q.kind_of? LongDecimalQuot) then
|
719
|
+
q.to_r
|
720
|
+
else
|
721
|
+
q
|
722
|
+
end
|
782
723
|
end
|
783
724
|
|
725
|
+
#
|
726
|
+
# divide self by other and return result as LongDecimalQuot
|
727
|
+
# because division does not have an obvious rounding rule like
|
728
|
+
# addition, subtraction and multiplication, the result needs to be
|
729
|
+
# rounded afterwards to become a LongDecimal again. This way
|
730
|
+
# calculations can still be done in the natural readable way using +,
|
731
|
+
# -, *, and /, but the rounding can be provided later.
|
732
|
+
# It is very important in complicated calculations put the rounding
|
733
|
+
# steps in the right places, usually after having performed a division.
|
734
|
+
#
|
735
|
+
def /(other)
|
736
|
+
o, s = coerce(other)
|
737
|
+
if (s.kind_of? LongDecimal) then
|
738
|
+
LongDecimalQuot(s, o)
|
739
|
+
else
|
740
|
+
s / o
|
741
|
+
end
|
742
|
+
end
|
784
743
|
|
785
744
|
#
|
786
|
-
#
|
787
|
-
#
|
745
|
+
# power of self (LongDecimal) with other.
|
746
|
+
# if other is expressable as non-negative integer, the power is what
|
747
|
+
# would be obtained by successive multiplications.
|
748
|
+
# if other is expressable as negative integer, the power is a
|
749
|
+
# LongDecimalQuot as would result by successive division, but with
|
750
|
+
# the same scale as the positive power would get. Explicit rounding
|
751
|
+
# is needed to convert into a LongDecimal again
|
752
|
+
# in all other cases, self is converted into a Rational prior to
|
753
|
+
# applying power, usually resulting in a Float as power.
|
788
754
|
#
|
789
|
-
def
|
790
|
-
|
755
|
+
def **(other)
|
756
|
+
if ((other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot)) && other.is_int? then
|
757
|
+
other = other.to_i
|
758
|
+
end
|
759
|
+
if other.kind_of? Integer then
|
760
|
+
if other >= 0 then
|
761
|
+
LongDecimal(int_val ** other, scale * other)
|
762
|
+
else
|
763
|
+
abs_other = -other
|
764
|
+
new_scale = abs_other * scale
|
765
|
+
LongDecimalQuot(Rational(10 ** new_scale, int_val ** abs_other), new_scale)
|
766
|
+
end
|
767
|
+
else
|
768
|
+
if (other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot) then
|
769
|
+
other = other.to_r
|
770
|
+
end
|
771
|
+
self.to_r ** other
|
772
|
+
end
|
791
773
|
end
|
792
774
|
|
793
|
-
|
794
775
|
#
|
795
|
-
#
|
796
|
-
# digits after the decimal point (scale=s)
|
776
|
+
# do integer division with remainder, returning two values
|
797
777
|
#
|
798
|
-
def
|
799
|
-
|
778
|
+
def divmod(other)
|
779
|
+
if (other.kind_of? Complex) then
|
780
|
+
raise TypeError, "divmod not supported for Complex"
|
781
|
+
end
|
782
|
+
q = (self / other).to_i
|
783
|
+
return q, self - other * q
|
800
784
|
end
|
801
785
|
|
802
|
-
|
803
786
|
#
|
804
|
-
#
|
805
|
-
# digits after the decimal point (scale=s)
|
787
|
+
# remainder of integer division by other
|
806
788
|
#
|
807
|
-
def
|
808
|
-
|
789
|
+
def %(other)
|
790
|
+
q, r = divmod other
|
791
|
+
r
|
809
792
|
end
|
810
793
|
|
811
|
-
|
812
794
|
#
|
813
|
-
#
|
814
|
-
# exponent e and with the given number of digits after the decimal
|
815
|
-
# point (scale=s)
|
795
|
+
# performs bitwise AND between self and other
|
816
796
|
#
|
817
|
-
def
|
818
|
-
|
819
|
-
|
820
|
-
|
797
|
+
def &(other)
|
798
|
+
s, o = equalize_scale(other)
|
799
|
+
if s.kind_of? LongDecimal then
|
800
|
+
LongDecimal(s.int_val & o.int_val, s.scale)
|
801
|
+
else
|
802
|
+
s & o
|
803
|
+
end
|
821
804
|
end
|
822
805
|
|
823
|
-
|
824
806
|
#
|
825
|
-
#
|
826
|
-
# parameters:
|
827
|
-
# LongDecimal.new(x, s) where x is a string or a number and s is the scale
|
828
|
-
# the resulting LongDecimal holds the number x / 10**s
|
807
|
+
# performs bitwise OR between self and other
|
829
808
|
#
|
830
|
-
def
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
# we could maybe even work with complex number, if their imaginary part is zero.
|
835
|
-
# but this is not so important to deal with, so we raise an error anyway.
|
836
|
-
raise TypeError, "complex numbers not supported \"#{x.inspect}\"" if x.kind_of? Complex
|
837
|
-
|
838
|
-
# handle some obvious errors with optional second parameter, if present
|
839
|
-
raise TypeError, "non integer 2nd arg \"#{s.inspect}\"" if ! s.kind_of? Integer
|
840
|
-
raise TypeError, "negative 2nd arg \"#{s.inspect}\"" if s < 0
|
841
|
-
|
842
|
-
# scale is the second parameter or 0 if it is missing
|
843
|
-
scale = s
|
844
|
-
# int_val is the integral value that is multiplied by some 10**-n
|
845
|
-
int_val = 0
|
846
|
-
|
847
|
-
if x.kind_of? Integer then
|
848
|
-
# integers are trivial to handle
|
849
|
-
int_val = x
|
850
|
-
|
851
|
-
elsif x.kind_of? Rational then
|
852
|
-
# rationals are rounded somehow
|
853
|
-
# we need to come up with a better rule here.
|
854
|
-
# if denominator is any product of powers of 2 and 5, we do not need to round
|
855
|
-
denom = x.denominator
|
856
|
-
mul_2 = LongMath.multiplicity_of_factor(denom, 2)
|
857
|
-
mul_5 = LongMath.multiplicity_of_factor(denom, 5)
|
858
|
-
iscale = [mul_2, mul_5].max
|
859
|
-
scale += iscale
|
860
|
-
denom /= 2 ** mul_2
|
861
|
-
denom /= 5 ** mul_5
|
862
|
-
iscale2 = Math.log10(denom).ceil
|
863
|
-
scale += iscale2
|
864
|
-
# int_val = (x * 10 ** scale).to_i
|
865
|
-
int_val = (x * 10 ** (iscale2+iscale)).to_i
|
866
|
-
|
809
|
+
def |(other)
|
810
|
+
s, o = equalize_scale(other)
|
811
|
+
if s.kind_of? LongDecimal then
|
812
|
+
LongDecimal(s.int_val | o.int_val, s.scale)
|
867
813
|
else
|
868
|
-
|
869
|
-
# floating point number or BigDecimal is converted to string, so
|
870
|
-
# we only deal with strings
|
871
|
-
# this operation is not so common, so there is no urgent need to
|
872
|
-
# optimize it
|
873
|
-
num_str = x.to_s
|
874
|
-
len = num_str.length
|
875
|
-
|
876
|
-
# handle the obvious error that string is empty
|
877
|
-
raise TypeError, "1st arg must not be empty string. \"#{num_str.inspect}\"" if len == 0
|
878
|
-
|
879
|
-
# remove spaces and underscores
|
880
|
-
num_str.gsub! /\s/, ""
|
881
|
-
num_str.gsub! /_/, ""
|
882
|
-
|
883
|
-
# handle sign
|
884
|
-
num_str.gsub! /^\+/, ""
|
885
|
-
negative = false
|
886
|
-
if num_str.gsub! /^-/, "" then
|
887
|
-
negative = true
|
888
|
-
end
|
889
|
-
|
890
|
-
# split in parts before and after decimal point
|
891
|
-
num_arr = num_str.split /\./
|
892
|
-
if num_arr.length > 2 then
|
893
|
-
raise TypeError, "1st arg contains more than one . \"#{num_str.inspect}\""
|
894
|
-
end
|
895
|
-
num_int = num_arr[0]
|
896
|
-
num_rem = num_arr[1]
|
897
|
-
num_frac = nil
|
898
|
-
num_exp = nil
|
899
|
-
unless num_rem.nil? then
|
900
|
-
num_arr = num_rem.split /[Ee]/
|
901
|
-
num_frac = num_arr[0]
|
902
|
-
num_exp = num_arr[1]
|
903
|
-
end
|
904
|
-
|
905
|
-
if num_frac.nil? then
|
906
|
-
num_frac = ""
|
907
|
-
end
|
908
|
-
|
909
|
-
if num_exp.nil? || num_exp.empty? then
|
910
|
-
num_exp = "0"
|
911
|
-
end
|
912
|
-
num_exp = num_exp.to_i
|
913
|
-
iscale = num_frac.length - num_exp
|
914
|
-
scale += iscale
|
915
|
-
int_val = (num_int + num_frac).to_i
|
916
|
-
if negative then
|
917
|
-
int_val = -int_val
|
918
|
-
end
|
814
|
+
s | o
|
919
815
|
end
|
920
|
-
|
921
|
-
@int_val = int_val
|
922
|
-
|
923
|
-
end # initialize
|
924
|
-
|
925
|
-
attr_reader :int_val, :scale
|
816
|
+
end
|
926
817
|
|
927
818
|
#
|
928
|
-
#
|
929
|
-
#
|
930
|
-
# only for internal use:
|
931
|
-
# use round_to_scale instead
|
819
|
+
# performs bitwise XOR between self and other
|
932
820
|
#
|
933
|
-
def
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
# multiply int_val by a power of 10 in order to compensate for
|
940
|
-
# the change of scale and to keep number in the same order of magnitude.
|
941
|
-
d = s - @scale
|
942
|
-
f = 10 ** (d.abs)
|
943
|
-
if (d >= 0) then
|
944
|
-
@int_val = (@int_val * f).to_i
|
945
|
-
else
|
946
|
-
# here we actually do rounding
|
947
|
-
@int_val = (@int_val / f).to_i
|
948
|
-
end
|
949
|
-
@scale = s
|
821
|
+
def ^(other)
|
822
|
+
s, o = equalize_scale(other)
|
823
|
+
if s.kind_of? LongDecimal then
|
824
|
+
LongDecimal(s.int_val ^ o.int_val, s.scale)
|
825
|
+
else
|
826
|
+
s ^ o
|
950
827
|
end
|
951
828
|
end
|
952
829
|
|
953
|
-
protected :scale=
|
954
|
-
|
955
830
|
#
|
956
|
-
#
|
957
|
-
# param1: new_scale new scale for result
|
958
|
-
# param2: mode rounding mode to be applied when information is
|
959
|
-
# lost. defaults to ROUND_UNNECESSARY, which
|
960
|
-
# means that an exception is thrown if rounding
|
961
|
-
# would actually loose any information.
|
831
|
+
# bitwise inversion
|
962
832
|
#
|
963
|
-
def
|
964
|
-
|
965
|
-
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
966
|
-
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
967
|
-
raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
|
968
|
-
if @scale == new_scale then
|
969
|
-
self
|
970
|
-
else
|
971
|
-
diff = new_scale - scale
|
972
|
-
factor = 10 ** (diff.abs)
|
973
|
-
if (diff > 0) then
|
974
|
-
# we become more precise, no rounding issues
|
975
|
-
new_int_val = int_val * factor
|
976
|
-
else
|
977
|
-
quot, rem = int_val.divmod(factor)
|
978
|
-
if (rem == 0) then
|
979
|
-
new_int_val = quot
|
980
|
-
elsif (mode == ROUND_UNNECESSARY) then
|
981
|
-
raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
|
982
|
-
else
|
983
|
-
return LongDecimalQuot(self, LongDecimal(1)).round_to_scale(new_scale, mode)
|
984
|
-
end
|
985
|
-
end
|
986
|
-
LongDecimal(new_int_val, new_scale)
|
987
|
-
end
|
833
|
+
def ~
|
834
|
+
LongDecimal(~int_val, scale)
|
988
835
|
end
|
989
836
|
|
990
837
|
#
|
991
|
-
#
|
992
|
-
# Use trailing zeros, if int_val has them.
|
993
|
-
|
994
|
-
# optional parameter shown_scale is the number of digits after the
|
995
|
-
# decimal point. Defaults to the scale of self.
|
996
|
-
# optional parameter mode ist the rounding mode to be applied.
|
997
|
-
# Defaults to ROUND_UNNECESSARY, in which case an exception is
|
998
|
-
# thrown if rounding is actually necessary.
|
999
|
-
# optional parameter base is the base to be used when expressing
|
1000
|
-
# self as string. defaults to 10.
|
838
|
+
# performs bitwise left shift of self by other
|
1001
839
|
#
|
1002
|
-
def
|
1003
|
-
|
1004
|
-
|
1005
|
-
to_s_10
|
1006
|
-
else
|
1007
|
-
s = self.round_to_scale(shown_scale, mode)
|
1008
|
-
s.to_s_10
|
1009
|
-
end
|
1010
|
-
else
|
1011
|
-
# base is not 10
|
1012
|
-
unless (base.kind_of? Integer) && 2 <= base && base <= 36 then
|
1013
|
-
raise TypeError, "base must be integer between 2 and 36"
|
1014
|
-
end
|
1015
|
-
quot = (self.move_point_right(scale) * base ** shown_scale) / 10 ** scale
|
1016
|
-
# p(quot)
|
1017
|
-
rounded = quot.round_to_scale(0, mode)
|
1018
|
-
# p(rounded)
|
1019
|
-
rounded.to_s_internal(base, shown_scale)
|
840
|
+
def <<(other)
|
841
|
+
unless (other.kind_of? Fixnum) && other >= 0 then
|
842
|
+
raise TypeError, "cannot shift by something other than Fixnum >= 0"
|
1020
843
|
end
|
844
|
+
LongDecimal(int_val << other, scale)
|
1021
845
|
end
|
1022
846
|
|
1023
847
|
#
|
1024
|
-
#
|
1025
|
-
# with default settings.
|
848
|
+
# performs bitwise right shift of self by other
|
1026
849
|
#
|
1027
|
-
def
|
1028
|
-
|
850
|
+
def >>(other)
|
851
|
+
unless (other.kind_of? Fixnum) && other >= 0 then
|
852
|
+
raise TypeError, "cannot shift by something other than Fixnum >= 0"
|
853
|
+
end
|
854
|
+
LongDecimal(int_val >> other, scale)
|
1029
855
|
end
|
1030
856
|
|
1031
857
|
#
|
1032
|
-
#
|
858
|
+
# gets binary digit of self
|
1033
859
|
#
|
1034
|
-
def
|
1035
|
-
|
1036
|
-
i = int_val.abs
|
1037
|
-
str = i.to_s(b)
|
1038
|
-
if sc > 0 then
|
1039
|
-
missing = sc - str.length + 1
|
1040
|
-
if missing > 0 then
|
1041
|
-
str = ("0" * missing) + str
|
1042
|
-
end
|
1043
|
-
str[-sc, 0] = "."
|
1044
|
-
end
|
1045
|
-
str = "-" + str if sg < 0
|
1046
|
-
str
|
860
|
+
def [](other)
|
861
|
+
int_val[other]
|
1047
862
|
end
|
1048
863
|
|
1049
|
-
protected :to_s_10
|
1050
|
-
protected :to_s_internal
|
1051
|
-
|
1052
864
|
#
|
1053
|
-
#
|
1054
|
-
# this works quite straitforward. use int_val as numerator and a
|
1055
|
-
# power of 10 as denominator
|
865
|
+
# gets size of int_val
|
1056
866
|
#
|
1057
|
-
def
|
1058
|
-
|
867
|
+
def size
|
868
|
+
int_val.size
|
1059
869
|
end
|
1060
870
|
|
1061
871
|
#
|
1062
|
-
#
|
1063
|
-
# this works straitforward by dividing int_val by power of 10 in
|
1064
|
-
# float-arithmetic, in all cases where numerator and denominator are
|
1065
|
-
# within the ranges expressable as Floats. Goes via string
|
1066
|
-
# representation otherwise.
|
872
|
+
# divide by 10**n
|
1067
873
|
#
|
1068
|
-
def
|
1069
|
-
|
1070
|
-
if (
|
1071
|
-
|
1072
|
-
elsif int_val.abs <= LongMath::MAX_FLOATABLE then
|
1073
|
-
if (divisor.abs > LongMath::MAX_FLOATABLE) then
|
1074
|
-
return 0.0
|
1075
|
-
else
|
1076
|
-
f = int_val.to_f
|
1077
|
-
return f / divisor
|
1078
|
-
end
|
1079
|
-
elsif numerator.abs < divisor
|
1080
|
-
# self is between -1 and 1
|
1081
|
-
# factor = numerator.abs.div(LongMath::MAX_FLOATABLE)
|
1082
|
-
# digits = factor.to_ld.int_digits10
|
1083
|
-
# return LongDecimal(numerator.div(10**digits), scale -digits).to_f
|
1084
|
-
return self.to_s.to_f
|
874
|
+
def move_point_left(n)
|
875
|
+
raise TypeError, "only implemented for Fixnum" unless n.kind_of? Fixnum
|
876
|
+
if (n >= 0) then
|
877
|
+
move_point_left_int(n)
|
1085
878
|
else
|
1086
|
-
|
1087
|
-
# return LongDecimal(numerator.div(10**s2), scale - s2).to_f
|
1088
|
-
return self.to_s.to_f
|
879
|
+
move_point_right_int(-n)
|
1089
880
|
end
|
1090
881
|
end
|
1091
882
|
|
1092
883
|
#
|
1093
|
-
#
|
1094
|
-
# This may loose information. In most cases it is preferred to
|
1095
|
-
# control this by calling round_to_scale first and then applying
|
1096
|
-
# to_i when the number represented by self is actually an integer.
|
884
|
+
# multiply by 10**n
|
1097
885
|
#
|
1098
|
-
def
|
1099
|
-
|
886
|
+
def move_point_right(n)
|
887
|
+
raise TypeError, "only implemented for Fixnum" unless n.kind_of? Fixnum
|
888
|
+
if (n < 0) then
|
889
|
+
move_point_left_int(-n)
|
890
|
+
else
|
891
|
+
move_point_right_int(n)
|
892
|
+
end
|
1100
893
|
end
|
1101
894
|
|
1102
895
|
#
|
1103
|
-
#
|
896
|
+
# internal method
|
897
|
+
# divide by 10**n
|
1104
898
|
#
|
1105
|
-
def
|
1106
|
-
|
899
|
+
def move_point_left_int(n)
|
900
|
+
raise TypeError, "only implemented for Fixnum >= 0" unless n >= 0
|
901
|
+
LongDecimal(int_val, scale + n)
|
1107
902
|
end
|
1108
903
|
|
1109
904
|
#
|
1110
|
-
#
|
905
|
+
# internal method
|
906
|
+
# multiply by 10**n
|
1111
907
|
#
|
1112
|
-
def
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
908
|
+
def move_point_right_int(n)
|
909
|
+
raise TypeError, "only implemented for Fixnum >= 0" unless n >= 0
|
910
|
+
if (n > scale) then
|
911
|
+
LongDecimal(int_val * 10**(n-scale), 0)
|
912
|
+
else
|
913
|
+
LongDecimal(int_val, scale-n)
|
914
|
+
end
|
1116
915
|
end
|
1117
916
|
|
917
|
+
protected :move_point_left_int, :move_point_right_int
|
918
|
+
|
1118
919
|
#
|
1119
|
-
#
|
1120
|
-
# denominator for compatibility with other numeric classes this
|
1121
|
-
# method is included, returning 10**scale.
|
1122
|
-
# Please observe that there may be common factors of numerator and
|
1123
|
-
# denominator in case of LongDecimal, which does not occur in case
|
1124
|
-
# of Rational
|
920
|
+
# calculate the square of self
|
1125
921
|
#
|
1126
|
-
def
|
1127
|
-
|
922
|
+
def square
|
923
|
+
self * self
|
1128
924
|
end
|
1129
925
|
|
1130
926
|
#
|
1131
|
-
#
|
1132
|
-
#
|
1133
|
-
#
|
1134
|
-
#
|
1135
|
-
# of Rational
|
927
|
+
# calculate the sqrt of self
|
928
|
+
# provide the result with given number
|
929
|
+
# new_scale of digits after the decimal point
|
930
|
+
# use rounding_mode if the result is not exact
|
1136
931
|
#
|
1137
|
-
|
932
|
+
def sqrt(new_scale, rounding_mode)
|
933
|
+
sqrt_internal(new_scale, rounding_mode, false)
|
934
|
+
end
|
1138
935
|
|
1139
936
|
#
|
1140
|
-
#
|
1141
|
-
#
|
1142
|
-
#
|
1143
|
-
#
|
1144
|
-
# 4.xxx -> 3
|
1145
|
-
# 8.xxx -> 4
|
1146
|
-
# ...
|
937
|
+
# calculate the sqrt s of self and remainder r >= 0
|
938
|
+
# such that s*s+r = self and (s+1)*(s+1) > self
|
939
|
+
# provide the result with given number
|
940
|
+
# new_scale of digits after the decimal point
|
1147
941
|
#
|
1148
|
-
def
|
1149
|
-
|
1150
|
-
if int_part.zero? then
|
1151
|
-
return 0
|
1152
|
-
end
|
1153
|
-
|
1154
|
-
n = int_part.size * 8 - 31
|
1155
|
-
int_part = int_part >> n
|
1156
|
-
until int_part.zero? do
|
1157
|
-
int_part = int_part >> 1
|
1158
|
-
n += 1
|
1159
|
-
end
|
1160
|
-
n
|
942
|
+
def sqrt_with_remainder(new_scale)
|
943
|
+
sqrt_internal(new_scale, ROUND_DOWN, true)
|
1161
944
|
end
|
1162
945
|
|
946
|
+
|
1163
947
|
#
|
1164
|
-
#
|
1165
|
-
# single 0.
|
1166
|
-
# 0.xxx -> 0
|
1167
|
-
# 1.xxx -> 1
|
1168
|
-
# 10.xxx -> 2
|
1169
|
-
# ...
|
948
|
+
# internal helper method for calculationg sqrt and sqrt_with_remainder
|
1170
949
|
#
|
1171
|
-
def
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
end
|
950
|
+
def sqrt_internal(new_scale, rounding_mode, with_rem)
|
951
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
952
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
953
|
+
raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless rounding_mode.kind_of? RoundingModeClass
|
1176
954
|
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
idx = 0
|
1181
|
-
until int_part.zero? do
|
1182
|
-
expon = 1 << idx
|
1183
|
-
powers[idx] = power
|
1184
|
-
break if int_part < power
|
1185
|
-
id += expon
|
1186
|
-
int_part = (int_part / power).to_i
|
1187
|
-
idx += 1
|
1188
|
-
power = power * power
|
955
|
+
new_scale1 = new_scale
|
956
|
+
unless (with_rem) then
|
957
|
+
new_scale1 += 1
|
1189
958
|
end
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
959
|
+
old_scale = (new_scale1 << 1)
|
960
|
+
x = round_to_scale(old_scale, rounding_mode)
|
961
|
+
root, rem = LongMath.sqrtw_with_remainder(x.int_val)
|
962
|
+
y = LongDecimal(root, new_scale1)
|
963
|
+
if (with_rem) then
|
964
|
+
r = LongDecimal(rem, old_scale)
|
965
|
+
return [ y, r ]
|
966
|
+
else
|
967
|
+
if ((rounding_mode == ROUND_HALF_EVEN || rounding_mode == ROUND_HALF_DOWN) && rem > 0) then
|
968
|
+
rounding_mode = ROUND_HALF_UP
|
1198
969
|
end
|
970
|
+
y = y.round_to_scale(new_scale, rounding_mode)
|
971
|
+
return y
|
1199
972
|
end
|
1200
|
-
id
|
1201
973
|
end
|
1202
974
|
|
975
|
+
private :sqrt_internal
|
976
|
+
|
1203
977
|
#
|
1204
|
-
#
|
1205
|
-
# it is mandatory to set them to the same scale. The maximum of the
|
1206
|
-
# two summands is used, in order to avoid loosing any information.
|
1207
|
-
# this method is mostly for internal use
|
978
|
+
# calculate the multiplicative inverse
|
1208
979
|
#
|
1209
|
-
def
|
1210
|
-
|
1211
|
-
if (s.kind_of? LongDecimal) then
|
1212
|
-
# make sure Floats do not mess up our number of significant digits when adding
|
1213
|
-
if (other.kind_of? Float) then
|
1214
|
-
o = o.round_to_scale(s.scale, ROUND_HALF_UP)
|
1215
|
-
else
|
1216
|
-
new_scale = [s.scale, o.scale].max
|
1217
|
-
s = s.round_to_scale(new_scale)
|
1218
|
-
o = o.round_to_scale(new_scale)
|
1219
|
-
end
|
1220
|
-
end
|
1221
|
-
return s, o
|
980
|
+
def reciprocal
|
981
|
+
1 / self
|
1222
982
|
end
|
1223
983
|
|
984
|
+
alias inverse reciprocal
|
985
|
+
|
1224
986
|
#
|
1225
|
-
#
|
1226
|
-
# make them both to integers, so the result is simply expressable as
|
1227
|
-
# a rational
|
1228
|
-
# this method is mostly for internal use
|
987
|
+
# Absolute value
|
1229
988
|
#
|
1230
|
-
def
|
1231
|
-
|
1232
|
-
if (s.kind_of? LongDecimal) then
|
1233
|
-
exponent = [s.scale, o.scale].max
|
1234
|
-
factor = 10**exponent
|
1235
|
-
s *= factor
|
1236
|
-
o *= factor
|
1237
|
-
s = s.round_to_scale(0)
|
1238
|
-
o = o.round_to_scale(0)
|
1239
|
-
end
|
1240
|
-
return s, o
|
989
|
+
def abs
|
990
|
+
LongDecimal(int_val.abs, scale)
|
1241
991
|
end
|
1242
992
|
|
1243
993
|
#
|
1244
|
-
#
|
1245
|
-
#
|
1246
|
-
# 1, but by 1/10**scale.
|
994
|
+
# square of absolute value
|
995
|
+
# happens to be the square
|
1247
996
|
#
|
1248
|
-
|
1249
|
-
LongDecimal(int_val + 1, scale)
|
1250
|
-
end
|
1251
|
-
|
1252
|
-
alias next succ
|
997
|
+
alias abs2 square
|
1253
998
|
|
1254
999
|
#
|
1255
|
-
#
|
1256
|
-
#
|
1257
|
-
#
|
1000
|
+
# Compares the two numbers.
|
1001
|
+
# returns -1 if self < other
|
1002
|
+
# 0 if self-other = 0
|
1003
|
+
# +1 if self > other
|
1004
|
+
# it needs to be observed, that
|
1005
|
+
# x == y implies (x <=> y) == 0
|
1006
|
+
# but not
|
1007
|
+
# (x <=> y) == 0 implies x == y
|
1008
|
+
# because == also takes the scale into account and considers two
|
1009
|
+
# numbers only equal, if they have the same number of potentially
|
1010
|
+
# zero digits after the decimal point.
|
1258
1011
|
#
|
1259
|
-
def
|
1260
|
-
|
1012
|
+
def <=> (other)
|
1013
|
+
diff = (self - other)
|
1014
|
+
if (diff.kind_of? LongDecimal) || (diff.kind_of? LongDecimalQuot) then
|
1015
|
+
diff.sgn
|
1016
|
+
else
|
1017
|
+
diff <=> 0
|
1018
|
+
end
|
1261
1019
|
end
|
1262
1020
|
|
1263
1021
|
#
|
1264
|
-
#
|
1022
|
+
# <=>-comparison for the scales
|
1265
1023
|
#
|
1266
|
-
def
|
1267
|
-
|
1024
|
+
def scale_ufo(other)
|
1025
|
+
raise TypeError, "only works for LongDecimal and LongDecimalQuot" unless (other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot)
|
1026
|
+
self.scale <=> other.scale
|
1268
1027
|
end
|
1269
1028
|
|
1270
1029
|
#
|
1271
|
-
#
|
1030
|
+
# ==-comparison for the scales
|
1272
1031
|
#
|
1273
|
-
def
|
1274
|
-
|
1032
|
+
def scale_equal(other)
|
1033
|
+
scale_ufo(other).zero?
|
1275
1034
|
end
|
1276
1035
|
|
1277
1036
|
#
|
1278
|
-
# self
|
1037
|
+
# return a pair o, s resembling other, self, but potentially
|
1038
|
+
# converted to compatible types and ready for
|
1039
|
+
# arithmetic operations.
|
1279
1040
|
#
|
1280
|
-
def
|
1281
|
-
|
1041
|
+
def coerce(other)
|
1042
|
+
if other.kind_of? LongDecimal then
|
1043
|
+
return other, self
|
1044
|
+
elsif other.kind_of? LongDecimalQuot then
|
1045
|
+
return other, LongDecimalQuot(self.to_r, scale)
|
1046
|
+
elsif other.kind_of? Rational then
|
1047
|
+
sc = scale
|
1048
|
+
o = LongDecimalQuot(other, sc)
|
1049
|
+
s = LongDecimalQuot(self.to_r, sc)
|
1050
|
+
return o, s
|
1051
|
+
elsif (other.kind_of? Integer) || (other.kind_of? Float) then
|
1052
|
+
other = LongDecimal(other)
|
1053
|
+
if (other.scale > scale) then
|
1054
|
+
other = other.round_to_scale(scale, ROUND_HALF_UP)
|
1055
|
+
end
|
1056
|
+
return other, self
|
1057
|
+
elsif other.kind_of? BigDecimal then
|
1058
|
+
s, o = other.coerce(self.to_bd)
|
1059
|
+
return o, s
|
1060
|
+
elsif other.kind_of? Complex then
|
1061
|
+
# s, o = other.coerce(Complex(self.to_bd, 0))
|
1062
|
+
s, o = other.coerce(Complex(self.to_f, 0))
|
1063
|
+
return o, s
|
1064
|
+
elsif (other.kind_of? Float) && size > 8 then
|
1065
|
+
return coerce(BigDecimal(other.to_s))
|
1066
|
+
elsif other.kind_of? Numeric then
|
1067
|
+
s, o = other.coerce(self.to_f)
|
1068
|
+
return o, s
|
1069
|
+
else
|
1070
|
+
raise TypeError, "unsupported type #{other.inspect} for coerce of LongDecimal"
|
1071
|
+
end
|
1282
1072
|
end
|
1283
1073
|
|
1284
1074
|
#
|
1285
|
-
# self
|
1075
|
+
# is self expressable as an integer without loss of digits?
|
1286
1076
|
#
|
1287
|
-
def
|
1288
|
-
|
1077
|
+
def is_int?
|
1078
|
+
scale == 0 || int_val % 10**scale == 0
|
1289
1079
|
end
|
1290
1080
|
|
1291
1081
|
#
|
1292
|
-
#
|
1082
|
+
# get the sign of self
|
1083
|
+
# -1 if self < 0
|
1084
|
+
# 0 if self is 0 (with any number of 0s after the decimal point)
|
1085
|
+
# +1 if self > 0
|
1293
1086
|
#
|
1294
|
-
def
|
1295
|
-
|
1087
|
+
def sgn
|
1088
|
+
int_val <=> 0
|
1296
1089
|
end
|
1297
1090
|
|
1091
|
+
alias signum sgn
|
1092
|
+
alias sign sgn
|
1093
|
+
|
1298
1094
|
#
|
1299
|
-
#
|
1300
|
-
#
|
1095
|
+
# comparison of self with other for equality
|
1096
|
+
# takes into account the values expressed by self and other and the
|
1097
|
+
# equality of the number of digits.
|
1301
1098
|
#
|
1302
|
-
def
|
1303
|
-
self
|
1099
|
+
def ==(other)
|
1100
|
+
# (other.kind_of? LongDecimal) && (self <=> other) == 0 && self.scale == other.scale
|
1101
|
+
(other.kind_of? LongDecimal) && self.int_val == other.int_val && self.scale == other.scale
|
1304
1102
|
end
|
1305
1103
|
|
1306
1104
|
#
|
1307
|
-
#
|
1308
|
-
#
|
1105
|
+
# check if the number expressed by self is 0 (zero)
|
1106
|
+
# with any number of 0s after the decimal point.
|
1309
1107
|
#
|
1310
|
-
def
|
1311
|
-
|
1312
|
-
self
|
1313
|
-
else
|
1314
|
-
LongDecimal(-int_val, scale)
|
1315
|
-
end
|
1108
|
+
def zero?
|
1109
|
+
int_val.zero?
|
1316
1110
|
end
|
1317
1111
|
|
1318
1112
|
#
|
1319
|
-
#
|
1320
|
-
#
|
1321
|
-
# a LongDecimal as well. The number of digits after the decimal
|
1322
|
-
# point is the max of the scales of the summands
|
1323
|
-
# if LongDecimal does not cover the two summands, call addition of
|
1324
|
-
# Complex, Float or LongRationalQuot
|
1113
|
+
# check if the number expressed by self is 1 (one)
|
1114
|
+
# with any number of 0s after the decimal point.
|
1325
1115
|
#
|
1326
|
-
def
|
1327
|
-
|
1328
|
-
if s.kind_of? LongDecimal then
|
1329
|
-
LongDecimal(s.int_val + o.int_val, s.scale)
|
1330
|
-
else
|
1331
|
-
s + o
|
1332
|
-
end
|
1116
|
+
def one?
|
1117
|
+
(self-1).zero?
|
1333
1118
|
end
|
1334
1119
|
|
1335
1120
|
#
|
1336
|
-
#
|
1337
|
-
# if both can immediately be expressed as LongDecimal, the result is
|
1338
|
-
# a LongDecimal as well. The number of digits after the decimal
|
1339
|
-
# point is the max of the scales of self and other.
|
1340
|
-
# if LongDecimal does not cover self and other, the subtraction of
|
1341
|
-
# Complex, Float or LongRationalQuot is used
|
1121
|
+
# Returns a hash code for the complex number.
|
1342
1122
|
#
|
1343
|
-
def
|
1344
|
-
|
1345
|
-
if s.kind_of? LongDecimal then
|
1346
|
-
LongDecimal(s.int_val - o.int_val, s.scale)
|
1347
|
-
else
|
1348
|
-
s - o
|
1349
|
-
end
|
1123
|
+
def hash
|
1124
|
+
int_val.hash ^ scale.hash
|
1350
1125
|
end
|
1351
1126
|
|
1352
1127
|
#
|
1353
|
-
#
|
1354
|
-
# if both can immediately be expressed as LongDecimal, the result is
|
1355
|
-
# a LongDecimal as well. The number of digits after the decimal
|
1356
|
-
# point is the sum of the scales of both factors.
|
1357
|
-
# if LongDecimal does not cover self and other, the multiplication of
|
1358
|
-
# Complex, Float or LongRationalQuot is used
|
1128
|
+
# Returns "<tt>LongDecimal(<i>int_val</i>, <i>scale</i>)</tt>".
|
1359
1129
|
#
|
1360
|
-
def
|
1361
|
-
|
1362
|
-
if s.kind_of? LongDecimal then
|
1363
|
-
LongDecimal(s.int_val * o.int_val, s.scale + o.scale)
|
1364
|
-
else
|
1365
|
-
s * o
|
1366
|
-
end
|
1130
|
+
def inspect
|
1131
|
+
sprintf("LongDecimal(%s, %s)", int_val.inspect, scale.inspect)
|
1367
1132
|
end
|
1368
1133
|
|
1134
|
+
end # LongDecimal
|
1135
|
+
|
1136
|
+
#
|
1137
|
+
# This class is used for storing intermediate results after having
|
1138
|
+
# performed a division. The division cannot be completed without
|
1139
|
+
# providing additional information on how to round the result.
|
1140
|
+
#
|
1141
|
+
class LongDecimalQuot < Numeric
|
1142
|
+
|
1143
|
+
@RCS_ID='-$Id: long-decimal.rb,v 1.6 2006/03/20 21:38:32 bk1 Exp $-'
|
1144
|
+
|
1145
|
+
include LongDecimalRoundingMode
|
1146
|
+
|
1369
1147
|
#
|
1370
|
-
#
|
1371
|
-
#
|
1148
|
+
# constructor
|
1149
|
+
# first, second is either a pair of LongDecimals or a Rational and an Integer
|
1150
|
+
# The resulting LongDecimal will contain a rational obtained by
|
1151
|
+
# dividing the two LongDecimals or by taking the Rational as it is.
|
1152
|
+
# The scale is there to provide a default rounding precision for
|
1153
|
+
# conversion to LongDecimal, but it has no influence on the value
|
1154
|
+
# expressed by the LongDecimalQuot
|
1372
1155
|
#
|
1373
|
-
def
|
1374
|
-
|
1156
|
+
def LongDecimalQuot.new!(first, second)
|
1157
|
+
new(first, second)
|
1375
1158
|
end
|
1376
1159
|
|
1377
1160
|
#
|
1378
|
-
#
|
1379
|
-
#
|
1161
|
+
# create a new LongDecimalQuot from a rational and a scale or a
|
1162
|
+
# pair of LongDecimals
|
1380
1163
|
#
|
1381
|
-
def
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
q.round_to_scale(new_scale, rounding_mode)
|
1164
|
+
def initialize(first, second)
|
1165
|
+
if ((first.kind_of? Rational) || (first.kind_of? Integer)) && (second.kind_of? Integer) then
|
1166
|
+
@rat = Rational(first.numerator, first.denominator)
|
1167
|
+
@scale = second
|
1168
|
+
elsif (first.kind_of? LongDecimal) && (second.kind_of? LongDecimal) then
|
1169
|
+
orig_scale = first.scale
|
1170
|
+
first, second = first.anti_equalize_scale(second)
|
1171
|
+
@rat = Rational(first.to_i, second.to_i)
|
1172
|
+
@scale = orig_scale
|
1391
1173
|
else
|
1392
|
-
|
1174
|
+
raise TypeError, "parameters must be (LongDecimal, LongDecimal) or (Rational, Integer): first=#{first.inspect} second=#{second.inspect}";
|
1393
1175
|
end
|
1394
1176
|
end
|
1395
1177
|
|
1178
|
+
attr_reader :scale, :rat
|
1179
|
+
|
1396
1180
|
#
|
1397
|
-
#
|
1398
|
-
#
|
1181
|
+
# numerator of the included rational number.
|
1182
|
+
# LongDecimals should duck type like Rationals
|
1399
1183
|
#
|
1400
|
-
def
|
1401
|
-
|
1402
|
-
if (q.kind_of? LongDecimalQuot) then
|
1403
|
-
q.to_r
|
1404
|
-
else
|
1405
|
-
q
|
1406
|
-
end
|
1184
|
+
def numerator
|
1185
|
+
rat.numerator
|
1407
1186
|
end
|
1408
1187
|
|
1409
1188
|
#
|
1410
|
-
#
|
1411
|
-
#
|
1412
|
-
# addition, subtraction and multiplication, the result needs to be
|
1413
|
-
# rounded afterwards to become a LongDecimal again. This way
|
1414
|
-
# calculations can still be done in the natural readable way using +,
|
1415
|
-
# -, *, and /, but the rounding can be provided later.
|
1416
|
-
# It is very important in complicated calculations put the rounding
|
1417
|
-
# steps in the right places, usually after having performed a division.
|
1189
|
+
# denominator of the included rational number.
|
1190
|
+
# LongDecimals should duck type like Rationals
|
1418
1191
|
#
|
1419
|
-
def
|
1420
|
-
|
1421
|
-
if (s.kind_of? LongDecimal) then
|
1422
|
-
LongDecimalQuot(s, o)
|
1423
|
-
else
|
1424
|
-
s / o
|
1425
|
-
end
|
1192
|
+
def denominator
|
1193
|
+
rat.denominator
|
1426
1194
|
end
|
1427
1195
|
|
1428
1196
|
#
|
1429
|
-
#
|
1430
|
-
# if other is expressable as non-negative integer, the power is what
|
1431
|
-
# would be obtained by successive multiplications.
|
1432
|
-
# if other is expressable as negative integer, the power is a
|
1433
|
-
# LongDecimalQuot as would result by successive division, but with
|
1434
|
-
# the same scale as the positive power would get. Explicit rounding
|
1435
|
-
# is needed to convert into a LongDecimal again
|
1436
|
-
# in all other cases, self is converted into a Rational prior to
|
1437
|
-
# applying power, usually resulting in a Float as power.
|
1197
|
+
# alter scale (only for internal use)
|
1438
1198
|
#
|
1439
|
-
def
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
1443
|
-
if other.kind_of? Integer then
|
1444
|
-
if other >= 0 then
|
1445
|
-
LongDecimal(int_val ** other, scale * other)
|
1446
|
-
else
|
1447
|
-
abs_other = -other
|
1448
|
-
new_scale = abs_other * scale
|
1449
|
-
LongDecimalQuot(Rational(10 ** new_scale, int_val ** abs_other), new_scale)
|
1450
|
-
end
|
1451
|
-
else
|
1452
|
-
if (other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot) then
|
1453
|
-
other = other.to_r
|
1454
|
-
end
|
1455
|
-
self.to_r ** other
|
1456
|
-
end
|
1199
|
+
def scale=(s)
|
1200
|
+
raise TypeError, "non integer arg \"#{s.inspect}\"" if ! s.kind_of? Integer
|
1201
|
+
raise TypeError, "negative arg \"#{s.inspect}\"" if s < 0
|
1202
|
+
@scale = s
|
1457
1203
|
end
|
1458
1204
|
|
1205
|
+
private :scale=
|
1206
|
+
|
1459
1207
|
#
|
1460
|
-
#
|
1208
|
+
# conversion to string. Based on the conversion of Rational
|
1461
1209
|
#
|
1462
|
-
def
|
1463
|
-
|
1464
|
-
|
1465
|
-
end
|
1466
|
-
q = (self / other).to_i
|
1467
|
-
return q, self - other * q
|
1210
|
+
def to_s
|
1211
|
+
str = @rat.to_s
|
1212
|
+
str + "[" + scale.to_s + "]"
|
1468
1213
|
end
|
1469
1214
|
|
1470
1215
|
#
|
1471
|
-
#
|
1216
|
+
# conversion to rational
|
1472
1217
|
#
|
1473
|
-
def
|
1474
|
-
|
1475
|
-
r
|
1218
|
+
def to_r
|
1219
|
+
Rational(numerator, denominator)
|
1476
1220
|
end
|
1477
1221
|
|
1478
1222
|
#
|
1479
|
-
#
|
1223
|
+
# convert into Float
|
1480
1224
|
#
|
1481
|
-
def
|
1482
|
-
|
1483
|
-
if s.kind_of? LongDecimal then
|
1484
|
-
LongDecimal(s.int_val & o.int_val, s.scale)
|
1485
|
-
else
|
1486
|
-
s & o
|
1487
|
-
end
|
1225
|
+
def to_f
|
1226
|
+
to_r.to_f
|
1488
1227
|
end
|
1489
1228
|
|
1490
1229
|
#
|
1491
|
-
#
|
1230
|
+
# convert into Integer
|
1492
1231
|
#
|
1493
|
-
def
|
1494
|
-
|
1495
|
-
if s.kind_of? LongDecimal then
|
1496
|
-
LongDecimal(s.int_val | o.int_val, s.scale)
|
1497
|
-
else
|
1498
|
-
s | o
|
1499
|
-
end
|
1232
|
+
def to_i
|
1233
|
+
to_r.to_i
|
1500
1234
|
end
|
1501
1235
|
|
1502
1236
|
#
|
1503
|
-
#
|
1237
|
+
# conversion to LongDecimal using the internal scale
|
1504
1238
|
#
|
1505
|
-
def
|
1506
|
-
|
1507
|
-
if s.kind_of? LongDecimal then
|
1508
|
-
LongDecimal(s.int_val ^ o.int_val, s.scale)
|
1509
|
-
else
|
1510
|
-
s ^ o
|
1511
|
-
end
|
1239
|
+
def to_ld
|
1240
|
+
round_to_scale(scale, ROUND_HALF_UP)
|
1512
1241
|
end
|
1513
1242
|
|
1514
1243
|
#
|
1515
|
-
#
|
1244
|
+
# unary plus returns self
|
1516
1245
|
#
|
1517
|
-
def
|
1518
|
-
|
1246
|
+
def +@
|
1247
|
+
self
|
1519
1248
|
end
|
1520
1249
|
|
1521
1250
|
#
|
1522
|
-
#
|
1251
|
+
# unary minus returns negation of self
|
1252
|
+
# leaves self unchanged.
|
1523
1253
|
#
|
1524
|
-
def
|
1525
|
-
|
1526
|
-
|
1254
|
+
def -@
|
1255
|
+
if self.zero? then
|
1256
|
+
self
|
1257
|
+
else
|
1258
|
+
LongDecimalQuot(-rat, scale)
|
1527
1259
|
end
|
1528
|
-
LongDecimal(s.int_val << other, s.scale)
|
1529
1260
|
end
|
1530
1261
|
|
1531
1262
|
#
|
1532
|
-
#
|
1263
|
+
# addition
|
1264
|
+
# if other can be converted into LongDecimalQuot, add as
|
1265
|
+
# LongDecimalQuot, using the addition of Rationals internally
|
1266
|
+
# otherwise use BigDecimal, Complex or Float
|
1533
1267
|
#
|
1534
|
-
def
|
1535
|
-
|
1536
|
-
|
1268
|
+
def +(other)
|
1269
|
+
o, s = coerce(other)
|
1270
|
+
if (s.kind_of? LongDecimalQuot) then
|
1271
|
+
LongDecimalQuot(s.rat + o.rat, [s.scale, o.scale].max)
|
1272
|
+
else
|
1273
|
+
s + o
|
1537
1274
|
end
|
1538
|
-
LongDecimal(s.int_val >> other, s.scale)
|
1539
1275
|
end
|
1540
1276
|
|
1541
1277
|
#
|
1542
|
-
#
|
1278
|
+
# subtraction
|
1279
|
+
# if other can be converted into LongDecimalQuot, add as
|
1280
|
+
# LongDecimalQuot, using the subtraction of Rationals internally
|
1281
|
+
# otherwise use BigDecimal, Complex or Float
|
1543
1282
|
#
|
1544
|
-
def
|
1545
|
-
|
1283
|
+
def -(other)
|
1284
|
+
o, s = coerce(other)
|
1285
|
+
if (s.kind_of? LongDecimalQuot) then
|
1286
|
+
LongDecimalQuot(s.rat - o.rat, [s.scale, o.scale].max)
|
1287
|
+
else
|
1288
|
+
s - o
|
1289
|
+
end
|
1546
1290
|
end
|
1547
1291
|
|
1548
1292
|
#
|
1549
|
-
#
|
1293
|
+
# multiplication
|
1294
|
+
# if other can be converted into LongDecimalQuot, add as
|
1295
|
+
# LongDecimalQuot, using the multiplication of Rationals internally
|
1296
|
+
# otherwise use BigDecimal, Complex or Float
|
1550
1297
|
#
|
1551
|
-
def
|
1552
|
-
|
1298
|
+
def *(other)
|
1299
|
+
o, s = coerce(other)
|
1300
|
+
if (s.kind_of? LongDecimalQuot) then
|
1301
|
+
LongDecimalQuot(s.rat * o.rat, s.scale + o.scale)
|
1302
|
+
else
|
1303
|
+
s * o
|
1304
|
+
end
|
1553
1305
|
end
|
1554
1306
|
|
1555
1307
|
#
|
1556
|
-
#
|
1308
|
+
# division
|
1309
|
+
# if other can be converted into LongDecimalQuot, add as
|
1310
|
+
# LongDecimalQuot, using the division of Rationals internally
|
1311
|
+
# otherwise use BigDecimal, Complex or Float
|
1557
1312
|
#
|
1558
|
-
def
|
1559
|
-
|
1560
|
-
if (
|
1561
|
-
|
1313
|
+
def /(other)
|
1314
|
+
o, s = coerce(other)
|
1315
|
+
if (s.kind_of? LongDecimalQuot) then
|
1316
|
+
LongDecimalQuot(s.rat / o.rat, scale)
|
1562
1317
|
else
|
1563
|
-
|
1318
|
+
s / o
|
1564
1319
|
end
|
1565
1320
|
end
|
1566
1321
|
|
1567
1322
|
#
|
1568
|
-
#
|
1323
|
+
# potentiation
|
1324
|
+
# if other can be converted into integer, use power of rational base
|
1325
|
+
# with integral exponent internally
|
1326
|
+
# otherwise result will be Float, BigDecimal or Complex
|
1569
1327
|
#
|
1570
|
-
def
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1328
|
+
def **(other)
|
1329
|
+
if (other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot) then
|
1330
|
+
if other.is_int? then
|
1331
|
+
other = other.to_i
|
1332
|
+
else
|
1333
|
+
other = other.to_r
|
1334
|
+
end
|
1335
|
+
end
|
1336
|
+
rat_result = rat ** other
|
1337
|
+
if (rat_result.kind_of? Rational) then
|
1338
|
+
if (other.kind_of? Integer) && other >= 0 then
|
1339
|
+
new_scale = scale * other
|
1340
|
+
else
|
1341
|
+
new_scale = scale
|
1342
|
+
end
|
1343
|
+
LongDecimalQuot(rat_result, new_scale)
|
1574
1344
|
else
|
1575
|
-
|
1345
|
+
rat_result
|
1576
1346
|
end
|
1577
1347
|
end
|
1578
1348
|
|
1579
1349
|
#
|
1580
|
-
#
|
1581
|
-
#
|
1350
|
+
# division with remainder
|
1351
|
+
# calculate q and r such that
|
1352
|
+
# q is an integer and r is non-negative and less or equal the
|
1353
|
+
# divisor.
|
1582
1354
|
#
|
1583
|
-
def
|
1584
|
-
|
1585
|
-
|
1355
|
+
def divmod(other)
|
1356
|
+
if (other.kind_of? Complex) then
|
1357
|
+
raise TypeError, "divmod not supported for Complex"
|
1358
|
+
end
|
1359
|
+
q = (self / other).to_i
|
1360
|
+
return q, self - other * q
|
1586
1361
|
end
|
1587
|
-
|
1362
|
+
|
1588
1363
|
#
|
1589
|
-
#
|
1590
|
-
#
|
1364
|
+
# division with remainder
|
1365
|
+
# only return the remainder
|
1591
1366
|
#
|
1592
|
-
def
|
1593
|
-
|
1594
|
-
|
1595
|
-
LongDecimal(int_val * 10**(n-scale), 0)
|
1596
|
-
else
|
1597
|
-
LongDecimal(int_val, scale-n)
|
1598
|
-
end
|
1367
|
+
def %(other)
|
1368
|
+
q, r = divmod other
|
1369
|
+
r
|
1599
1370
|
end
|
1600
1371
|
|
1601
|
-
protected :move_point_left_int, :move_point_right_int
|
1602
|
-
|
1603
1372
|
#
|
1604
1373
|
# calculate the square of self
|
1605
1374
|
#
|
@@ -1607,57 +1376,141 @@ class LongDecimal < Numeric
|
|
1607
1376
|
self * self
|
1608
1377
|
end
|
1609
1378
|
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1379
|
+
#
|
1380
|
+
# calculate the multiplicative inverse
|
1381
|
+
#
|
1382
|
+
def reciprocal
|
1383
|
+
1 / self
|
1384
|
+
end
|
1614
1385
|
|
1615
|
-
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
|
1620
|
-
rounding_mode = ROUND_HALF_UP
|
1621
|
-
end
|
1622
|
-
y = LongDecimal(root, new_scale1)
|
1623
|
-
y.round_to_scale(new_scale, rounding_mode)
|
1386
|
+
#
|
1387
|
+
# Absolute value
|
1388
|
+
#
|
1389
|
+
def abs
|
1390
|
+
LongDecimalQuot(rat.abs, scale)
|
1624
1391
|
end
|
1625
1392
|
|
1393
|
+
#
|
1394
|
+
# square of absolute value
|
1395
|
+
#
|
1396
|
+
def abs2
|
1397
|
+
self.abs.square
|
1398
|
+
end
|
1626
1399
|
|
1627
1400
|
#
|
1628
|
-
#
|
1401
|
+
# convert LongDecimalQuot to LongDecimal with the given precision
|
1402
|
+
# and the given rounding mode
|
1629
1403
|
#
|
1630
|
-
def
|
1631
|
-
|
1404
|
+
def round_to_scale(new_scale = @scale, mode = ROUND_UNNECESSARY)
|
1405
|
+
|
1406
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
1407
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
1408
|
+
raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
|
1409
|
+
|
1410
|
+
factor = 10**new_scale
|
1411
|
+
sign_quot = numerator <=> 0
|
1412
|
+
if sign_quot == 0 then
|
1413
|
+
return LongDecimal(0, new_scale)
|
1414
|
+
end
|
1415
|
+
prod = numerator * factor
|
1416
|
+
divisor = denominator
|
1417
|
+
quot, rem = prod.divmod(divisor)
|
1418
|
+
sign_rem = rem <=> 0
|
1419
|
+
if (sign_rem == 0)
|
1420
|
+
return LongDecimal(quot, new_scale)
|
1421
|
+
end
|
1422
|
+
raise Error, "signs do not match self=#{self.to_s} f=#{factor} prod=#{prod} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem <= 0
|
1423
|
+
if (sign_quot < 0) then
|
1424
|
+
rem -= divisor
|
1425
|
+
quot += 1
|
1426
|
+
sign_rem = rem <=> 0
|
1427
|
+
raise Error, "signs do not match self=#{self.to_s} f=#{factor} prod=#{prod} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem >= 0
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
if mode == ROUND_UNNECESSARY then
|
1431
|
+
raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
if (mode == ROUND_CEILING)
|
1435
|
+
mode = (sign_quot > 0) ? ROUND_UP : ROUND_DOWN
|
1436
|
+
elsif (mode == ROUND_FLOOR)
|
1437
|
+
mode = (sign_quot < 0) ? ROUND_UP : ROUND_DOWN
|
1438
|
+
else
|
1439
|
+
abs_rem = rem.abs
|
1440
|
+
half = (abs_rem << 1) <=> denominator
|
1441
|
+
if (mode == ROUND_HALF_UP || mode == ROUND_HALF_DOWN || mode == ROUND_HALF_EVEN) then
|
1442
|
+
if (half < 0) then
|
1443
|
+
mode = ROUND_DOWN
|
1444
|
+
elsif half > 0 then
|
1445
|
+
mode = ROUND_UP
|
1446
|
+
else
|
1447
|
+
# half == 0
|
1448
|
+
if (mode == ROUND_HALF_UP) then
|
1449
|
+
mode = ROUND_UP
|
1450
|
+
elsif (mode == ROUND_HALF_DOWN) then
|
1451
|
+
mode = ROUND_DOWN
|
1452
|
+
else
|
1453
|
+
# mode == ROUND_HALF_EVEN
|
1454
|
+
mode = (quot[0] == 1 ? ROUND_UP : ROUND_DOWN)
|
1455
|
+
end
|
1456
|
+
end
|
1457
|
+
end
|
1458
|
+
end
|
1459
|
+
|
1460
|
+
if mode == ROUND_UP
|
1461
|
+
quot += sign_quot
|
1462
|
+
end
|
1463
|
+
new_int_val = quot
|
1464
|
+
LongDecimal(new_int_val, new_scale)
|
1632
1465
|
end
|
1633
1466
|
|
1634
|
-
alias inverse reciprocal
|
1635
|
-
|
1636
1467
|
#
|
1637
|
-
#
|
1468
|
+
# prepare binary operation of other with LongDecimalQuot
|
1469
|
+
# Integer, LongDecimal, Rational and LongDecimalQuot can be
|
1470
|
+
# expressed as LongDecimalQuot, using the scale of self in case of
|
1471
|
+
# Integer and Rational. Floats can be approximated by LongDecimals
|
1472
|
+
# and thus be expressed as LongDecimalQuot
|
1473
|
+
# In case of BigDecimal, Complex or any unknown type, convert self
|
1474
|
+
# to BigDecimal or Float.
|
1638
1475
|
#
|
1639
|
-
def
|
1640
|
-
|
1476
|
+
def coerce(other)
|
1477
|
+
if other.kind_of? LongDecimal then
|
1478
|
+
return LongDecimalQuot(other.to_r, other.scale), self
|
1479
|
+
elsif other.kind_of? LongDecimalQuot then
|
1480
|
+
return other, self
|
1481
|
+
elsif other.kind_of? Rational then
|
1482
|
+
s = scale
|
1483
|
+
return LongDecimalQuot(other, s), self
|
1484
|
+
elsif (other.kind_of? Integer) then
|
1485
|
+
return LongDecimalQuot(other.to_r, scale), self
|
1486
|
+
elsif other.kind_of? Float then
|
1487
|
+
return LongDecimalQuot(other.to_ld.to_r, scale), self
|
1488
|
+
elsif other.kind_of? BigDecimal then
|
1489
|
+
s, o = other.coerce(self.to_bd)
|
1490
|
+
elsif other.kind_of? Numeric then
|
1491
|
+
s, o = other.coerce(self.to_f)
|
1492
|
+
return o, s
|
1493
|
+
else
|
1494
|
+
raise TypeError, "unsupported type #{other.inspect} for coerce of LongDecimalQuot"
|
1495
|
+
end
|
1641
1496
|
end
|
1642
1497
|
|
1643
1498
|
#
|
1644
|
-
#
|
1645
|
-
#
|
1499
|
+
# compare two numbers for equality.
|
1500
|
+
# The LongDecimalQuot self is considered == to other if and only if
|
1501
|
+
# other is also LongDecimalQuot, expresses the same value and has the
|
1502
|
+
# same scale.
|
1503
|
+
# It needs to be observed that scale does not influence the value expressed
|
1504
|
+
# by the number, but only how rouding is performed by default if no
|
1505
|
+
# explicit number of digits after the decimal point is given. But
|
1506
|
+
# scale needs to match for equality.
|
1646
1507
|
#
|
1647
|
-
|
1508
|
+
def ==(other)
|
1509
|
+
(other.kind_of? LongDecimalQuot) && (self <=> other) == 0 && self.scale == other.scale
|
1510
|
+
end
|
1648
1511
|
|
1649
1512
|
#
|
1650
|
-
# Compares the two numbers.
|
1651
|
-
# returns -1 if self < other
|
1652
|
-
# 0 if self-other = 0
|
1653
|
-
# +1 if self > other
|
1654
|
-
# it needs to be observed, that
|
1655
|
-
# x == y implies (x <=> y) == 0
|
1656
|
-
# but not
|
1657
|
-
# (x <=> y) == 0 implies x == y
|
1658
|
-
# because == also takes the scale into account and considers two
|
1659
|
-
# numbers only equal, if they have the same number of potentially
|
1660
|
-
# zero digits after the decimal point.
|
1513
|
+
# Compares the two numbers for < and > etc.
|
1661
1514
|
#
|
1662
1515
|
def <=> (other)
|
1663
1516
|
diff = (self - other)
|
@@ -1669,7 +1522,7 @@ class LongDecimal < Numeric
|
|
1669
1522
|
end
|
1670
1523
|
|
1671
1524
|
#
|
1672
|
-
#
|
1525
|
+
# compare scales with <=>
|
1673
1526
|
#
|
1674
1527
|
def scale_ufo(other)
|
1675
1528
|
raise TypeError, "only works for LongDecimal and LongDecimalQuot" unless (other.kind_of? LongDecimal) || (other.kind_of? LongDecimalQuot)
|
@@ -1677,555 +1530,759 @@ class LongDecimal < Numeric
|
|
1677
1530
|
end
|
1678
1531
|
|
1679
1532
|
#
|
1680
|
-
#
|
1533
|
+
# check if scales are equal
|
1681
1534
|
#
|
1682
1535
|
def scale_equal(other)
|
1683
1536
|
scale_ufo(other).zero?
|
1684
1537
|
end
|
1685
1538
|
|
1686
|
-
#
|
1687
|
-
# return a pair o, s resembling other, self, but potentially
|
1688
|
-
# converted to compatible types and ready for
|
1689
|
-
# arithmetic operations.
|
1690
|
-
#
|
1691
|
-
def coerce(other)
|
1692
|
-
if other.kind_of? LongDecimal then
|
1693
|
-
return other, self
|
1694
|
-
elsif other.kind_of? LongDecimalQuot then
|
1695
|
-
return other, LongDecimalQuot(self.to_r, scale)
|
1696
|
-
elsif other.kind_of? Rational then
|
1697
|
-
sc = scale
|
1698
|
-
o = LongDecimalQuot(other, sc)
|
1699
|
-
s = LongDecimalQuot(self.to_r, sc)
|
1700
|
-
return o, s
|
1701
|
-
elsif (other.kind_of? Integer) || (other.kind_of? Float) then
|
1702
|
-
other = LongDecimal(other)
|
1703
|
-
if (other.scale > scale) then
|
1704
|
-
other = other.round_to_scale(scale, ROUND_HALF_UP)
|
1705
|
-
end
|
1706
|
-
return other, self
|
1707
|
-
elsif other.kind_of? BigDecimal then
|
1708
|
-
s, o = other.coerce(self.to_bd)
|
1709
|
-
return o, s
|
1710
|
-
elsif other.kind_of? Complex then
|
1711
|
-
# s, o = other.coerce(Complex(self.to_bd, 0))
|
1712
|
-
s, o = other.coerce(Complex(self.to_f, 0))
|
1713
|
-
return o, s
|
1714
|
-
elsif (other.kind_of? Float) && size > 8 then
|
1715
|
-
return coerce(BigDecimal(other.to_s))
|
1716
|
-
elsif other.kind_of? Numeric then
|
1717
|
-
s, o = other.coerce(self.to_f)
|
1718
|
-
return o, s
|
1719
|
-
else
|
1720
|
-
raise TypeError, "unsupported type #{other.inspect} for coerce of LongDecimal"
|
1721
|
-
end
|
1722
|
-
end
|
1723
|
-
|
1724
1539
|
#
|
1725
1540
|
# is self expressable as an integer without loss of digits?
|
1726
1541
|
#
|
1727
1542
|
def is_int?
|
1728
|
-
|
1543
|
+
denominator == 1
|
1729
1544
|
end
|
1730
1545
|
|
1731
1546
|
#
|
1732
|
-
#
|
1733
|
-
# -1 if self < 0
|
1734
|
-
# 0 if self is 0 (with any number of 0s after the decimal point)
|
1735
|
-
# +1 if self > 0
|
1547
|
+
# sign of self
|
1736
1548
|
#
|
1737
1549
|
def sgn
|
1738
|
-
|
1550
|
+
numerator <=> 0
|
1739
1551
|
end
|
1740
|
-
|
1741
1552
|
alias signum sgn
|
1742
1553
|
alias sign sgn
|
1743
1554
|
|
1744
|
-
#
|
1745
|
-
# comparison of self with other for equality
|
1746
|
-
# takes into account the values expressed by self and other and the
|
1747
|
-
# equality of the number of digits.
|
1748
|
-
#
|
1749
|
-
def ==(other)
|
1750
|
-
# (other.kind_of? LongDecimal) && (self <=> other) == 0 && self.scale == other.scale
|
1751
|
-
(other.kind_of? LongDecimal) && self.int_val == other.int_val && self.scale == other.scale
|
1752
|
-
end
|
1753
|
-
|
1754
|
-
#
|
1755
|
-
# check if the number expressed by self is 0 (zero)
|
1756
|
-
# with any number of 0s after the decimal point.
|
1757
|
-
#
|
1758
|
-
def zero?
|
1759
|
-
int_val.zero?
|
1760
|
-
end
|
1761
|
-
|
1762
|
-
#
|
1763
|
-
# check if the number expressed by self is 1 (one)
|
1764
|
-
# with any number of 0s after the decimal point.
|
1765
|
-
#
|
1766
|
-
def one?
|
1767
|
-
(self-1).zero?
|
1768
|
-
end
|
1769
|
-
|
1770
1555
|
#
|
1771
1556
|
# Returns a hash code for the complex number.
|
1772
1557
|
#
|
1773
1558
|
def hash
|
1774
|
-
|
1559
|
+
rat.hash ^ scale.hash
|
1775
1560
|
end
|
1776
1561
|
|
1562
|
+
|
1777
1563
|
#
|
1778
|
-
# Returns "<tt>
|
1564
|
+
# Returns "<tt>LongDecimalQuot(<i>int_val</i>, <i>scale</i>, <i>num</i>, <i>denom</i>)</tt>".
|
1779
1565
|
#
|
1780
1566
|
def inspect
|
1781
|
-
sprintf("
|
1567
|
+
sprintf("LongDecimalQuot(Rational(%s, %s), %s)", numerator.inspect, denominator.inspect, scale.inspect)
|
1782
1568
|
end
|
1783
1569
|
|
1784
|
-
end #
|
1570
|
+
end # LongDecimalQuot
|
1785
1571
|
|
1786
1572
|
#
|
1787
|
-
#
|
1788
|
-
# performed a division. The division cannot be completed without
|
1789
|
-
# providing additional information on how to round the result.
|
1573
|
+
# Creates a LongDecimal number. +a+ and +b+ should be Numeric.
|
1790
1574
|
#
|
1791
|
-
|
1575
|
+
def LongDecimal(a, b = 0)
|
1576
|
+
if b == 0 && (a.kind_of? LongDecimal) then
|
1577
|
+
a
|
1578
|
+
else
|
1579
|
+
LongDecimal.new!(a, b)
|
1580
|
+
end
|
1581
|
+
end
|
1792
1582
|
|
1793
|
-
|
1583
|
+
#
|
1584
|
+
# construct a LongDecimalQuot from the given parameters
|
1585
|
+
# 1st case: both are LongDecimals
|
1586
|
+
# 2nd case: first is Rational, second is scale
|
1587
|
+
#
|
1588
|
+
def LongDecimalQuot(first, second)
|
1589
|
+
LongDecimalQuot.new!(first, second)
|
1590
|
+
end
|
1794
1591
|
|
1795
|
-
include LongDecimalRoundingMode
|
1796
1592
|
|
1797
|
-
|
1798
|
-
# constructor
|
1799
|
-
# first, second is either a pair of LongDecimals or a Rational and an Integer
|
1800
|
-
# The resulting LongDecimal will contain a rational obtained by
|
1801
|
-
# dividing the two LongDecimals or by taking the Rational as it is.
|
1802
|
-
# The scale is there to provide a default rounding precision for
|
1803
|
-
# conversion to LongDecimal, but it has no influence on the value
|
1804
|
-
# expressed by the LongDecimalQuot
|
1805
|
-
#
|
1806
|
-
def LongDecimalQuot.new!(first, second)
|
1807
|
-
new(first, second)
|
1808
|
-
end
|
1593
|
+
class Numeric
|
1809
1594
|
|
1810
1595
|
#
|
1811
|
-
#
|
1812
|
-
# pair of LongDecimals
|
1596
|
+
# convert self to LongDecimal
|
1813
1597
|
#
|
1814
|
-
def
|
1815
|
-
|
1816
|
-
@rat = Rational(first.numerator, first.denominator)
|
1817
|
-
@scale = second
|
1818
|
-
elsif (first.kind_of? LongDecimal) && (second.kind_of? LongDecimal) then
|
1819
|
-
orig_scale = first.scale
|
1820
|
-
first, second = first.anti_equalize_scale(second)
|
1821
|
-
@rat = Rational(first.to_i, second.to_i)
|
1822
|
-
@scale = orig_scale
|
1823
|
-
else
|
1824
|
-
raise TypeError, "parameters must be (LongDecimal, LongDecimal) or (Rational, Integer): first=#{first.inspect} second=#{second.inspect}";
|
1825
|
-
end
|
1598
|
+
def to_ld
|
1599
|
+
LongDecimal(self)
|
1826
1600
|
end
|
1827
1601
|
|
1828
|
-
|
1602
|
+
end # Numeric
|
1603
|
+
|
1604
|
+
#
|
1605
|
+
# LongMath provides some helper functions to support LongDecimal and
|
1606
|
+
# LongDecimalQuot, mostly operating on integers. They are used
|
1607
|
+
# internally here, but possibly they can be used elsewhere as well.
|
1608
|
+
# In addition LongMath provides methods like those in Math, but for
|
1609
|
+
# LongDecimal instead of Float.
|
1610
|
+
#
|
1611
|
+
module LongMath
|
1829
1612
|
|
1830
|
-
|
1831
|
-
# @scale
|
1832
|
-
# end
|
1613
|
+
include LongDecimalRoundingMode
|
1833
1614
|
|
1834
|
-
|
1835
|
-
|
1836
|
-
|
1615
|
+
MAX_FLOATABLE = Float::MAX.to_i
|
1616
|
+
MAX_EXP_ABLE = Math.log(MAX_FLOATABLE).to_i
|
1617
|
+
LOG2 = Math.log(2.0)
|
1618
|
+
LOG10 = Math.log(10.0)
|
1837
1619
|
|
1838
1620
|
#
|
1839
|
-
#
|
1840
|
-
#
|
1621
|
+
# helper method for internal use: checks if word_len is a reasonable
|
1622
|
+
# size for splitting a number into parts
|
1841
1623
|
#
|
1842
|
-
def
|
1843
|
-
|
1624
|
+
def LongMath.check_word_len(word_len, name="word_len")
|
1625
|
+
raise TypeError, "#{name} must be a positive number <= 1024" unless (word_len.kind_of? Fixnum) && word_len > 0 && word_len <= 1024
|
1626
|
+
word_len
|
1844
1627
|
end
|
1845
1628
|
|
1846
1629
|
#
|
1847
|
-
#
|
1848
|
-
# LongDecimals should duck type like Rationals
|
1630
|
+
# helper method for internal use: checks if parameter x is an Integer
|
1849
1631
|
#
|
1850
|
-
def
|
1851
|
-
|
1632
|
+
def LongMath.check_is_int(x, name="x")
|
1633
|
+
raise TypeError, "#{name}=#{x.inspect} must be Integer" unless x.kind_of? Integer
|
1852
1634
|
end
|
1853
1635
|
|
1854
1636
|
#
|
1855
|
-
#
|
1637
|
+
# helper method for internal use: checks if parameter x is a LongDecimal
|
1856
1638
|
#
|
1857
|
-
def
|
1858
|
-
raise TypeError, "
|
1859
|
-
raise TypeError, "negative arg \"#{s.inspect}\"" if s < 0
|
1860
|
-
@scale = s
|
1639
|
+
def LongMath.check_is_ld(x, name="x")
|
1640
|
+
raise TypeError, "x=#{x.inspect} must be LongDecimal" unless x.kind_of? LongDecimal
|
1861
1641
|
end
|
1862
1642
|
|
1863
|
-
private :scale=
|
1864
|
-
|
1865
1643
|
#
|
1866
|
-
#
|
1644
|
+
# helper method for internal use: checks if parameter x is a
|
1645
|
+
# reasonable value for the precision (scale) of a LongDecimal
|
1867
1646
|
#
|
1868
|
-
def
|
1869
|
-
|
1870
|
-
|
1647
|
+
def LongMath.check_is_prec(prec, name="prec")
|
1648
|
+
check_is_int(prec, "prec")
|
1649
|
+
raise TypeError, "#{name}=#{prec.inspect} must be >= 0" unless prec >= 0
|
1871
1650
|
end
|
1872
1651
|
|
1873
1652
|
#
|
1874
|
-
#
|
1653
|
+
# helper method for internal use: checks if parameter x is a
|
1654
|
+
# rounding mode (instance of RoundingModeClass)
|
1875
1655
|
#
|
1876
|
-
def
|
1877
|
-
|
1656
|
+
def LongMath.check_is_mode(mode, name="mode")
|
1657
|
+
raise TypeError, "#{name}=#{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
|
1878
1658
|
end
|
1879
1659
|
|
1880
1660
|
#
|
1881
|
-
#
|
1661
|
+
# split number (Integer) x into parts of word_len bits each such
|
1662
|
+
# that the concatenation of these parts as bit patterns is x
|
1663
|
+
# (the opposite of merge_from_words)
|
1882
1664
|
#
|
1883
|
-
def
|
1884
|
-
|
1665
|
+
def LongMath.split_to_words(x, word_len = 32)
|
1666
|
+
check_word_len(word_len)
|
1667
|
+
check_is_int(x, "x")
|
1668
|
+
m = x.abs
|
1669
|
+
s = (x <=> 0)
|
1670
|
+
bit_pattern = (1 << word_len) - 1
|
1671
|
+
words = []
|
1672
|
+
while (m != 0 || words.length == 0) do
|
1673
|
+
w = m & bit_pattern
|
1674
|
+
m = m >> word_len
|
1675
|
+
words.unshift(w)
|
1676
|
+
end
|
1677
|
+
if (s < 0) then
|
1678
|
+
words[0] = -words[0]
|
1679
|
+
end
|
1680
|
+
words
|
1885
1681
|
end
|
1886
1682
|
|
1887
1683
|
#
|
1888
|
-
#
|
1684
|
+
# concatenate numbers given in words as bit patterns
|
1685
|
+
# (the opposite of split_to_words)
|
1889
1686
|
#
|
1890
|
-
def
|
1891
|
-
|
1687
|
+
def LongMath.merge_from_words(words, word_len = 32)
|
1688
|
+
check_word_len(word_len)
|
1689
|
+
raise TypeError, "words must be array of length > 0" unless (words.kind_of? Array) && words.length > 0
|
1690
|
+
y = 0
|
1691
|
+
s = (words[0] <=> 0)
|
1692
|
+
if (s < 0) then
|
1693
|
+
words[0] = -words[0]
|
1694
|
+
end
|
1695
|
+
words.each do |w|
|
1696
|
+
y = y << word_len
|
1697
|
+
y += w
|
1698
|
+
end
|
1699
|
+
if (s < 0) then
|
1700
|
+
y = -y
|
1701
|
+
end
|
1702
|
+
y
|
1892
1703
|
end
|
1893
1704
|
|
1894
1705
|
#
|
1895
|
-
|
1706
|
+
|
1707
|
+
# calculate the square root of an integer x using bitwise algorithm
|
1708
|
+
# the result is rounded to an integer y such that
|
1709
|
+
# y**2�<=�x�<�(y+1)**2
|
1896
1710
|
#
|
1897
|
-
def
|
1898
|
-
|
1711
|
+
def LongMath.sqrtb(x)
|
1712
|
+
a = sqrtb_with_remainder(x)
|
1713
|
+
a[0]
|
1899
1714
|
end
|
1900
1715
|
|
1901
1716
|
#
|
1902
|
-
|
1717
|
+
#�calculate�the�an�integer�s�>=�0�and�a�remainder�r�>=�0�such�that
|
1718
|
+
#�x�=�s**2�+�r�and�s**2�<=�x�<�(s+1)**2
|
1719
|
+
# the bitwise algorithm is used, which works well for relatively
|
1720
|
+
# small values of x.
|
1903
1721
|
#
|
1904
|
-
def
|
1905
|
-
|
1722
|
+
def LongMath.sqrtb_with_remainder(x)
|
1723
|
+
check_is_int(x, "x")
|
1724
|
+
|
1725
|
+
s = (x <=> 0)
|
1726
|
+
if (s == 0) then
|
1727
|
+
return [0, 0]
|
1728
|
+
elsif (s < 0)
|
1729
|
+
a = sqrtb_with_remainder(-x)
|
1730
|
+
return [ Complex(0, a[0]), a[1]]
|
1731
|
+
end
|
1732
|
+
|
1733
|
+
xwords = split_to_words(x, 2)
|
1734
|
+
xi = xwords[0] - 1
|
1735
|
+
yi = 1
|
1736
|
+
|
1737
|
+
1.upto(xwords.length-1) do |i|
|
1738
|
+
xi = (xi << 2) + xwords[i]
|
1739
|
+
d0 = (yi << 2) + 1
|
1740
|
+
r = xi - d0
|
1741
|
+
b = 0
|
1742
|
+
if (r >= 0) then
|
1743
|
+
b = 1
|
1744
|
+
xi = r
|
1745
|
+
end
|
1746
|
+
yi = (yi << 1) + b
|
1747
|
+
end
|
1748
|
+
return [yi, xi]
|
1906
1749
|
end
|
1907
1750
|
|
1908
1751
|
#
|
1909
|
-
|
1910
|
-
#
|
1752
|
+
|
1753
|
+
# calculate the square root of an integer using larger chunks of the
|
1754
|
+
# number. The optional parameter n provides the size of these
|
1755
|
+
# chunks. It is by default chosen to be 16, which is optimized for
|
1756
|
+
# 32 bit systems, because internally parts of the double size are
|
1757
|
+
# used.
|
1758
|
+
# the result is rounded to an integer y such that
|
1759
|
+
# y**2�<=�x�<�(y+1)**2
|
1911
1760
|
#
|
1912
|
-
def
|
1913
|
-
|
1914
|
-
|
1915
|
-
else
|
1916
|
-
LongDecimalQuot(-rat, scale)
|
1917
|
-
end
|
1761
|
+
def LongMath.sqrtw(x, n = 16)
|
1762
|
+
a = sqrtw_with_remainder(x, n)
|
1763
|
+
a[0]
|
1918
1764
|
end
|
1919
1765
|
|
1920
1766
|
#
|
1921
|
-
#
|
1922
|
-
|
1923
|
-
#
|
1924
|
-
#
|
1767
|
+
# calculate the an integer s >= 0 and a remainder r >= 0 such that
|
1768
|
+
#�x�=�s**2�+�r�and�s**2�<=�x�<�(s+1)**2
|
1769
|
+
# the wordwise algorithm is used, which works well for relatively
|
1770
|
+
# large values of x. n defines the word size to be used for the
|
1771
|
+
# algorithm. It is good to use half of the machine word, but the
|
1772
|
+
# algorithm would also work for other values.
|
1925
1773
|
#
|
1926
|
-
def
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1774
|
+
def LongMath.sqrtw_with_remainder(x, n = 16)
|
1775
|
+
check_is_int(x, "x")
|
1776
|
+
check_is_int(n, "n")
|
1777
|
+
n2 = n<<1
|
1778
|
+
n1 = n+1
|
1779
|
+
check_word_len(n2, "2*n")
|
1780
|
+
|
1781
|
+
s = (x <=> 0)
|
1782
|
+
if (s == 0) then
|
1783
|
+
return [0, 0]
|
1784
|
+
elsif (s < 0)
|
1785
|
+
a = sqrtw_with_remainder(-x)
|
1786
|
+
return [ Complex(0, a[0]), a[1]]
|
1932
1787
|
end
|
1933
|
-
end
|
1934
1788
|
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
LongDecimalQuot(s.rat - o.rat, [s.scale, o.scale].max)
|
1939
|
-
else
|
1940
|
-
s - o
|
1789
|
+
xwords = split_to_words(x, n2)
|
1790
|
+
if (xwords.length == 1) then
|
1791
|
+
return sqrtb_with_remainder(xwords[0])
|
1941
1792
|
end
|
1942
|
-
end
|
1943
1793
|
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1794
|
+
# puts(xwords.inspect + "\n")
|
1795
|
+
xi = (xwords[0] << n2) + xwords[1]
|
1796
|
+
a = sqrtb_with_remainder(xi)
|
1797
|
+
yi = a[0]
|
1798
|
+
if (xwords.length <= 2) then
|
1799
|
+
return a
|
1800
|
+
end
|
1801
|
+
|
1802
|
+
xi -= yi*yi
|
1803
|
+
2.upto(xwords.length-1) do |i|
|
1804
|
+
xi = (xi << n2) + xwords[i]
|
1805
|
+
d0 = (yi << n1)
|
1806
|
+
q = (xi / d0).to_i
|
1807
|
+
q0 = q
|
1808
|
+
j = 0
|
1809
|
+
was_negative = false
|
1810
|
+
while (true) do
|
1811
|
+
d = d0 + q
|
1812
|
+
r = xi - (q * d)
|
1813
|
+
break if (0 <= r && (r < d || was_negative))
|
1814
|
+
# puts("i=#{i} j=#{j} q=#{q} d0=#{d0} d=#{d} r=#{r} yi=#{yi} xi=#{xi}\n")
|
1815
|
+
if (r < 0) then
|
1816
|
+
was_negative = true
|
1817
|
+
q = q-1
|
1818
|
+
else
|
1819
|
+
q = q+1
|
1820
|
+
end
|
1821
|
+
j += 1
|
1822
|
+
if (j > 10) then
|
1823
|
+
# puts("i=#{i} j=#{j} q=#{q} q0=#{q0} d0=#{d0} d=#{d} r=#{r} yi=#{yi} xi=#{xi}\n")
|
1824
|
+
break
|
1825
|
+
end
|
1826
|
+
end
|
1827
|
+
xi = r
|
1828
|
+
yi = (yi << n) + q
|
1950
1829
|
end
|
1830
|
+
return [ yi, xi ]
|
1951
1831
|
end
|
1952
1832
|
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
|
1958
|
-
|
1833
|
+
#
|
1834
|
+
|
1835
|
+
# find the gcd of an Integer x with b**n0 where n0 is a sufficiently
|
1836
|
+
# high exponent
|
1837
|
+
# such that gcd(x, b**m) = gcd(x, b**n) for all m, n >= n0
|
1838
|
+
#
|
1839
|
+
def LongMath.gcd_with_high_power(x, b)
|
1840
|
+
check_is_int(x, "x")
|
1841
|
+
raise ZeroDivisionError, "gcd_with_high_power of zero with \"#{b.inspect}\" would be infinity" if x.zero?
|
1842
|
+
check_is_int(b, "b")
|
1843
|
+
raise ZeroDivisionError, "gcd_with_high_power with b < 2 is not defined. b=\"#{b.inspect}\"" if b < 2
|
1844
|
+
s = x.abs
|
1845
|
+
exponent = 1
|
1846
|
+
b = b.abs
|
1847
|
+
if (b < s && s < MAX_FLOATABLE)
|
1848
|
+
exponent = (Math.log(s) / Math.log(b)).ceil
|
1959
1849
|
end
|
1850
|
+
power = b**exponent
|
1851
|
+
result = 1
|
1852
|
+
begin
|
1853
|
+
f = s.gcd(power)
|
1854
|
+
s /= f
|
1855
|
+
result *= f
|
1856
|
+
end while f > 1
|
1857
|
+
result
|
1960
1858
|
end
|
1961
1859
|
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1965
|
-
|
1860
|
+
#
|
1861
|
+
# Find the exponent of the highest power of prime number p that divides
|
1862
|
+
# the Integer x. Only works for prime numbers p (parameter prime_number).
|
1863
|
+
# The caller has to make sure that p (parameter prime_number) is
|
1864
|
+
# actually a prime number, because checks for primality actually cost
|
1865
|
+
# something and should not be duplicated more than necessary.
|
1866
|
+
# This method works even for numbers x that exceed the range of Float
|
1867
|
+
#
|
1868
|
+
def LongMath.multiplicity_of_factor(x, prime_number)
|
1869
|
+
|
1870
|
+
if (x.kind_of? Rational) || (x.kind_of? LongDecimalQuot) then
|
1871
|
+
m1 = multiplicity_of_factor(x.numerator, prime_number)
|
1872
|
+
m2 = multiplicity_of_factor(x.denominator, prime_number)
|
1873
|
+
return m1 - m2
|
1874
|
+
|
1875
|
+
elsif (x.kind_of? LongDecimal)
|
1876
|
+
m1 = multiplicity_of_factor(x.numerator, prime_number)
|
1877
|
+
if (prime_number == 2 || prime_number == 5) then
|
1878
|
+
return m1 - x.scale
|
1966
1879
|
else
|
1967
|
-
|
1880
|
+
return m1
|
1968
1881
|
end
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1882
|
+
|
1883
|
+
elsif (x.kind_of? Integer)
|
1884
|
+
|
1885
|
+
power = gcd_with_high_power(x, prime_number)
|
1886
|
+
if (power.abs < MAX_FLOATABLE) then
|
1887
|
+
result = (Math.log(power) / Math.log(prime_number)).round
|
1974
1888
|
else
|
1975
|
-
|
1889
|
+
e = (Math.log(MAX_FLOATABLE) / Math.log(prime_number)).floor
|
1890
|
+
result = 0
|
1891
|
+
partial = prime_number ** e
|
1892
|
+
while (power > partial) do
|
1893
|
+
power /= partial
|
1894
|
+
result += e
|
1895
|
+
end
|
1896
|
+
result += (Math.log(power) / Math.log(prime_number)).round
|
1976
1897
|
end
|
1977
|
-
|
1898
|
+
return result
|
1978
1899
|
else
|
1979
|
-
|
1900
|
+
raise TypeError, "type of x is not supported #{x.class} #{x.inpect}"
|
1980
1901
|
end
|
1981
1902
|
end
|
1982
1903
|
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1904
|
+
#
|
1905
|
+
# method for calculating pi to the given number of digits after the
|
1906
|
+
# decimal point.
|
1907
|
+
# It works fine for 1000 or 2000 digits or so.
|
1908
|
+
# This method could be optimized more, but if you really want to go
|
1909
|
+
# for more digits, you will find a specialized and optimized program
|
1910
|
+
# for this specific purpose, probably written in C or C++.
|
1911
|
+
# Since calculation of pi is not what should typically be done with
|
1912
|
+
# LongDecimal, you may consider this method to be the easter egg of
|
1913
|
+
# LongDecimal. ;-)
|
1914
|
+
#
|
1915
|
+
def LongMath.calc_pi(prec, final_mode = LongDecimal::ROUND_HALF_DOWN)
|
1916
|
+
mode = LongDecimal::ROUND_HALF_DOWN
|
1917
|
+
iprec = 5*(prec+1)
|
1918
|
+
sprec = (iprec >> 1) + 1
|
1919
|
+
dprec = (prec+1) << 1
|
1990
1920
|
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1921
|
+
a = LongDecimal(1)
|
1922
|
+
b = (1 / LongDecimal(2).sqrt(iprec,mode)).round_to_scale(iprec, mode)
|
1923
|
+
c = LongDecimal(5,1)
|
1924
|
+
k = 1
|
1925
|
+
pow_k = 2
|
1995
1926
|
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
# LongDecimalQuot(s.rat % o.rat, scale)
|
2000
|
-
# else
|
2001
|
-
# s % o
|
2002
|
-
# end
|
2003
|
-
# end
|
1927
|
+
pi = 0
|
1928
|
+
last_pi = 0
|
1929
|
+
last_diff = 1
|
2004
1930
|
|
2005
|
-
|
2006
|
-
|
1931
|
+
loop do
|
1932
|
+
a, b = ((a + b) / 2).round_to_scale(sprec, mode), (a * b).round_to_scale(iprec, mode).sqrt(sprec, mode)
|
1933
|
+
c = (c - pow_k * (a * a - b * b)).round_to_scale(iprec, mode)
|
1934
|
+
pi = (2 * a * a / c).round_to_scale(sprec, mode)
|
1935
|
+
diff = (pi - last_pi).round_to_scale(dprec, mode).abs
|
1936
|
+
if (diff.zero? && last_diff.zero?) then
|
1937
|
+
break
|
1938
|
+
end
|
1939
|
+
last_pi = pi
|
1940
|
+
last_diff = diff
|
1941
|
+
k += 1
|
1942
|
+
pow_k = pow_k << 1
|
1943
|
+
# puts("k=#{k} pi=#{pi.to_s}\nd=#{diff}\n\n")
|
1944
|
+
end
|
1945
|
+
pi.round_to_scale(prec, final_mode)
|
2007
1946
|
end
|
2008
1947
|
|
2009
1948
|
#
|
2010
|
-
#
|
1949
|
+
# calc the exponential function of x to the given precision as
|
1950
|
+
# LongDecimal. Only supports values of x such that the result still
|
1951
|
+
# fits into a float (x <= 709). This limitation is somewhat
|
1952
|
+
# arbitrary, but it is enforced in order to avoid producing numbers
|
1953
|
+
# with the exponential function that exceed the memory. It may be
|
1954
|
+
# removed in future versions.
|
2011
1955
|
#
|
2012
|
-
def
|
2013
|
-
|
1956
|
+
def LongMath.exp(x, prec, mode = LongDecimal::ROUND_HALF_DOWN)
|
1957
|
+
check_is_ld(x, "x")
|
1958
|
+
raise TypeError, "x=#{x.inspect} must not be greater #{MAX_EXP_ABLE}" unless x <= MAX_EXP_ABLE
|
1959
|
+
check_is_prec(prec, "prec")
|
1960
|
+
check_is_mode(mode, "mode")
|
1961
|
+
exp_internal(x, prec, mode)
|
2014
1962
|
end
|
2015
1963
|
|
2016
1964
|
#
|
2017
|
-
#
|
1965
|
+
# private helper method for exponentiation
|
1966
|
+
# calculate internal precision
|
2018
1967
|
#
|
2019
|
-
def
|
2020
|
-
|
1968
|
+
def LongMath.calc_iprec_for_exp(x, prec)
|
1969
|
+
iprec_extra = 0
|
1970
|
+
if (x > 1) then
|
1971
|
+
xf = x.to_f
|
1972
|
+
iprec_extra = (xf / LOG10).abs
|
1973
|
+
end
|
1974
|
+
iprec = ((prec+10)*1.20 + iprec_extra).round
|
1975
|
+
if (iprec < prec) then
|
1976
|
+
iprec = prec
|
1977
|
+
end
|
1978
|
+
# puts("calc_iprec_for_exp: x=#{x} prec=#{prec} iprec=#{iprec} iprec_extra=#{iprec_extra}\n")
|
1979
|
+
iprec
|
2021
1980
|
end
|
2022
1981
|
|
2023
|
-
|
2024
|
-
self.abs.square
|
2025
|
-
end
|
1982
|
+
# private :calc_iprec_for_exp
|
2026
1983
|
|
2027
1984
|
#
|
2028
|
-
#
|
2029
|
-
#
|
1985
|
+
# internal functionality of exp. exposes some more parameters, that
|
1986
|
+
# should usually be set to defaut values, in order to allow better testing.
|
1987
|
+
# do not actually call this method unless you are testing exp.
|
1988
|
+
# create a bug report, if the default settings for the parameters do
|
1989
|
+
# not work correctly
|
2030
1990
|
#
|
2031
|
-
def
|
1991
|
+
def LongMath.exp_internal(x, prec = nil, final_mode = LongDecimal::ROUND_HALF_DOWN, j = nil, k = nil, iprec = nil, mode = LongDecimal::ROUND_HALF_DOWN)
|
1992
|
+
check_is_ld(x, "x")
|
1993
|
+
if (prec == nil) then
|
1994
|
+
prec = x.scale
|
1995
|
+
end
|
1996
|
+
check_is_prec(prec, "prec")
|
2032
1997
|
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
1998
|
+
if (final_mode == nil)
|
1999
|
+
final_mode = LongDecimal::ROUND_HALF_DOWN
|
2000
|
+
end
|
2001
|
+
check_is_mode(final_mode, "final_mode")
|
2002
|
+
check_is_mode(mode, "mode")
|
2036
2003
|
|
2037
|
-
|
2038
|
-
|
2039
|
-
if
|
2040
|
-
return LongDecimal(
|
2004
|
+
# if the result would come out to zero anyway, cut the work
|
2005
|
+
xi = x.to_i
|
2006
|
+
if (xi < -LongMath::MAX_FLOATABLE) || -((xi.to_f - 1) / LOG10) > prec+1 then
|
2007
|
+
return LongDecimal(25, prec+2).round_to_scale(prec, final_mode)
|
2041
2008
|
end
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2009
|
+
|
2010
|
+
if j == nil || k == nil then
|
2011
|
+
s1 = (prec * LOG10 / LOG2) ** (1.0/3.0)
|
2012
|
+
if (j == nil) then
|
2013
|
+
j = s1.round
|
2014
|
+
end
|
2015
|
+
if (k == nil) then
|
2016
|
+
k = (s1 + Math.log([1, prec].max) / LOG2).round
|
2017
|
+
end
|
2018
|
+
if (x > 1) then
|
2019
|
+
k += (Math.log(x.to_f) / LOG2).abs.round
|
2020
|
+
end
|
2048
2021
|
end
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
raise Error, "signs do not match self=#{self.to_s} f=#{factor} prod=#{prod} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem >= 0
|
2022
|
+
if (j <= 0) then
|
2023
|
+
j = 1
|
2024
|
+
end
|
2025
|
+
if (k < 0) then
|
2026
|
+
k = 0
|
2055
2027
|
end
|
2028
|
+
check_is_int(j, "j")
|
2029
|
+
check_is_int(k, "k")
|
2056
2030
|
|
2057
|
-
if
|
2058
|
-
|
2031
|
+
if (iprec == nil) then
|
2032
|
+
iprec = calc_iprec_for_exp(x, prec)
|
2059
2033
|
end
|
2034
|
+
check_is_prec(iprec, "iprec")
|
2035
|
+
# puts("exp_internal: x=#{x} prec=#{prec} iprec=#{iprec}\n")
|
2060
2036
|
|
2061
|
-
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2069
|
-
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
|
2074
|
-
# half == 0
|
2075
|
-
if (mode == ROUND_HALF_UP) then
|
2076
|
-
mode = ROUND_UP
|
2077
|
-
elsif (mode == ROUND_HALF_DOWN) then
|
2078
|
-
mode = ROUND_DOWN
|
2079
|
-
else
|
2080
|
-
# mode == ROUND_HALF_EVEN
|
2081
|
-
mode = (quot[0] == 1 ? ROUND_UP : ROUND_DOWN)
|
2082
|
-
end
|
2083
|
-
end
|
2037
|
+
dprec = [ iprec, (prec + 1) << 1 ].min
|
2038
|
+
|
2039
|
+
x_k = (x / (1 << k)).round_to_scale(iprec, mode)
|
2040
|
+
x_j = (x_k ** j).round_to_scale(iprec, mode)
|
2041
|
+
s = [ LongDecimal(0) ] * j
|
2042
|
+
t = LongDecimal(1)
|
2043
|
+
last_t = 1
|
2044
|
+
f = 0
|
2045
|
+
loop do
|
2046
|
+
j.times do |i|
|
2047
|
+
s[i] += t
|
2048
|
+
f += 1
|
2049
|
+
t = (t / f).round_to_scale(iprec, mode)
|
2084
2050
|
end
|
2051
|
+
t = (t * x_j).round_to_scale(iprec, mode)
|
2052
|
+
break if (t.zero?)
|
2053
|
+
tr = t.round_to_scale(dprec, LongDecimal::ROUND_DOWN).abs
|
2054
|
+
break if (t.zero?)
|
2055
|
+
tu = t.unit
|
2056
|
+
break if (tr <= tu && last_t <= tu)
|
2057
|
+
last_t = tr
|
2085
2058
|
end
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2059
|
+
x_i = 1
|
2060
|
+
y_k = LongDecimal(0)
|
2061
|
+
j.times do |i|
|
2062
|
+
if (i > 0) then
|
2063
|
+
x_i = (x_i * x_k).round_to_scale(iprec, mode)
|
2064
|
+
end
|
2065
|
+
# puts("y_k=#{y_k}\ni=#{i} j=#{j} k=#{k} x=#{x}\nx_k=#{x_k}\nx_j=#{x_j}\nx_i=#{x_i}\ns[i]=#{s[i]}\n\n")
|
2066
|
+
y_k += (s[i] * x_i).round_to_scale(iprec, mode)
|
2089
2067
|
end
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
#
|
2095
|
-
# prepare binary operation of other with LongDecimalQuot
|
2096
|
-
# Integer, LongDecimal, Rational and LongDecimalQuot can be
|
2097
|
-
# expressed as LongDecimalQuot, using the scale of self in case of
|
2098
|
-
# Integer and Rational. Floats can be approximated by LongDecimals
|
2099
|
-
# and thus be expressed as LongDecimalQuot
|
2100
|
-
# In case of BigDecimal, Complex or any unknown type, convert self
|
2101
|
-
# to BigDecimal or Float.
|
2102
|
-
#
|
2103
|
-
def coerce(other)
|
2104
|
-
if other.kind_of? LongDecimal then
|
2105
|
-
return LongDecimalQuot(other.to_r, other.scale), self
|
2106
|
-
elsif other.kind_of? LongDecimalQuot then
|
2107
|
-
return other, self
|
2108
|
-
elsif other.kind_of? Rational then
|
2109
|
-
s = scale
|
2110
|
-
return LongDecimalQuot(other, s), self
|
2111
|
-
elsif (other.kind_of? Integer) then
|
2112
|
-
return LongDecimalQuot(other.to_r, scale), self
|
2113
|
-
elsif other.kind_of? Float then
|
2114
|
-
return LongDecimalQuot(other.to_ld.to_r, scale), self
|
2115
|
-
elsif other.kind_of? BigDecimal then
|
2116
|
-
s, o = other.coerce(self.to_bd)
|
2117
|
-
elsif other.kind_of? Numeric then
|
2118
|
-
s, o = other.coerce(self.to_f)
|
2119
|
-
return o, s
|
2120
|
-
else
|
2121
|
-
raise TypeError, "unsupported type #{other.inspect} for coerce of LongDecimalQuot"
|
2068
|
+
# puts("y_k = #{y_k}\n")
|
2069
|
+
k.times do |i|
|
2070
|
+
y_k = y_k.square.round_to_scale(iprec, mode)
|
2071
|
+
# puts("i=#{i} y_k = #{y_k}\n")
|
2122
2072
|
end
|
2073
|
+
y = y_k.round_to_scale(prec, final_mode)
|
2074
|
+
y
|
2123
2075
|
end
|
2124
2076
|
|
2125
2077
|
#
|
2126
|
-
#
|
2127
|
-
#
|
2128
|
-
# other is also LongDecimalQuot, expresses the same value and has the
|
2129
|
-
# same scale.
|
2130
|
-
# It needs to be observed that scale does not influence the value expressed
|
2131
|
-
# by the number, but only how rouding is performed by default if no
|
2132
|
-
# explicit number of digits after the decimal point is given. But
|
2133
|
-
# scale needs to match for equality.
|
2078
|
+
# calculate the natural logarithm function of x to the given precision as
|
2079
|
+
# LongDecimal.
|
2134
2080
|
#
|
2135
|
-
def
|
2136
|
-
(
|
2081
|
+
def LongMath.log(x, prec, mode = LongDecimal::ROUND_HALF_DOWN)
|
2082
|
+
check_is_ld(x, "x")
|
2083
|
+
check_is_prec(prec, "prec")
|
2084
|
+
check_is_mode(mode, "mode")
|
2085
|
+
log_internal(x, prec, mode)
|
2137
2086
|
end
|
2138
2087
|
|
2139
2088
|
#
|
2140
|
-
#
|
2089
|
+
# calculate the base 10 logarithm of x to the given precision as
|
2090
|
+
# LongDecimal.
|
2141
2091
|
#
|
2142
|
-
def
|
2143
|
-
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
diff <=> 0
|
2092
|
+
def LongMath.log10(x, prec, mode = LongDecimal::ROUND_HALF_DOWN)
|
2093
|
+
check_is_ld(x, "x")
|
2094
|
+
check_is_prec(prec, "prec")
|
2095
|
+
if (x.one?) then
|
2096
|
+
return LongDecimal.zero!(prec)
|
2148
2097
|
end
|
2098
|
+
check_is_mode(mode, "mode")
|
2099
|
+
iprec = prec + 2
|
2100
|
+
id = x.int_digits10
|
2101
|
+
xx = x.move_point_left(id)
|
2102
|
+
# puts("x=#{x} xx=#{xx} id=#{id} iprec=#{iprec}\n")
|
2103
|
+
lnxx = log_internal(xx, iprec, mode)
|
2104
|
+
ln10 = log_internal(10.to_ld, iprec, mode)
|
2105
|
+
y = id + (lnxx / ln10).round_to_scale(prec, mode)
|
2106
|
+
return y
|
2149
2107
|
end
|
2150
2108
|
|
2151
2109
|
#
|
2152
|
-
#
|
2110
|
+
# calculate the base 2 logarithm of x to the given precision as
|
2111
|
+
# LongDecimal.
|
2153
2112
|
#
|
2154
|
-
def
|
2155
|
-
|
2156
|
-
|
2113
|
+
def LongMath.log2(x, prec, mode = LongDecimal::ROUND_HALF_DOWN)
|
2114
|
+
check_is_ld(x, "x")
|
2115
|
+
check_is_prec(prec, "prec")
|
2116
|
+
if (x.one?) then
|
2117
|
+
return LongDecimal.zero!(prec)
|
2118
|
+
end
|
2119
|
+
check_is_mode(mode, "mode")
|
2120
|
+
iprec = prec + 2
|
2121
|
+
id = x.int_digits2
|
2122
|
+
xx = (x / (1 << id)).round_to_scale(x.scale+id)
|
2123
|
+
# puts("x=#{x} xx=#{xx} id=#{id} iprec=#{iprec}\n")
|
2124
|
+
lnxx = log_internal(xx, iprec, mode)
|
2125
|
+
ln2 = log_internal(2.to_ld, iprec, mode)
|
2126
|
+
y = id + (lnxx / ln2).round_to_scale(prec, mode)
|
2127
|
+
return y
|
2157
2128
|
end
|
2158
2129
|
|
2159
2130
|
#
|
2160
|
-
#
|
2131
|
+
# internal functionality of log. exposes some more parameters, that
|
2132
|
+
# should usually be set to defaut values, in order to allow better testing.
|
2133
|
+
# do not actually call this method unless you are testing log.
|
2134
|
+
# create a bug report, if the default settings for the parameters do
|
2135
|
+
# not work correctly
|
2161
2136
|
#
|
2162
|
-
def
|
2163
|
-
|
2164
|
-
|
2137
|
+
def LongMath.log_internal(x, prec = nil, final_mode = LongDecimal::ROUND_HALF_DOWN, iprec = nil, mode = LongDecimal::ROUND_HALF_DOWN)
|
2138
|
+
check_is_ld(x)
|
2139
|
+
raise TypeError, "x=#{x.inspect} must not be positive" unless x > 0
|
2140
|
+
if (prec == nil) then
|
2141
|
+
prec = x.scale
|
2142
|
+
end
|
2143
|
+
check_is_prec(prec, "prec")
|
2144
|
+
if (x.one?) then
|
2145
|
+
return LongDecimal.zero!(prec)
|
2146
|
+
end
|
2165
2147
|
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
2170
|
-
|
2171
|
-
end
|
2148
|
+
if (final_mode == nil)
|
2149
|
+
final_mode = LongDecimal::ROUND_HALF_DOWN
|
2150
|
+
end
|
2151
|
+
check_is_mode(final_mode, "final_mode")
|
2152
|
+
check_is_mode(mode, "mode")
|
2172
2153
|
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
alias sign sgn
|
2154
|
+
if (iprec == nil) then
|
2155
|
+
iprec = ((prec+10)*1.20).round
|
2156
|
+
end
|
2157
|
+
if (iprec < prec) then
|
2158
|
+
iprec = prec
|
2159
|
+
end
|
2160
|
+
check_is_prec(iprec, "iprec")
|
2181
2161
|
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2162
|
+
# dprec = [ iprec - 1, (prec + 1) << 1 ].min
|
2163
|
+
dprec = iprec - 1
|
2164
|
+
|
2165
|
+
y = 0
|
2166
|
+
s = 1
|
2167
|
+
if (x < 1) then
|
2168
|
+
# puts("x=#{x} iprec=#{iprec}\n")
|
2169
|
+
x = (1 / x).round_to_scale(iprec, mode)
|
2170
|
+
s = -1
|
2171
|
+
# puts("s=#{s} x=#{x} iprec=#{iprec}\n")
|
2172
|
+
end
|
2173
|
+
exp_part = 0
|
2174
|
+
estimate = 0
|
2175
|
+
while (x > MAX_FLOATABLE) do
|
2176
|
+
if (exp_part == 0) then
|
2177
|
+
estimate = MAX_EXP_ABLE.to_ld
|
2178
|
+
exp_part = exp(estimate, iprec)
|
2179
|
+
end
|
2180
|
+
x = (x / exp_part).round_to_scale(iprec, mode)
|
2181
|
+
if (s < 0) then
|
2182
|
+
y -= estimate
|
2183
|
+
else
|
2184
|
+
y += estimate
|
2185
|
+
end
|
2186
|
+
end
|
2188
2187
|
|
2188
|
+
delta = LongDecimal(1, 3)
|
2189
|
+
while (x - 1).abs > delta do
|
2190
|
+
# puts("too far from 1: x=#{x}\n")
|
2191
|
+
xf = x.to_f
|
2192
|
+
# puts("xf=#{xf}\n")
|
2193
|
+
mlx = Math.log(xf)
|
2194
|
+
# puts("log(xf)=#{mlx}\n")
|
2195
|
+
estimate = mlx.to_ld.round_to_scale(20, mode)
|
2196
|
+
exp_part = exp(estimate, iprec << 1)
|
2197
|
+
# puts("y=#{y} s=#{s} est=#{estimate} part=#{exp_part} x=#{x}\n")
|
2198
|
+
x = (x / exp_part).round_to_scale(iprec, mode)
|
2199
|
+
# puts("divided by exp_part=#{exp_part}: #{x}\n")
|
2200
|
+
if (s < 0) then
|
2201
|
+
y -= estimate
|
2202
|
+
else
|
2203
|
+
y += estimate
|
2204
|
+
end
|
2205
|
+
# puts("y=#{y} s=#{s} est=#{estimate} part=#{exp_part} x=#{x}\n")
|
2206
|
+
end
|
2189
2207
|
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2208
|
+
factor = 1
|
2209
|
+
# delta = LongDecimal(1, (iprec.to_f**(1/3)).round)
|
2210
|
+
# while (x - 1).abs > delta do
|
2211
|
+
# x = sqrt(x)
|
2212
|
+
# factor *= 2
|
2213
|
+
# end
|
2196
2214
|
|
2197
|
-
|
2215
|
+
sum = 0
|
2216
|
+
z = 1 - x
|
2217
|
+
i = 1
|
2218
|
+
p = 1.to_ld
|
2219
|
+
d = 1.to_ld
|
2220
|
+
until p.abs.round_to_scale(dprec, LongDecimal::ROUND_DOWN).zero? do
|
2221
|
+
p = (p * z).round_to_scale(iprec, mode)
|
2222
|
+
d = (p / i).round_to_scale(iprec, mode)
|
2223
|
+
i += 1
|
2224
|
+
sum += d
|
2198
2225
|
|
2199
|
-
#
|
2200
|
-
|
2201
|
-
#
|
2202
|
-
def LongDecimal(a, b = 0)
|
2203
|
-
if b == 0 && (a.kind_of? LongDecimal) then
|
2204
|
-
a
|
2205
|
-
else
|
2206
|
-
LongDecimal.new!(a, b)
|
2207
|
-
end
|
2208
|
-
end
|
2226
|
+
# puts("log_internal: s=#{sum} d=#{d} x=#{x} i=#{i} p=#{p} iprec=#{iprec} dprec=#{dprec}\n") if (i & 0x0f == 0x0f)
|
2227
|
+
end
|
2209
2228
|
|
2210
|
-
#
|
2211
|
-
|
2212
|
-
#
|
2213
|
-
|
2214
|
-
#
|
2215
|
-
def LongDecimalQuot(first, second)
|
2216
|
-
LongDecimalQuot.new!(first, second)
|
2217
|
-
end
|
2229
|
+
# puts("y=#{y} s=#{s} f=#{factor} sum=#{sum}\n")
|
2230
|
+
y -= ((s * factor) * sum).round_to_scale(iprec, mode)
|
2231
|
+
# puts("y=#{y} s=#{s} f=#{factor} sum=#{sum}\n")
|
2232
|
+
return y.round_to_scale(prec, final_mode)
|
2218
2233
|
|
2234
|
+
end
|
2219
2235
|
|
2220
|
-
|
2236
|
+
#
|
2237
|
+
# calc the power of x with exponent y to the given precision as
|
2238
|
+
# LongDecimal. Only supports values of y such that exp(y) still
|
2239
|
+
# fits into a float (y <= 709)
|
2240
|
+
#
|
2241
|
+
def LongMath.power(x, y, prec, mode = LongDecimal::ROUND_HALF_DOWN)
|
2242
|
+
check_is_ld(x, "x")
|
2243
|
+
check_is_ld(y, "y")
|
2244
|
+
raise TypeError, "y=#{y.inspect} must not be greater #{MAX_EXP_ABLE}" unless y <= MAX_EXP_ABLE
|
2245
|
+
raise TypeError, "x=#{x.inspect} must not be greater #{MAX_FLOATABLE}" unless x <= MAX_FLOATABLE
|
2246
|
+
raise TypeError, "x=#{x.inspect} must not positive" unless x > 0
|
2247
|
+
check_is_prec(prec, "prec")
|
2248
|
+
check_is_mode(mode, "mode")
|
2249
|
+
LongMath.power_internal(x, y, prec, mode)
|
2250
|
+
end
|
2221
2251
|
|
2222
2252
|
#
|
2223
|
-
#
|
2253
|
+
# internal functionality of exp. exposes some more parameters, that
|
2254
|
+
# should usually be set to defaut values, in order to allow better testing.
|
2255
|
+
# do not actually call this method unless you are testing exp.
|
2256
|
+
# create a bug report, if the default settings for the parameters do
|
2257
|
+
# not work correctly
|
2224
2258
|
#
|
2225
|
-
def
|
2226
|
-
|
2259
|
+
def LongMath.power_internal(x, y, prec = nil, final_mode = LongDecimal::ROUND_HALF_DOWN, iprec = nil, mode = LongDecimal::ROUND_HALF_DOWN)
|
2260
|
+
check_is_ld(x, "x")
|
2261
|
+
if (prec == nil) then
|
2262
|
+
prec = x.scale
|
2263
|
+
end
|
2264
|
+
check_is_prec(prec, "prec")
|
2265
|
+
|
2266
|
+
if (final_mode == nil)
|
2267
|
+
final_mode = LongDecimal::ROUND_HALF_DOWN
|
2268
|
+
end
|
2269
|
+
check_is_mode(final_mode, "final_mode")
|
2270
|
+
check_is_mode(mode, "mode")
|
2271
|
+
|
2272
|
+
logx_y_f = Math.log(x.to_f) * (y.to_f)
|
2273
|
+
|
2274
|
+
# iprec = (prec * 1.2 + 20 + (y.abs.to_f) * 1.5 * x.int_digits2).round
|
2275
|
+
if (iprec == nil) then
|
2276
|
+
iprec = calc_iprec_for_exp(logx_y_f, prec) + 2
|
2277
|
+
end
|
2278
|
+
# puts("power_internal: x=#{x} y=#{y} logx_y=#{logx_y_f} iprec=#{iprec} prec=#{prec}\n")
|
2279
|
+
logx = log(x, iprec, mode)
|
2280
|
+
logx_y = logx*y
|
2281
|
+
xy = exp_internal(logx_y, prec + 1, mode)
|
2282
|
+
# puts("power_internal: x=#{x} logx=#{logx} y=#{y} logx_y=#{logx_y} xy=#{xy} iprec=#{iprec} prec=#{prec}\n")
|
2283
|
+
xy.round_to_scale(prec, final_mode)
|
2227
2284
|
end
|
2228
2285
|
|
2229
|
-
end #
|
2286
|
+
end # LongMath
|
2230
2287
|
|
2231
2288
|
# end of file long-decimal.rb
|