long-decimal 0.02.01 → 1.00.01
Sign up to get free protection for your applications and to get access to all the features.
- 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
|