long-decimal 0.02.01 → 1.00.01
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 +7 -16
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/install.rb +1 -1
- data/lib/long-decimal-extra.rb +623 -72
- data/lib/long-decimal.rb +716 -223
- data/make_doc.rb +1 -1
- data/test/testlongdecimal-extra.rb +1101 -9
- data/test/testlongdecimal-performance.rb +357 -0
- data/test/testlongdecimal.rb +509 -76
- data/test/testlongdeclib.rb +94 -43
- data/test/testrandlib.rb +1 -1
- data/test/testrandom-extra.rb +5 -3
- data/test/testrandom.rb +5 -3
- data/test/testrandpower.rb +5 -3
- data/version.rb +4 -2
- metadata +28 -18
data/README
CHANGED
@@ -1,25 +1,15 @@
|
|
1
1
|
Version
|
2
2
|
-------
|
3
3
|
|
4
|
-
This version ($Name:
|
4
|
+
This version ($Name: RELEASE_1_00_01 $) is similar to the previous beta-0.02.01
|
5
5
|
|
6
6
|
Improvements over the previous version:
|
7
7
|
|
8
|
-
-
|
9
|
-
- workaround for a bug in JRuby's Fixnum-multiplication, which has
|
10
|
-
been fixed for the next JRuby-version, but not for the existing installed base.
|
11
|
-
- calculation of powers with exponents having huge magnitude and with
|
12
|
-
bases close to 1 works better now.
|
13
|
-
- new method initialize_copy needed for clone()
|
14
|
-
- new method cbrt (cubic root)
|
15
|
-
- improved to_f which works better near Float::MAX
|
16
|
-
- new Method LongMath.log_f to obtain a Float-Approximation of the log
|
17
|
-
of a LongDecimal
|
18
|
-
- more and improved runit-Tests
|
8
|
+
- better rubydoc
|
19
9
|
|
20
10
|
All this functionality did not show any bugs during intensive
|
21
11
|
testing, so it could be assumed that the whole library is good for
|
22
|
-
|
12
|
+
for production/stable.
|
23
13
|
|
24
14
|
This software development effort is hosted on RubyForge (
|
25
15
|
http://rubyforge.org/ ) under the project name "long-decimal", to be
|
@@ -123,7 +113,7 @@ $ cd /tmp
|
|
123
113
|
$ wget http://rubyforge.org/frs/download.php/6461/crypt-isaac_0.9.1.gem
|
124
114
|
$ su -l
|
125
115
|
# cd /tmp
|
126
|
-
# gem install
|
116
|
+
# gem install crypt-isaac
|
127
117
|
(you may need to adjust the URL for downloading the gem)
|
128
118
|
|
129
119
|
.... and then go into the directory, where the gem is
|
@@ -254,11 +244,12 @@ Find copies of these licenses on http://www.gnu.org/ or http://www.ruby-lang.org
|
|
254
244
|
Warranty
|
255
245
|
--------
|
256
246
|
|
257
|
-
This is
|
247
|
+
This is free software and it comes with absolutely no warranty.
|
248
|
+
Tests indicate that most functions work
|
258
249
|
relyably in all situations and all functions work relyably in most
|
259
250
|
situations. But do not expect too much! This is work in progress! I
|
260
251
|
do not take any responsibility. Please use it as it is, change it
|
261
|
-
according to the terms of the license or wait for a
|
252
|
+
according to the terms of the license or wait for a future
|
262
253
|
version (for which I can't take any warranty either...)
|
263
254
|
|
264
255
|
Author
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2009
|
5
5
|
#
|
6
6
|
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/Rakefile,v 1.4 2009/04/15 19:29:37 bk1 Exp $
|
7
|
-
# CVS-Label: $Name:
|
7
|
+
# CVS-Label: $Name: RELEASE_1_00_01 $
|
8
8
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
9
9
|
#
|
10
10
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.00.01
|
data/install.rb
CHANGED
data/lib/long-decimal-extra.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
#
|
4
4
|
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2009
|
5
5
|
#
|
6
|
-
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal-extra.rb,v 1.
|
7
|
-
# CVS-Label: $Name:
|
6
|
+
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal-extra.rb,v 1.26 2011/01/16 18:12:50 bk1 Exp $
|
7
|
+
# CVS-Label: $Name: RELEASE_1_00_00 $
|
8
8
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
9
9
|
#
|
10
10
|
require "complex"
|
@@ -15,34 +15,266 @@ require "bigdecimal"
|
|
15
15
|
|
16
16
|
# require "bigdecimal/math"
|
17
17
|
|
18
|
-
class
|
19
|
-
alias :to_g :to_f
|
18
|
+
class LongDecimal
|
20
19
|
|
21
|
-
|
20
|
+
# timer for performance measurements
|
21
|
+
def ts(i)
|
22
|
+
@timer ||= []
|
23
|
+
@timer[i] = Time.now
|
24
|
+
end
|
22
25
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
26
|
+
def te(i)
|
27
|
+
@@tt ||= []
|
28
|
+
@@tt[i] ||= 0
|
29
|
+
@@tt[i] += Time.now - @timer[i]
|
30
|
+
@@tc ||= []
|
31
|
+
@@tc[i] ||= 0
|
32
|
+
@@tc[i] += 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def tt(i)
|
36
|
+
@@tt ||= []
|
37
|
+
@@tt[i] ||= 0
|
38
|
+
@@tc ||= []
|
39
|
+
@@tc[i] ||= 0
|
40
|
+
if (@@tc[i] == 0)
|
41
|
+
@@tt[i]
|
42
|
+
else
|
43
|
+
@@tc[i].to_s + ":" + @@tt[i].to_s + ":" + (@@tt[i]/@@tc[i]).to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# create copy of self with different scale
|
49
|
+
# param1: new_scale new scale for result
|
50
|
+
# param2: mode rounding mode to be applied when information is
|
51
|
+
# lost. defaults to ROUND_UNNECESSARY, which
|
52
|
+
# means that an exception is thrown if rounding
|
53
|
+
# would actually loose any information.
|
54
|
+
#
|
55
|
+
def round_to_scale2(new_scale, mode = ROUND_UNNECESSARY)
|
56
|
+
|
57
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
58
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
59
|
+
raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
|
60
|
+
if @scale == new_scale then
|
61
|
+
self
|
62
|
+
else
|
63
|
+
ts 16
|
64
|
+
diff = new_scale - scale
|
65
|
+
factor = LongMath.npower10(diff.abs)
|
66
|
+
te 16
|
67
|
+
if (diff > 0) then
|
68
|
+
# we become more precise, no rounding issues
|
69
|
+
ts 17
|
70
|
+
new_int_val = int_val * factor
|
71
|
+
te 17
|
72
|
+
else
|
73
|
+
ts 18
|
74
|
+
quot, rem = int_val.divmod(factor)
|
75
|
+
te 18
|
76
|
+
if (rem == 0) then
|
77
|
+
new_int_val = quot
|
78
|
+
elsif (mode == ROUND_UNNECESSARY) then
|
79
|
+
raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
|
80
|
+
else
|
81
|
+
ts 19
|
82
|
+
sign_self = sign
|
83
|
+
|
84
|
+
if (sign_self < 0) then
|
85
|
+
# handle negative sign of self
|
86
|
+
rem -= divisor
|
87
|
+
quot += 1
|
88
|
+
end
|
89
|
+
sign_rem = rem <=> 0
|
90
|
+
raise Error, "signs do not match self=#{self.to_s} f=#{factor} divisor=#{divisor} rem=#{rem}" if sign_rem >= 0 && sign_self < 0
|
91
|
+
|
92
|
+
if (mode == ROUND_CEILING)
|
93
|
+
# ROUND_CEILING goes to the closest allowed number >= self, even
|
94
|
+
# for negative numbers. Since sign is handled separately, it is
|
95
|
+
# more conveniant to use ROUND_UP or ROUND_DOWN depending on the
|
96
|
+
# sign.
|
97
|
+
mode = (sign_self > 0) ? ROUND_UP : ROUND_DOWN
|
98
|
+
|
99
|
+
elsif (mode == ROUND_FLOOR)
|
100
|
+
# ROUND_FLOOR goes to the closest allowed number <= self, even
|
101
|
+
# for negative numbers. Since sign is handled separately, it is
|
102
|
+
# more conveniant to use ROUND_UP or ROUND_DOWN depending on the
|
103
|
+
# sign.
|
104
|
+
mode = (sign_self < 0) ? ROUND_UP : ROUND_DOWN
|
105
|
+
else
|
106
|
+
if (mode == ROUND_HALF_CEILING)
|
107
|
+
# ROUND_HALF_CEILING goes to the closest allowed number >= self, even
|
108
|
+
# for negative numbers. Since sign is handled separately, it is
|
109
|
+
# more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
|
110
|
+
# sign.
|
111
|
+
mode = (sign_self > 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
|
112
|
+
|
113
|
+
elsif (mode == ROUND_HALF_FLOOR)
|
114
|
+
# ROUND_HALF_FLOOR goes to the closest allowed number <= self, even
|
115
|
+
# for negative numbers. Since sign is handled separately, it is
|
116
|
+
# more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
|
117
|
+
# sign.
|
118
|
+
mode = (sign_self < 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
# handle the ROUND_HALF_... stuff and find the adequate ROUND_UP
|
123
|
+
# or ROUND_DOWN to use
|
124
|
+
abs_rem = rem.abs
|
125
|
+
half = (abs_rem << 1) <=> denominator
|
126
|
+
if (mode == ROUND_HALF_UP || mode == ROUND_HALF_DOWN || mode == ROUND_HALF_EVEN) then
|
127
|
+
if (half < 0) then
|
128
|
+
mode = ROUND_DOWN
|
129
|
+
elsif half > 0 then
|
130
|
+
mode = ROUND_UP
|
131
|
+
else
|
132
|
+
# half == 0
|
133
|
+
if (mode == ROUND_HALF_UP) then
|
134
|
+
mode = ROUND_UP
|
135
|
+
elsif (mode == ROUND_HALF_DOWN) then
|
136
|
+
mode = ROUND_DOWN
|
137
|
+
else
|
138
|
+
# mode == ROUND_HALF_EVEN
|
139
|
+
mode = (quot[0] == 1 ? ROUND_UP : ROUND_DOWN)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if mode == ROUND_UP
|
146
|
+
# since the case where we can express the result exactly without
|
147
|
+
# loss has already been handled above, ROUND_UP can be handled
|
148
|
+
# correctly by adding one unit.
|
149
|
+
quot += sign_self
|
150
|
+
end
|
151
|
+
|
152
|
+
# put together result
|
153
|
+
new_int_val = quot
|
154
|
+
te 19
|
155
|
+
end
|
39
156
|
end
|
157
|
+
ts 20
|
158
|
+
y = LongDecimal(new_int_val, new_scale)
|
159
|
+
te 20
|
160
|
+
return y
|
40
161
|
end
|
41
|
-
return numerator.to_f / denominator.to_f
|
42
162
|
end
|
43
|
-
end
|
44
163
|
|
45
|
-
|
164
|
+
#
|
165
|
+
# number of decimal digits before the decimal point, not counting a
|
166
|
+
# single 0. negative value, if some zeros follow immediately after
|
167
|
+
# decimal point
|
168
|
+
#
|
169
|
+
# 0.000x -> -3
|
170
|
+
# 0.00x -> -2
|
171
|
+
# 0.0xx -> -1
|
172
|
+
# 0.xxx -> 0
|
173
|
+
# 1.xxx -> 1
|
174
|
+
# 10.xxx -> 2
|
175
|
+
# 99.xxx -> 2
|
176
|
+
# 100.xxx -> 3
|
177
|
+
# ...
|
178
|
+
# second implementation
|
179
|
+
#
|
180
|
+
def sint_digits10_2
|
181
|
+
if zero?
|
182
|
+
return -scale
|
183
|
+
else
|
184
|
+
n = numerator.abs
|
185
|
+
d = denominator
|
186
|
+
i = 0
|
187
|
+
if (n < d)
|
188
|
+
i = (d.size - i.size + 1.size) * 53 / 22
|
189
|
+
n *= LongMath.npower10(i)
|
190
|
+
if (n < d)
|
191
|
+
raise ArgumentError, "still not working well: n=#{n} d=#{d} i=#{i} self=#{self}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
return LongMath.int_digits10(n/d) - i
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# number of decimal digits before the decimal point, not counting a
|
200
|
+
# single 0. negative value, if some zeros follow immediately after
|
201
|
+
# decimal point
|
202
|
+
#
|
203
|
+
# 0.000x -> -3
|
204
|
+
# 0.00x -> -2
|
205
|
+
# 0.0xx -> -1
|
206
|
+
# 0.xxx -> 0
|
207
|
+
# 1.xxx -> 1
|
208
|
+
# 10.xxx -> 2
|
209
|
+
# 99.xxx -> 2
|
210
|
+
# 100.xxx -> 3
|
211
|
+
# ...
|
212
|
+
# third implementation
|
213
|
+
#
|
214
|
+
def sint_digits10_3
|
215
|
+
if zero?
|
216
|
+
return -scale
|
217
|
+
else
|
218
|
+
l = LongMath.log10(self.abs, 0, LongDecimal::ROUND_HALF_FLOOR).to_i
|
219
|
+
f = LongMath.npower10(l + scale)
|
220
|
+
if (f > int_val.abs)
|
221
|
+
l -= 1
|
222
|
+
end
|
223
|
+
return l.to_i + 1
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# number of decimal digits before the decimal point, not counting a
|
229
|
+
# single 0. negative value, if some zeros follow immediately after
|
230
|
+
# decimal point
|
231
|
+
#
|
232
|
+
# 0.000x -> -3
|
233
|
+
# 0.00x -> -2
|
234
|
+
# 0.0xx -> -1
|
235
|
+
# 0.xxx -> 0
|
236
|
+
# 1.xxx -> 1
|
237
|
+
# 10.xxx -> 2
|
238
|
+
# 99.xxx -> 2
|
239
|
+
# 100.xxx -> 3
|
240
|
+
# ...
|
241
|
+
# forth implementation (for evaluation of algorithms only, will be removed again)
|
242
|
+
#
|
243
|
+
def sint_digits10_4
|
244
|
+
if zero?
|
245
|
+
return -scale
|
246
|
+
else
|
247
|
+
prec_limit = LongMath.prec_limit
|
248
|
+
LongMath.prec_limit = LongMath::MAX_PREC
|
249
|
+
n = numerator.abs
|
250
|
+
s = 0
|
251
|
+
imax = LongMath::POWERS_BIG_EXP_LIMIT
|
252
|
+
puts "imax=#{imax}"
|
253
|
+
fmax = LongMath.npower10(imax)
|
254
|
+
puts "fmax: #{fmax.size}"
|
255
|
+
imin = 0
|
256
|
+
fmin = 1
|
257
|
+
while n > fmax
|
258
|
+
n /= fmax
|
259
|
+
s += imax
|
260
|
+
end
|
261
|
+
# 1 <= n < 10**imax
|
262
|
+
while (imin + 1 < imax)
|
263
|
+
# 10**imin <= n < 10**imax
|
264
|
+
imed = (imin + imax)/2
|
265
|
+
fmed = LongMath.npower10(imed)
|
266
|
+
if (n < fmed)
|
267
|
+
imax = imed
|
268
|
+
fmax = fmed
|
269
|
+
else
|
270
|
+
imin = imed
|
271
|
+
fmin = fmed
|
272
|
+
end
|
273
|
+
end
|
274
|
+
LongMath.prec_limit = prec_limit
|
275
|
+
return s + imin - scale + 1
|
276
|
+
end
|
277
|
+
end
|
46
278
|
|
47
279
|
#
|
48
280
|
# convert self into Float
|
@@ -52,69 +284,56 @@ class LongDecimal
|
|
52
284
|
# representation otherwise.
|
53
285
|
#
|
54
286
|
def to_g
|
287
|
+
|
288
|
+
# make sure we do not have to deal with negative sign beyond this point
|
289
|
+
if (self < 0) then
|
290
|
+
return -(-self).to_f
|
291
|
+
end
|
292
|
+
|
55
293
|
# handle overflow: raise exception
|
56
|
-
if (self
|
294
|
+
if (self > LongMath::MAX_FLOATABLE) then
|
57
295
|
raise ArgumentError, "self=#{self.inspect} cannot be expressed as Float"
|
58
296
|
end
|
59
297
|
|
60
298
|
# handle underflow: return 0.0
|
61
|
-
if (self
|
62
|
-
puts "-> 0.0"
|
299
|
+
if (self < LongMath::MIN_FLOATABLE) then
|
63
300
|
return 0.0
|
64
301
|
end
|
65
302
|
|
66
|
-
if (self < 0) then
|
67
|
-
puts "-> negate"
|
68
|
-
return -(-self).to_g
|
69
|
-
end
|
70
|
-
|
71
303
|
dividend = numerator
|
72
304
|
divisor = denominator
|
73
305
|
|
74
306
|
if (divisor == 1) then
|
75
|
-
puts "-> /1"
|
76
307
|
return dividend.to_f
|
77
|
-
elsif dividend
|
78
|
-
|
79
|
-
|
80
|
-
puts "-> divisor > MAX_FLOATABLE"
|
81
|
-
qe = scale - Float::MAX_10_EXP
|
82
|
-
q = 10**qe
|
83
|
-
puts "-> q=#{q}"
|
308
|
+
elsif dividend <= LongMath::MAX_FLOATABLE then
|
309
|
+
if (divisor > LongMath::MAX_FLOATABLE) then
|
310
|
+
q = LongMath.npower10(scale - Float::MAX_10_EXP)
|
84
311
|
f = (dividend / q).to_f
|
85
|
-
puts "-> f=#{f}"
|
86
312
|
d = LongMath::MAX_FLOATABLE10
|
87
|
-
|
88
|
-
y = f / d
|
89
|
-
puts "-> y=#{y}"
|
90
|
-
return y
|
313
|
+
return f / d
|
91
314
|
else
|
92
|
-
puts "-> divisor <= MAX_FLOATABLE"
|
93
315
|
f = dividend.to_f
|
94
316
|
return f / divisor
|
95
317
|
end
|
96
|
-
elsif dividend
|
97
|
-
|
98
|
-
#
|
99
|
-
|
100
|
-
# factor = dividend.abs.div(LongMath::MAX_FLOATABLE)
|
101
|
-
# digits = factor.to_ld.int_digits10
|
102
|
-
# return LongDecimal(dividend.div(10**digits), scale -digits).to_f
|
318
|
+
elsif dividend < divisor
|
319
|
+
# self is between 0 and 1 and dividend > LongMath::MAX_FLOATABLE
|
320
|
+
# return LongDecimal(dividend.div(LongMath.npower10(digits)), scale -digits).to_f
|
321
|
+
# puts "via s (1): #{self.inspect}"
|
103
322
|
return self.to_s.to_f
|
104
323
|
else
|
105
|
-
puts "-> >= 1"
|
106
324
|
q = dividend.abs / divisor
|
107
325
|
if (q.abs > 1000000000000000000000)
|
108
|
-
puts "-> > 1000000000000000000000"
|
109
326
|
return q.to_f
|
110
327
|
else
|
111
|
-
puts "
|
328
|
+
# puts "via s (2): #{self.inspect}"
|
112
329
|
return self.to_s.to_f
|
113
330
|
end
|
114
331
|
end
|
115
332
|
end
|
333
|
+
|
116
334
|
end
|
117
335
|
|
336
|
+
|
118
337
|
#
|
119
338
|
# LongMath provides some helper functions to support LongDecimal and
|
120
339
|
# LongDecimalQuot, mostly operating on integers. They are used
|
@@ -123,7 +342,7 @@ end
|
|
123
342
|
# LongDecimal instead of Float.
|
124
343
|
#
|
125
344
|
module LongMath
|
126
|
-
|
345
|
+
|
127
346
|
#
|
128
347
|
# calc the base-2-exponential function of x to the given precision as
|
129
348
|
# LongDecimal. Only supports values of x such that the result still
|
@@ -152,7 +371,7 @@ module LongMath
|
|
152
371
|
#
|
153
372
|
def LongMath.log10(x, prec, mode = LongMath.standard_mode) # down?
|
154
373
|
|
155
|
-
check_is_prec(prec, "prec")
|
374
|
+
prec = check_is_prec(prec, "prec")
|
156
375
|
check_is_mode(mode, "mode")
|
157
376
|
iprec = prec + 6
|
158
377
|
unless (x.kind_of? LongDecimal)
|
@@ -176,7 +395,7 @@ module LongMath
|
|
176
395
|
#
|
177
396
|
def LongMath.log2(x, prec, mode = LongMath.standard_mode)
|
178
397
|
|
179
|
-
check_is_prec(prec, "prec")
|
398
|
+
prec = check_is_prec(prec, "prec")
|
180
399
|
check_is_mode(mode, "mode")
|
181
400
|
iprec = prec + 6
|
182
401
|
unless (x.kind_of? LongDecimal)
|
@@ -271,8 +490,9 @@ module LongMath
|
|
271
490
|
raise TypeError, "y=#{y.inspect} must not be greater #{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
|
272
491
|
raise TypeError, "y=#{y.inspect} must not be negative if base is zero}" if y < 0 && x.zero?
|
273
492
|
raise TypeError, "x=#{x.inspect} must not negative" unless x >= 0
|
274
|
-
check_is_prec(prec, "prec")
|
493
|
+
prec = check_is_prec(prec, "prec")
|
275
494
|
check_is_mode(mode, "mode")
|
495
|
+
puts "LongMath.power(x=#{x} y=#{y} prec=#{prec} mode=#{mode})"
|
276
496
|
|
277
497
|
# handle the special cases where base or exponent are 0 or 1 explicitely
|
278
498
|
if y.zero? then
|
@@ -289,10 +509,10 @@ module LongMath
|
|
289
509
|
# x ** y <= 10**-s/2 <=> y * log(x) <= -s log(10) - log(2)
|
290
510
|
|
291
511
|
iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
|
292
|
-
|
512
|
+
puts "x=#{x} y=#{y} prec=#{prec} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y} logx_y_f=#{logx_y_f}: checking x < 1 && y > 0 || x > 1 && y < 0=#{x < 1 && y > 0 || x > 1 && y < 0}"
|
293
513
|
$stdout.flush
|
294
514
|
if (x < 1 && y > 0 || x > 1 && y < 0) then
|
295
|
-
|
515
|
+
puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
|
296
516
|
if (logx_y_f <= - prec * LOG10 - LOG2) then
|
297
517
|
return LongDecimal.zero!(prec)
|
298
518
|
end
|
@@ -342,10 +562,10 @@ module LongMath
|
|
342
562
|
y = -y
|
343
563
|
x = (1/x).round_to_scale(iprec_x*2, mode)
|
344
564
|
iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
|
345
|
-
|
565
|
+
puts "x=#{x} y=#{y} prec=#{prec} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y} logx_y_f=#{logx_y_f}: checking x < 1 && y > 0 || x > 1 && y < 0=#{x < 1 && y > 0 || x > 1 && y < 0}"
|
346
566
|
$stdout.flush
|
347
567
|
if (x < 1 && y > 0 || x > 1 && y < 0) then
|
348
|
-
|
568
|
+
puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
|
349
569
|
if (logx_y_f <= - prec * LOG10 - LOG2) then
|
350
570
|
return LongDecimal.zero!(prec)
|
351
571
|
end
|
@@ -357,11 +577,15 @@ module LongMath
|
|
357
577
|
y0 = y.round_to_scale(0, LongMath.standard_imode).to_i
|
358
578
|
x0 = x
|
359
579
|
point_shift = 0
|
580
|
+
puts "x0=#{x0} y0=#{y0}"
|
360
581
|
while x0 > LongMath::MAX_FLOATABLE
|
361
582
|
x0 = x0.move_point_left(100)
|
362
583
|
point_shift += 100
|
363
584
|
end
|
364
|
-
|
585
|
+
iprec2 = 2 * (iprec + point_shift)
|
586
|
+
iprec3 = [ iprec2, LongMath.prec_limit() - 24 ].min
|
587
|
+
puts "x0=#{x0} y0=#{y0} point_shift=#{point_shift} iprec=#{iprec} iprec2=#{iprec2} iprec3=#{iprec3}"
|
588
|
+
z0 = LongMath.ipower(x0, y0, iprec3, mode)
|
365
589
|
if (point_shift > 0)
|
366
590
|
unless z0.kind_of? LongDecimal
|
367
591
|
z0 = z0.to_ld(2*(iprec + point_shift))
|
@@ -393,13 +617,14 @@ module LongMath
|
|
393
617
|
raise TypeError, "exponent y=#{y} must be integer" unless y.kind_of? Integer
|
394
618
|
raise TypeError, "base x=#{x.inspect} must not be greater MAX_FLOATABLE=#{MAX_FLOATABLE}" unless x.abs <= MAX_FLOATABLE
|
395
619
|
raise TypeError, "exponent y=#{y.inspect} must not be greater MAX_FLOATABLE=#{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
|
396
|
-
check_is_prec(prec, "prec")
|
620
|
+
prec = check_is_prec(prec, "prec")
|
397
621
|
check_is_mode(mode, "mode")
|
622
|
+
puts "LongMath.ipower(x=#{x} y=#{y} prec=#{prec} mode=#{mode})"
|
398
623
|
|
399
624
|
if (y.zero?)
|
400
625
|
return 1
|
401
626
|
elsif ! (x.kind_of? LongDecimalBase) || x.scale * y.abs <= prec
|
402
|
-
|
627
|
+
puts "x=#{x} y=#{y} using **"
|
403
628
|
return x ** y
|
404
629
|
elsif (y < 0)
|
405
630
|
l = Math.log10(x.abs.to_f)
|
@@ -408,12 +633,12 @@ module LongMath
|
|
408
633
|
end
|
409
634
|
# return (1/LongMath.ipower(x, -y, prec + 2, mode)).round_to_scale(prec, mode)
|
410
635
|
xi = 1/x
|
411
|
-
|
636
|
+
puts "x=#{x} y=#{y} prec=#{prec} using (1/x)**y xi=#{xi}"
|
412
637
|
xr = xi.round_to_scale(prec + 6, mode)
|
413
638
|
return LongMath.ipower(xr, -y, prec, mode)
|
414
639
|
else
|
415
640
|
# y > 0
|
416
|
-
|
641
|
+
puts "x=#{x} y=#{y} regular"
|
417
642
|
cnt = 0
|
418
643
|
z = x
|
419
644
|
y0 = y
|
@@ -439,7 +664,7 @@ module LongMath
|
|
439
664
|
end
|
440
665
|
|
441
666
|
end
|
442
|
-
z
|
667
|
+
z *= x
|
443
668
|
if (z.kind_of? LongDecimalBase)
|
444
669
|
z = z.round_to_scale(prec+3, mode)
|
445
670
|
if (z.zero?)
|
@@ -447,7 +672,9 @@ module LongMath
|
|
447
672
|
end
|
448
673
|
end
|
449
674
|
end
|
675
|
+
puts "z=#{z} rounding prec=#{prec}"
|
450
676
|
z = z.round_to_scale(prec, mode)
|
677
|
+
puts "rounded -> z=#{z}"
|
451
678
|
return z
|
452
679
|
end
|
453
680
|
end
|
@@ -464,7 +691,7 @@ module LongMath
|
|
464
691
|
raise TypeError, "exponent y=#{y} must be integer" unless y.kind_of? Integer
|
465
692
|
raise TypeError, "base x=#{x.inspect} must not be greater MAX_FLOATABLE=#{MAX_FLOATABLE}" unless x.abs <= MAX_FLOATABLE
|
466
693
|
raise TypeError, "exponent y=#{y.inspect} must not be greater MAX_FLOATABLE=#{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
|
467
|
-
check_is_prec(prec, "prec")
|
694
|
+
prec = check_is_prec(prec, "prec")
|
468
695
|
check_is_mode(mode, "mode")
|
469
696
|
|
470
697
|
if (y.zero?)
|
@@ -534,7 +761,7 @@ module LongMath
|
|
534
761
|
raise ArgumentError, "precision must be supplied either as precision of x=#{x} or explicitely"
|
535
762
|
end
|
536
763
|
end
|
537
|
-
check_is_prec(prec, "prec")
|
764
|
+
prec = check_is_prec(prec, "prec")
|
538
765
|
|
539
766
|
if (final_mode.nil?)
|
540
767
|
final_mode = LongMath.standard_mode
|
@@ -570,6 +797,330 @@ module LongMath
|
|
570
797
|
|
571
798
|
end # power_internal
|
572
799
|
|
800
|
+
LOGARR = [ nil, \
|
801
|
+
0.0, \
|
802
|
+
1.0, \
|
803
|
+
1.58496250072116, \
|
804
|
+
2.0, \
|
805
|
+
2.32192809488736, \
|
806
|
+
2.58496250072116, \
|
807
|
+
2.8073549220576, \
|
808
|
+
3.0, \
|
809
|
+
3.16992500144231, \
|
810
|
+
3.32192809488736, \
|
811
|
+
3.4594316186373, \
|
812
|
+
3.58496250072116, \
|
813
|
+
3.70043971814109, \
|
814
|
+
3.8073549220576, \
|
815
|
+
3.90689059560852, \
|
816
|
+
4.0, \
|
817
|
+
4.08746284125034, \
|
818
|
+
4.16992500144231, \
|
819
|
+
4.24792751344359, \
|
820
|
+
4.32192809488736, \
|
821
|
+
4.39231742277876, \
|
822
|
+
4.4594316186373, \
|
823
|
+
4.52356195605701, \
|
824
|
+
4.58496250072116, \
|
825
|
+
4.64385618977472, \
|
826
|
+
4.70043971814109, \
|
827
|
+
4.75488750216347, \
|
828
|
+
4.8073549220576, \
|
829
|
+
4.85798099512757, \
|
830
|
+
4.90689059560852, \
|
831
|
+
4.95419631038688, \
|
832
|
+
5.0, \
|
833
|
+
5.04439411935845, \
|
834
|
+
5.08746284125034, \
|
835
|
+
5.12928301694497, \
|
836
|
+
5.16992500144231, \
|
837
|
+
5.20945336562895, \
|
838
|
+
5.24792751344359, \
|
839
|
+
5.28540221886225, \
|
840
|
+
5.32192809488736, \
|
841
|
+
5.35755200461808, \
|
842
|
+
5.39231742277876, \
|
843
|
+
5.4262647547021, \
|
844
|
+
5.4594316186373, \
|
845
|
+
5.49185309632967, \
|
846
|
+
5.52356195605701, \
|
847
|
+
5.55458885167764, \
|
848
|
+
5.58496250072116, \
|
849
|
+
5.61470984411521, \
|
850
|
+
5.64385618977472, \
|
851
|
+
5.6724253419715, \
|
852
|
+
5.70043971814109, \
|
853
|
+
5.7279204545632, \
|
854
|
+
5.75488750216347, \
|
855
|
+
5.78135971352466, \
|
856
|
+
5.8073549220576, \
|
857
|
+
5.83289001416474, \
|
858
|
+
5.85798099512757, \
|
859
|
+
5.88264304936184, \
|
860
|
+
5.90689059560852, \
|
861
|
+
5.93073733756289, \
|
862
|
+
5.95419631038688, \
|
863
|
+
5.97727992349992, \
|
864
|
+
6.0, \
|
865
|
+
6.02236781302845, \
|
866
|
+
6.04439411935845, \
|
867
|
+
6.06608919045777, \
|
868
|
+
6.08746284125034, \
|
869
|
+
6.10852445677817, \
|
870
|
+
6.12928301694497, \
|
871
|
+
6.14974711950468, \
|
872
|
+
6.16992500144231, \
|
873
|
+
6.18982455888002, \
|
874
|
+
6.20945336562895, \
|
875
|
+
6.22881869049588, \
|
876
|
+
6.24792751344359, \
|
877
|
+
6.2667865406949, \
|
878
|
+
6.28540221886225, \
|
879
|
+
6.3037807481771, \
|
880
|
+
6.32192809488736, \
|
881
|
+
6.33985000288463, \
|
882
|
+
6.35755200461808, \
|
883
|
+
6.37503943134693, \
|
884
|
+
6.39231742277876, \
|
885
|
+
6.4093909361377, \
|
886
|
+
6.4262647547021, \
|
887
|
+
6.44294349584873, \
|
888
|
+
6.4594316186373, \
|
889
|
+
6.4757334309664, \
|
890
|
+
6.49185309632967, \
|
891
|
+
6.5077946401987, \
|
892
|
+
6.52356195605701, \
|
893
|
+
6.53915881110803, \
|
894
|
+
6.55458885167764, \
|
895
|
+
6.56985560833095, \
|
896
|
+
6.58496250072116, \
|
897
|
+
6.59991284218713, \
|
898
|
+
6.61470984411521, \
|
899
|
+
6.62935662007961, \
|
900
|
+
6.64385618977473, \
|
901
|
+
6.6582114827518, \
|
902
|
+
6.6724253419715, \
|
903
|
+
6.68650052718322, \
|
904
|
+
6.70043971814109, \
|
905
|
+
6.71424551766612, \
|
906
|
+
6.7279204545632, \
|
907
|
+
6.74146698640115, \
|
908
|
+
6.75488750216347, \
|
909
|
+
6.76818432477693, \
|
910
|
+
6.78135971352466, \
|
911
|
+
6.79441586635011, \
|
912
|
+
6.8073549220576, \
|
913
|
+
6.82017896241519, \
|
914
|
+
6.83289001416474, \
|
915
|
+
6.84549005094438, \
|
916
|
+
6.85798099512757, \
|
917
|
+
6.8703647195834, \
|
918
|
+
6.88264304936184, \
|
919
|
+
6.89481776330794, \
|
920
|
+
6.90689059560852, \
|
921
|
+
6.9188632372746, \
|
922
|
+
6.93073733756289, \
|
923
|
+
6.94251450533924, \
|
924
|
+
6.95419631038688, \
|
925
|
+
6.96578428466209, \
|
926
|
+
6.97727992349992, \
|
927
|
+
6.98868468677217, \
|
928
|
+
7.0, \
|
929
|
+
7.01122725542325, \
|
930
|
+
7.02236781302845, \
|
931
|
+
7.03342300153745, \
|
932
|
+
7.04439411935845, \
|
933
|
+
7.05528243550119, \
|
934
|
+
7.06608919045777, \
|
935
|
+
7.07681559705083, \
|
936
|
+
7.08746284125034, \
|
937
|
+
7.09803208296053, \
|
938
|
+
7.10852445677817, \
|
939
|
+
7.11894107272351, \
|
940
|
+
7.12928301694497, \
|
941
|
+
7.13955135239879, \
|
942
|
+
7.14974711950468, \
|
943
|
+
7.15987133677839, \
|
944
|
+
7.16992500144231, \
|
945
|
+
7.17990909001493, \
|
946
|
+
7.18982455888002, \
|
947
|
+
7.19967234483636, \
|
948
|
+
7.20945336562895, \
|
949
|
+
7.21916852046216, \
|
950
|
+
7.22881869049588, \
|
951
|
+
7.23840473932508, \
|
952
|
+
7.24792751344359, \
|
953
|
+
7.25738784269265, \
|
954
|
+
7.2667865406949, \
|
955
|
+
7.27612440527424, \
|
956
|
+
7.28540221886225, \
|
957
|
+
7.29462074889163, \
|
958
|
+
7.3037807481771, \
|
959
|
+
7.31288295528436, \
|
960
|
+
7.32192809488736, \
|
961
|
+
7.33091687811462, \
|
962
|
+
7.33985000288462, \
|
963
|
+
7.34872815423108, \
|
964
|
+
7.35755200461808, \
|
965
|
+
7.36632221424582, \
|
966
|
+
7.37503943134693, \
|
967
|
+
7.38370429247405, \
|
968
|
+
7.39231742277876, \
|
969
|
+
7.40087943628218, \
|
970
|
+
7.4093909361377, \
|
971
|
+
7.4178525148859, \
|
972
|
+
7.4262647547021, \
|
973
|
+
7.43462822763673, \
|
974
|
+
7.44294349584873, \
|
975
|
+
7.45121111183233, \
|
976
|
+
7.4594316186373, \
|
977
|
+
7.467605550083, \
|
978
|
+
7.4757334309664, \
|
979
|
+
7.48381577726426, \
|
980
|
+
7.49185309632967, \
|
981
|
+
7.49984588708321, \
|
982
|
+
7.5077946401987, \
|
983
|
+
7.51569983828404, \
|
984
|
+
7.52356195605701, \
|
985
|
+
7.53138146051631, \
|
986
|
+
7.53915881110803, \
|
987
|
+
7.54689445988764, \
|
988
|
+
7.55458885167764, \
|
989
|
+
7.56224242422107, \
|
990
|
+
7.56985560833095, \
|
991
|
+
7.57742882803575, \
|
992
|
+
7.58496250072116, \
|
993
|
+
7.59245703726808, \
|
994
|
+
7.59991284218713, \
|
995
|
+
7.60733031374961, \
|
996
|
+
7.61470984411521, \
|
997
|
+
7.62205181945638, \
|
998
|
+
7.62935662007961, \
|
999
|
+
7.63662462054365, \
|
1000
|
+
7.64385618977472, \
|
1001
|
+
7.65105169117893, \
|
1002
|
+
7.6582114827518, \
|
1003
|
+
7.66533591718518, \
|
1004
|
+
7.6724253419715, \
|
1005
|
+
7.67948009950545, \
|
1006
|
+
7.68650052718322, \
|
1007
|
+
7.69348695749933, \
|
1008
|
+
7.70043971814109, \
|
1009
|
+
7.70735913208088, \
|
1010
|
+
7.71424551766612, \
|
1011
|
+
7.72109918870719, \
|
1012
|
+
7.7279204545632, \
|
1013
|
+
7.73470962022584, \
|
1014
|
+
7.74146698640115, \
|
1015
|
+
7.74819284958946, \
|
1016
|
+
7.75488750216347, \
|
1017
|
+
7.76155123244448, \
|
1018
|
+
7.76818432477693, \
|
1019
|
+
7.77478705960117, \
|
1020
|
+
7.78135971352466, \
|
1021
|
+
7.78790255939143, \
|
1022
|
+
7.79441586635011, \
|
1023
|
+
7.8008998999203, \
|
1024
|
+
7.8073549220576, \
|
1025
|
+
7.81378119121704, \
|
1026
|
+
7.82017896241519, \
|
1027
|
+
7.82654848729092, \
|
1028
|
+
7.83289001416474, \
|
1029
|
+
7.83920378809694, \
|
1030
|
+
7.84549005094438, \
|
1031
|
+
7.85174904141606, \
|
1032
|
+
7.85798099512757, \
|
1033
|
+
7.86418614465428, \
|
1034
|
+
7.8703647195834, \
|
1035
|
+
7.876516946565, \
|
1036
|
+
7.88264304936184, \
|
1037
|
+
7.88874324889826, \
|
1038
|
+
7.89481776330794, \
|
1039
|
+
7.90086680798075, \
|
1040
|
+
7.90689059560852, \
|
1041
|
+
7.91288933622996, \
|
1042
|
+
7.9188632372746, \
|
1043
|
+
7.92481250360578, \
|
1044
|
+
7.93073733756289, \
|
1045
|
+
7.93663793900257, \
|
1046
|
+
7.94251450533924, \
|
1047
|
+
7.94836723158468, \
|
1048
|
+
7.95419631038688, \
|
1049
|
+
7.96000193206808, \
|
1050
|
+
7.96578428466209, \
|
1051
|
+
7.97154355395077, \
|
1052
|
+
7.97727992349992, \
|
1053
|
+
7.98299357469431, \
|
1054
|
+
7.98868468677217, \
|
1055
|
+
7.99435343685886, \
|
1056
|
+
8.0 ]
|
1057
|
+
|
1058
|
+
def LongMath.log2int(x)
|
1059
|
+
unless x.kind_of? Integer
|
1060
|
+
raise TypeError, "x=#{x.inspect} must be Integer"
|
1061
|
+
end
|
1062
|
+
if (x <= 0)
|
1063
|
+
raise ArgumentError, "x=#{x} < 0"
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
s = x.size
|
1067
|
+
l = [ 8 * s - 36 , 0 ].max
|
1068
|
+
|
1069
|
+
xx = x >> l
|
1070
|
+
while xx >= 256
|
1071
|
+
l += 1
|
1072
|
+
xx = xx >> 1
|
1073
|
+
end
|
1074
|
+
yy = LOGARR[xx]
|
1075
|
+
y = l + yy
|
1076
|
+
y
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
# alternative calculations of sqrt using newtons algorithm
|
1080
|
+
def LongMath.sqrtn(x)
|
1081
|
+
check_is_int(x, "x")
|
1082
|
+
s = (x <=> 0)
|
1083
|
+
if (s == 0) then
|
1084
|
+
return 0;
|
1085
|
+
elsif (s == -1)
|
1086
|
+
raise ArgumentError, "x=#{x} is negative"
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
y = 1
|
1090
|
+
while (true)
|
1091
|
+
q = x/y
|
1092
|
+
if (q == y)
|
1093
|
+
return y
|
1094
|
+
end
|
1095
|
+
yn = (y + q) >> 1
|
1096
|
+
if (yn == y || yn == q)
|
1097
|
+
ym = x/yn
|
1098
|
+
y = [ yn, ym ].min
|
1099
|
+
puts "x=#{x} ym=#{ym} yn=#{yn}" if (y != yn)
|
1100
|
+
return y
|
1101
|
+
|
1102
|
+
end
|
1103
|
+
y = yn
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
573
1107
|
end # LongMath
|
574
1108
|
|
1109
|
+
# to be removed again, but needed now to investigate problems with ./usr/lib/ruby/1.8/rational.rb:547: warning: in a**b, b may be too big
|
1110
|
+
class Bignum
|
1111
|
+
|
1112
|
+
# Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
|
1113
|
+
def rpower(other)
|
1114
|
+
if other >= 0
|
1115
|
+
self.power!(other)
|
1116
|
+
else
|
1117
|
+
r = Rational.new!(self, 1)
|
1118
|
+
raise TypeError, "other=#{other} must be integer" unless other.kind_of? Integer
|
1119
|
+
raise ArgumentError, "other=#{other} must not be too big" unless other.abs < LongMath::MAX_FLOATABLE
|
1120
|
+
r ** other
|
1121
|
+
end
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
end
|
1125
|
+
|
575
1126
|
# end of file long-decimal-extra.rb
|