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 CHANGED
@@ -1,25 +1,15 @@
1
1
  Version
2
2
  -------
3
3
 
4
- This version ($Name: BETA_02_01 $) is similar to the previous alpha-0.01.03.
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
- - full support for JRuby
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
- beta and possibly even quite soon for production/stable.
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 ruby-isaac
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 a beta-version. Tests indicate that most functions work
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 more stable
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: BETA_02_01 $
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
- 0.02.01
1
+ 1.00.01
data/install.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  #
4
4
  # CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/install.rb,v 1.3 2009/04/15 19:29:37 bk1 Exp $
5
- # CVS-Label: $Name: BETA_02_01 $
5
+ # CVS-Label: $Name: RELEASE_1_00_00 $
6
6
  # Author: $Author: bk1 $ (Karl Brodowsky)
7
7
  #
8
8
 
@@ -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.9 2009/04/21 16:56:49 bk1 Exp $
7
- # CVS-Label: $Name: BETA_02_01 $
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 Rational
19
- alias :to_g :to_f
18
+ class LongDecimal
20
19
 
21
- FLOAT_MAX_I = Float::MAX.to_i
20
+ # timer for performance measurements
21
+ def ts(i)
22
+ @timer ||= []
23
+ @timer[i] = Time.now
24
+ end
22
25
 
23
- def to_f
24
- numerator = @numerator
25
- denominator = @denominator
26
- sign = numerator <=> 0
27
- if (sign.zero?)
28
- return 0.0
29
- elsif sign < 0
30
- numerator = -numerator
31
- end
32
- while numerator >= FLOAT_MAX_I || denominator >= FLOAT_MAX_I do
33
- numerator >>= 8
34
- denominator >>= 8
35
- if (denominator == 0)
36
- raise ZeroDivisionError, "denominator too close to zero: #{@numerator}/{@denominator}"
37
- elsif numerator == 0
38
- return 0.0
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
- class LongDecimal
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.abs > LongMath::MAX_FLOATABLE) then
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.abs < LongMath::MIN_FLOATABLE) then
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.abs <= LongMath::MAX_FLOATABLE then
78
- puts "-> dividend <= MAX_FLOATABLE"
79
- if (divisor.abs > LongMath::MAX_FLOATABLE) then
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
- puts "-> d=#{d}"
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.abs < divisor
97
- puts "-> < 1"
98
- # self is between -1 and 1
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 "-> <= 1000000000000000000000"
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
- # 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}"
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
- # puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
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
- # 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}"
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
- # puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
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
- z0 = LongMath.ipower(x0, y0, 2*(iprec + point_shift), mode)
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
- # puts "x=#{x} y=#{y} using **"
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
- # puts "x=#{x} y=#{y} prec=#{prec} using (1/x)**y xi=#{xi}"
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
- # puts "x=#{x} y=#{y} regular"
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 = (z*x)
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