long-decimal 0.01.03 → 0.02.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/lib/long-decimal.rb CHANGED
@@ -1,20 +1,25 @@
1
1
  #
2
2
  # long-decimal.rb -- Arbitrary precision decimals with fixed decimal point
3
3
  #
4
+ # (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2009
5
+ #
4
6
  # This class contains the basic functionality for working with LongDecimal
5
7
  # additional functionality, mostly transcendental functions,
6
8
  # may be found in long-decimal-extra.rb
7
9
  #
8
- # CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.51 2007/08/19 19:23:32 bk1 Exp $
9
- # CVS-Label: $Name: ALPHA_01_03 $
10
+ # CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $
11
+ # CVS-Label: $Name: BETA_02_01 $
10
12
  # Author: $Author: bk1 $ (Karl Brodowsky)
11
13
  #
14
+
12
15
  require "complex"
13
16
  require "rational"
14
17
  require "bigdecimal"
15
18
 
16
19
  # require "bigdecimal/math"
17
20
 
21
+ BYTE_SIZE_OF_ONE = 1.size
22
+
18
23
  #
19
24
  # define rounding modes to be used for LongDecimal
20
25
  # this serves the purpose of an "enum" in C/C++
@@ -144,6 +149,39 @@ module LongDecimalRoundingMode
144
149
 
145
150
  end # LongDecimalRoundingMode
146
151
 
152
+ # JRuby has a bug to be fixed in version > 1.2 that implies results of
153
+ # 0 for multiplications of two Fixnums neither of which is 0 in some
154
+ # cases. This code fixes the bug for the purposes of long-decimal.
155
+ if (RUBY_PLATFORM == 'java')
156
+
157
+ if (JRUBY_VERSION.match /^[01]\.[012]/)
158
+ class Fixnum
159
+
160
+ alias :mul :*
161
+
162
+ def *(y)
163
+ if (self == 0 || y == 0)
164
+ return self.mul(y)
165
+ elsif (y.kind_of? Fixnum)
166
+ x = self
167
+ s = 0
168
+ while (x & 0xff == 0)
169
+ x >>= 8
170
+ s += 8
171
+ end
172
+ while (y & 0xff == 0)
173
+ y >>= 8
174
+ s += 8
175
+ end
176
+ return x.mul(y) << s
177
+ else
178
+ return self.mul(y)
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+
147
185
  #
148
186
  # add one method to Integer
149
187
  #
@@ -159,8 +197,8 @@ class Integer
159
197
  self <=> 0
160
198
  end
161
199
 
162
- alias signum sgn
163
- alias sign sgn
200
+ alias :signum :sgn
201
+ alias :sign :sgn
164
202
 
165
203
  #
166
204
  # create copy of self round in such a way that the result is
@@ -207,7 +245,6 @@ class Integer
207
245
  if (r_self < r_first) then
208
246
  r_self += modulus
209
247
  end
210
- # puts "r_self=#{r_self_00}->#{r_self} r_first=#{r_first} r_last=#{r_last} r_first_again=#{r_first_again}"
211
248
  r_lower = -1
212
249
  r_upper = -1
213
250
  remainders.each_index do |i|
@@ -223,7 +260,6 @@ class Integer
223
260
  end
224
261
  lower = self - (r_self - r_lower)
225
262
  upper = self + (r_upper - r_self)
226
- # puts "r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
227
263
 
228
264
  unless (lower < self && self < upper)
229
265
  raise Error, "self=#{self} not in (#{lower}, #{upper})"
@@ -301,10 +337,8 @@ class Integer
301
337
  end
302
338
 
303
339
  if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then
304
- # puts "floor/lower r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
305
340
  return lower
306
341
  elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
307
- # puts "ceiling/upper r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
308
342
  return upper
309
343
  else
310
344
  raise Error, "this case can never happen: rounding_mode=#{rounding_mode}"
@@ -316,7 +350,7 @@ end
316
350
  # common base class for LongDecimal and LongDecimalQuot
317
351
  #
318
352
  class LongDecimalBase < Numeric
319
- @RCS_ID='-$Id: long-decimal.rb,v 1.51 2007/08/19 19:23:32 bk1 Exp $-'
353
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
320
354
 
321
355
  include LongDecimalRoundingMode
322
356
 
@@ -359,6 +393,13 @@ class LongDecimalBase < Numeric
359
393
  self * self
360
394
  end
361
395
 
396
+ #
397
+ # calculate the cube of self
398
+ #
399
+ def cube
400
+ self * self * self
401
+ end
402
+
362
403
  #
363
404
  # calculate the multiplicative inverse
364
405
  #
@@ -371,13 +412,13 @@ class LongDecimalBase < Numeric
371
412
  result
372
413
  end
373
414
 
374
- alias inverse reciprocal
415
+ alias :inverse :reciprocal
375
416
 
376
417
  #
377
418
  # square of absolute value
378
419
  # happens to be the square
379
420
  #
380
- alias abs2 square
421
+ alias :abs2 :square
381
422
 
382
423
  #
383
424
  # Compares the two numbers.
@@ -424,7 +465,7 @@ end # class LongDecimalBase
424
465
  # digits and the other one the position of the decimal point.
425
466
  #
426
467
  class LongDecimal < LongDecimalBase
427
- @RCS_ID='-$Id: long-decimal.rb,v 1.51 2007/08/19 19:23:32 bk1 Exp $-'
468
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
428
469
 
429
470
  # MINUS_ONE = LongDecimal(-1)
430
471
  # ZERO = LongDecimal(0)
@@ -479,6 +520,14 @@ class LongDecimal < LongDecimalBase
479
520
  new(10**(s+1), s)
480
521
  end
481
522
 
523
+ #
524
+ # creates a LongDecimal representing 1/2 with the given number of
525
+ # digits after the decimal point (scale=s)
526
+ #
527
+ def LongDecimal.half!(s = 1)
528
+ new(5*10**(s-1), s)
529
+ end
530
+
482
531
 
483
532
  #
484
533
  # creates a LongDecimal representing minus one with the given number of
@@ -500,6 +549,13 @@ class LongDecimal < LongDecimalBase
500
549
  new(10**(s+e), s)
501
550
  end
502
551
 
552
+ #
553
+ # needed for clone()
554
+ #
555
+ def initialize_copy(x)
556
+ @int_val = x.int_val
557
+ @scale = x.scale
558
+ end
503
559
 
504
560
  #
505
561
  # initialization
@@ -838,7 +894,8 @@ class LongDecimal < LongDecimalBase
838
894
  if (divisor.abs > LongMath::MAX_FLOATABLE) then
839
895
  q = 10**(scale - Float::MAX_10_EXP)
840
896
  f = (dividend / q).to_f
841
- d = divisor / q
897
+ d = LongMath::MAX_FLOATABLE10
898
+ # d = divisor / q
842
899
  return f / d
843
900
  else
844
901
  f = dividend.to_f
@@ -912,7 +969,7 @@ class LongDecimal < LongDecimalBase
912
969
  # denominator in case of LongDecimal, which does not occur in case
913
970
  # of Rational
914
971
  #
915
- alias numerator int_val
972
+ alias :numerator :int_val
916
973
 
917
974
  #
918
975
  # number of binary digits before the decimal point, not counting a single 0.
@@ -929,7 +986,7 @@ class LongDecimal < LongDecimalBase
929
986
  return 0
930
987
  end
931
988
 
932
- n = int_part.size * 8 - 31
989
+ n = ((int_part.size - BYTE_SIZE_OF_ONE) << 3) + 1
933
990
  int_part = int_part >> n
934
991
  until int_part.zero? do
935
992
  int_part = int_part >> 1
@@ -1022,7 +1079,7 @@ class LongDecimal < LongDecimalBase
1022
1079
  LongDecimal(int_val + 1, scale)
1023
1080
  end
1024
1081
 
1025
- alias next succ
1082
+ alias :next :succ
1026
1083
 
1027
1084
  #
1028
1085
  # predecessor (opposite of successor)
@@ -1210,7 +1267,6 @@ class LongDecimal < LongDecimalBase
1210
1267
  else
1211
1268
  abs_other = -other
1212
1269
  new_scale = abs_other * scale
1213
- # puts("other=#{other} abs_other=#{abs_other} int_val=#{int_val} new_scale=#{new_scale} scale=#{scale}")
1214
1270
  LongDecimalQuot(Rational(10 ** new_scale, int_val ** abs_other), new_scale)
1215
1271
  end
1216
1272
  else
@@ -1392,6 +1448,26 @@ class LongDecimal < LongDecimalBase
1392
1448
  LongMath.sqrt_with_remainder(self, new_scale)
1393
1449
  end
1394
1450
 
1451
+ #
1452
+ # calculate the cbrt (cubic root) of self
1453
+ # provide the result with given number
1454
+ # new_scale of digits after the decimal point
1455
+ # use rounding_mode if the result is not exact
1456
+ #
1457
+ def cbrt(new_scale, rounding_mode)
1458
+ LongMath.cbrt(self, new_scale, rounding_mode)
1459
+ end
1460
+
1461
+ #
1462
+ # calculate the cbrt s (cubic root) of self and remainder r >= 0
1463
+ # such that s**3+r = self and (s+1)**3 > self
1464
+ # provide the result with given number
1465
+ # new_scale of digits after the decimal point
1466
+ #
1467
+ def cbrt_with_remainder(new_scale)
1468
+ LongMath.cbrt_with_remainder(self, new_scale)
1469
+ end
1470
+
1395
1471
  #
1396
1472
  # Absolute value
1397
1473
  #
@@ -1480,8 +1556,8 @@ class LongDecimal < LongDecimalBase
1480
1556
  int_val <=> 0
1481
1557
  end
1482
1558
 
1483
- alias signum sgn
1484
- alias sign sgn
1559
+ alias :signum :sgn
1560
+ alias :sign :sgn
1485
1561
 
1486
1562
  #
1487
1563
  # comparison of self with other for equality
@@ -1542,7 +1618,7 @@ end # LongDecimal
1542
1618
  #
1543
1619
  class LongDecimalQuot < LongDecimalBase
1544
1620
 
1545
- @RCS_ID='-$Id: long-decimal.rb,v 1.51 2007/08/19 19:23:32 bk1 Exp $-'
1621
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
1546
1622
 
1547
1623
  #
1548
1624
  # constructor
@@ -1557,6 +1633,14 @@ class LongDecimalQuot < LongDecimalBase
1557
1633
  new(first, second)
1558
1634
  end
1559
1635
 
1636
+ #
1637
+ # needed for clone()
1638
+ #
1639
+ def initialize_copy(x)
1640
+ @rat = x.rat
1641
+ @scale = x.scale
1642
+ end
1643
+
1560
1644
  #
1561
1645
  # create a new LongDecimalQuot from a rational and a scale or a
1562
1646
  # pair of LongDecimals
@@ -1583,7 +1667,6 @@ class LongDecimalQuot < LongDecimalBase
1583
1667
  dx = first.sint_digits10
1584
1668
  dy = second.sint_digits10
1585
1669
  new_scale = [ 0, 2 * dy + sx + sy - [ dx + sx, dy + sy ].max - 3].max
1586
- # puts("sx=#{sx} sy=#{sy} dx=#{dx} dy=#{dy} sc=#{new_scale} x=#{first} y=#{second}\n")
1587
1670
 
1588
1671
  first, second = first.anti_equalize_scale(second)
1589
1672
  @rat = Rational(first.to_i, second.to_i)
@@ -1842,7 +1925,7 @@ class LongDecimalQuot < LongDecimalBase
1842
1925
  # square of absolute value
1843
1926
  # happens to be the square
1844
1927
  #
1845
- alias abs2 square
1928
+ alias :abs2 :square
1846
1929
 
1847
1930
  #
1848
1931
  # convert LongDecimalQuot to LongDecimal with the given precision
@@ -2051,8 +2134,8 @@ class LongDecimalQuot < LongDecimalBase
2051
2134
  def sgn
2052
2135
  numerator <=> 0
2053
2136
  end
2054
- alias signum sgn
2055
- alias sign sgn
2137
+ alias :signum :sgn
2138
+ alias :sign :sgn
2056
2139
 
2057
2140
  #
2058
2141
  # Returns a hash code for the complex number.
@@ -2148,8 +2231,10 @@ module LongMath
2148
2231
 
2149
2232
  include LongDecimalRoundingMode
2150
2233
 
2151
- MAX_FLOATABLE = Float::MAX.to_i
2152
- MAX_EXP_ABLE = Math.log(MAX_FLOATABLE).to_i
2234
+ MAX_FLOATABLE = Float::MAX.to_i
2235
+ MAX_FLOATABLE2 = MAX_FLOATABLE / 2
2236
+ MAX_FLOATABLE10 = 10.0 ** Float::MAX_10_EXP
2237
+ MAX_EXP_ABLE = 709
2153
2238
  MIN_FLOATABLE = Float::MIN.to_ld(340, LongMath::ROUND_UP)
2154
2239
  LOG2 = Math.log(2.0)
2155
2240
  LOG10 = Math.log(10.0)
@@ -2351,7 +2436,7 @@ module LongMath
2351
2436
  end
2352
2437
 
2353
2438
  #
2354
- #�calculate�the�an�integer�s�>=�0�and�a�remainder�r�>=�0�such�that
2439
+ #�calculate�an�integer�s�>=�0�and�a�remainder�r�>=�0�such�that
2355
2440
  #�x�=�s**2�+�r�and�s**2�<=�x�<�(s+1)**2
2356
2441
  # the bitwise algorithm is used, which works well for relatively
2357
2442
  # small values of x.
@@ -2464,6 +2549,53 @@ module LongMath
2464
2549
  return [ yi, xi ]
2465
2550
  end
2466
2551
 
2552
+ #
2553
+ # calculate the cubic root of an integer x using bitwise algorithm
2554
+ # the result is rounded to an integer y such that
2555
+ # y**3�<=�x�<�(y+1)**3
2556
+ #
2557
+ def LongMath.cbrtb(x)
2558
+ a = cbrtb_with_remainder(x)
2559
+ a[0]
2560
+ end
2561
+
2562
+ #
2563
+ #�calculate�an�integer�s�>=�0�and�a�remainder�r�>=�0�such�that
2564
+ #�x�=�s**3�+�r�and�s**3�<=�x�<�(s+1)**3
2565
+ # for negative numbers x return negative remainder and result.
2566
+ # the bitwise algorithm is used, which works well for relatively
2567
+ # small values of x.
2568
+ #
2569
+ def LongMath.cbrtb_with_remainder(x)
2570
+ check_is_int(x, "x")
2571
+
2572
+ s = (x <=> 0)
2573
+ if (s == 0) then
2574
+ return [0, 0]
2575
+ elsif (s < 0)
2576
+ a = cbrtb_with_remainder(-x)
2577
+ return [ -a[0], -a[1]]
2578
+ end
2579
+
2580
+ # split into groups of three bits
2581
+ xwords = split_to_words(x, 3)
2582
+ xi = xwords[0] - 1
2583
+ yi = 1
2584
+
2585
+ 1.upto(xwords.length-1) do |i|
2586
+ xi = (xi << 3) + xwords[i]
2587
+ d0 = 6 * yi * (2 * yi + 1) + 1
2588
+ r = xi - d0
2589
+ b = 0
2590
+ if (r >= 0) then
2591
+ b = 1
2592
+ xi = r
2593
+ end
2594
+ yi = (yi << 1) + b
2595
+ end
2596
+ return [yi, xi]
2597
+ end
2598
+
2467
2599
  #
2468
2600
  # find the gcd of an Integer x with b**n0 where n0 is a sufficiently
2469
2601
  # high exponent
@@ -2519,7 +2651,7 @@ module LongMath
2519
2651
  if (power.abs < MAX_FLOATABLE) then
2520
2652
  result = (Math.log(power) / Math.log(prime_number)).round
2521
2653
  else
2522
- e = (Math.log(MAX_FLOATABLE) / Math.log(prime_number)).floor
2654
+ e = (Math.log(Float::MAX) / Math.log(prime_number)).floor
2523
2655
  result = 0
2524
2656
  partial = prime_number ** e
2525
2657
  while (power > partial) do
@@ -2678,11 +2810,6 @@ module LongMath
2678
2810
  iprec_extra = (xf / LOG10).abs
2679
2811
  end
2680
2812
  iprec = ((prec+12) * 1.20 + iprec_extra * 1.10).round
2681
- # iprec = ((prec+15) * 1.20 + iprec_extra * 1.10).round
2682
- # iprec = ((prec+10) * 1.20 + iprec_extra * 1.10).round
2683
- # iprec = ((prec+10)*1.20 + iprec_extra).round
2684
- # iprec = ((prec+10)*1.20 + iprec_extra*1.20).round
2685
- # puts("calc_iprec_for_exp: iprec=#{iprec} iprec_extra=#{iprec_extra}\n")
2686
2813
  if (iprec < prec) then
2687
2814
  iprec = prec
2688
2815
  end
@@ -2779,9 +2906,7 @@ module LongMath
2779
2906
  # rounded to be accurate to all digits that are provided.
2780
2907
  #
2781
2908
  def LongMath.exp_raw(x, prec, j, k, iprec, mode)
2782
- # dprec = [ (iprec*0.9).round , (prec + 1) << 1 ].min
2783
2909
  dprec = [ (iprec*0.9).round, prec ].max
2784
- # puts("prec=#{prec} dprec=#{dprec} iprec=#{iprec}")
2785
2910
 
2786
2911
  unless (x.kind_of? LongDecimal)
2787
2912
  x = x.to_ld(iprec, mode)
@@ -2852,6 +2977,7 @@ module LongMath
2852
2977
  prec1 += 1
2853
2978
  end
2854
2979
  cache_key = nil
2980
+ y_arr = nil
2855
2981
  unless (with_rem)
2856
2982
  cache_key = get_cache_key("sqrt", x, mode, [2, 3, 5, 6, 7, 8, 10])
2857
2983
  y_arr = get_cached(cache_key, x, prec)
@@ -2889,6 +3015,74 @@ module LongMath
2889
3015
 
2890
3016
  public
2891
3017
 
3018
+ #
3019
+ # calculate approximation of cbrt of a LongDecimal.
3020
+ #
3021
+ def LongMath.cbrt(x, prec, mode = LongMath.standard_mode) # down
3022
+ LongMath.cbrt_internal(x, prec, mode, false)
3023
+ end
3024
+
3025
+ #
3026
+ # calculate approximation of cbrt of a LongDecimal with remainder
3027
+ #
3028
+ def LongMath.cbrt_with_remainder(x, prec)
3029
+ LongMath.cbrt_internal(x, prec, ROUND_DOWN, true)
3030
+ end
3031
+
3032
+ private
3033
+
3034
+ #
3035
+ # internal helper method for calculationg cbrt and cbrt_with_remainder
3036
+ #
3037
+ def LongMath.cbrt_internal(x, prec, mode, with_rem, cache_result = true)
3038
+ check_is_prec(prec, "prec")
3039
+ check_is_mode(mode, "mode")
3040
+ unless (x.kind_of? LongDecimal)
3041
+ x = x.to_ld(3 * (prec+1), mode)
3042
+ end
3043
+ prec1 = prec
3044
+ unless (with_rem) then
3045
+ prec1 += 1
3046
+ end
3047
+ cache_key = nil
3048
+ y_arr = nil
3049
+ unless (with_rem)
3050
+ cache_key = get_cache_key("cbrt", x, mode, [2, 3, 5, 6, 7, 8, 10])
3051
+ y_arr = get_cached(cache_key, x, prec)
3052
+ end
3053
+ if (y_arr.nil?) then
3054
+ y_arr = cbrt_raw(x, prec1, mode)
3055
+ def y_arr.scale
3056
+ self[0].scale
3057
+ end
3058
+ set_cached(cache_key, y_arr) if cache_result
3059
+ end
3060
+ if (with_rem) then
3061
+ return y_arr
3062
+ else
3063
+ y, r = y_arr
3064
+ if ((mode == ROUND_HALF_EVEN || mode == ROUND_HALF_DOWN) && r > 0) then
3065
+ mode = ROUND_HALF_UP
3066
+ end
3067
+ y = y.round_to_scale(prec, mode)
3068
+ return y
3069
+ end
3070
+ end
3071
+
3072
+ #
3073
+ # calculate cbrt with remainder uncached
3074
+ #
3075
+ def LongMath.cbrt_raw(x, new_scale1, rounding_mode)
3076
+ old_scale = (new_scale1 * 3)
3077
+ x = x.round_to_scale(old_scale, rounding_mode)
3078
+ root, rem = LongMath.cbrtb_with_remainder(x.int_val)
3079
+ y = LongDecimal(root, new_scale1)
3080
+ r = LongDecimal(rem, old_scale)
3081
+ return [y, r]
3082
+ end
3083
+
3084
+ public
3085
+
2892
3086
  #
2893
3087
  # calculate the natural logarithm function of x to the given precision as
2894
3088
  # LongDecimal.
@@ -2925,7 +3119,6 @@ module LongMath
2925
3119
  check_is_mode(mode, "mode")
2926
3120
 
2927
3121
  if (iprec.nil?) then
2928
- # iprec = ((prec+10)*1.20).round
2929
3122
  iprec = ((prec+12)*1.20).round
2930
3123
  end
2931
3124
  if (iprec < prec) then
@@ -2957,13 +3150,9 @@ module LongMath
2957
3150
  #
2958
3151
  def LongMath.log_raw(x, prec, iprec, mode)
2959
3152
 
2960
- # puts("log_raw start x=#{x}")
2961
-
2962
3153
  # we have to rely on iprec being at least 10
2963
3154
  raise TypeError, "iprec=#{iprec} out of range" unless (iprec.kind_of? Fixnum) && iprec >= 10
2964
3155
 
2965
- # dprec = [ iprec - 1, (prec + 1) << 1 ].min
2966
- # dprec >= 9
2967
3156
  dprec = iprec - 1
2968
3157
 
2969
3158
  # result is stored in y
@@ -2977,7 +3166,6 @@ module LongMath
2977
3166
  x = (1 / x).round_to_scale(iprec, mode1)
2978
3167
  s = -1
2979
3168
  end
2980
- # puts("log_raw prepared t=#{Time.new-t0} x=#{x} s=#{s} mode=#{mode} mode1=#{mode1}")
2981
3169
 
2982
3170
  # number that are beyond the usual range of Float need to be
2983
3171
  # handled specially to reduce to something expressable as Float
@@ -2993,30 +3181,22 @@ module LongMath
2993
3181
  end
2994
3182
  end
2995
3183
  end
2996
- # puts("log_raw divided t=#{Time.new-t0} x=#{x} y=#{y} s=#{s}")
2997
3184
 
2998
3185
  factor = 1
2999
3186
  sprec = (iprec * 1.5).round
3000
- # delta = LongDecimal(1, (iprec.to_f**(1/3)).round)
3001
- # delta = LongDecimal(1, (iprec.to_f**0.3).round)
3002
3187
  delta = LongDecimal(1, (iprec.to_f**0.45).round)
3003
- # delta = LongDecimal(1, LongMath.sqrtw(iprec))
3004
- # delta = LongDecimal(1, LongMath.sqrtw(LongMath.sqrtw(iprec+1)+1))
3005
3188
  while (x - 1).abs > delta do
3006
3189
  x = LongMath.sqrt(x, sprec, mode1)
3007
3190
  factor *= 2
3008
3191
  end
3009
- # puts("log_raw rooted t=#{Time.new-t0} x=#{x} y=#{y} s=#{s} f=#{factor}")
3010
3192
 
3011
3193
  ss = 1
3012
3194
  mode2 = mode1.ainverse
3013
3195
  if (x < 1)
3014
- puts("x<1 inverting")
3015
3196
  mode2 = mode2.ainverse
3016
3197
  x = (1 / x).round_to_scale(iprec, mode2)
3017
3198
  ss = -1
3018
3199
  end
3019
- # puts("log_raw 2nd prep t=#{Time.new-t0} x=#{x} y=#{y} s=#{s} ss=#{ss} f=#{factor}")
3020
3200
 
3021
3201
  sum = 0
3022
3202
  z = 1 - x
@@ -3031,295 +3211,11 @@ module LongMath
3031
3211
 
3032
3212
  end
3033
3213
  sum *= ss
3034
- # puts("log_raw added t=#{Time.new-t0} x=#{x} y=#{y} sum=#{sum} s=#{s} ss=#{ss} f=#{factor}")
3035
3214
 
3036
3215
  y -= ((s * factor) * sum).round_to_scale(iprec, mode.ainverse)
3037
- # puts("log_raw done t=#{Time.new-t0} x=#{x} y=#{y} sum=#{sum} s=#{s} ss=#{ss} f=#{factor}")
3038
3216
  return y
3039
3217
  end
3040
3218
 
3041
- # private
3042
-
3043
- # #
3044
- # # internal helper method for calculating the internal precision for power
3045
- # #
3046
- # def LongMath.calc_iprec_for_power(x, y, prec)
3047
-
3048
- # logx_f = nil
3049
- # if (x.abs <= LongMath::MAX_FLOATABLE)
3050
- # x_f = x.to_f
3051
- # logx_f = Math.log(x_f.abs)
3052
- # else
3053
- # logx_f = LongMath.log(x, 15, LongMath::ROUND_UP)
3054
- # end
3055
-
3056
- # y_f = nil
3057
- # if (y.abs <= LongMath::MAX_FLOATABLE) then
3058
- # y_f = y.to_f
3059
- # else
3060
- # y_f = y.round_to_scale(15, LongMath::ROUND_UP)
3061
- # end
3062
-
3063
- # logx_y_f = logx_f * y_f
3064
- # if (logx_y_f.abs > LongMath::MAX_FLOATABLE) then
3065
- # raise ArgumentError, "power would be way too big: y*log(x)=#{logx_y_f}";
3066
- # end
3067
- # logx_y_f = logx_y_f.to_f unless logx_y_f.kind_of? Float
3068
-
3069
- # iprec_x = calc_iprec_for_exp(logx_y_f.abs.ceil, prec, logx_y_f < 0)
3070
- # iprec_y = iprec_x
3071
- # iprec = iprec_x + 2
3072
- # if (logx_f < 0)
3073
- # iprec_x -= (logx_f/LOG10).round
3074
- # end
3075
- # if (y_f.abs < 1)
3076
- # logy_f = nil
3077
- # if (y_f.kind_of? Float) then
3078
- # logy_f = Math.log(y_f.abs)
3079
- # else
3080
- # logy_f = LongMath.log(y_f.abs, 15, LongMath::ROUND_UP)
3081
- # if (logy_f.abs > LongMath::MAX_FLOATABLE) then
3082
- # raise ArgumentError, "exponent would be way too big: y=#{y} logy_f=#{logy_f}";
3083
- # end
3084
- # logy_f = logy_f.to_f
3085
- # end
3086
- # # puts("x=#{x} y=#{y} x_f=#{x_f} y_f=#{y_f} logx_f=#{logx_f} logy_f=#{logy_f} logx_y_f=#{logx_y_f}\n")
3087
- # iprec_y -= (logy_f/LOG10).round
3088
- # end
3089
- # # puts("x=#{x} y=#{y} x_f=#{x_f} y_f=#{y_f} logx_f=#{logx_f} logy_f=#{logy_f} logx_y_f=#{logx_y_f}\n")
3090
- # # puts("\niprec: x=#{x} y=#{y} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y}\n")
3091
- # [ iprec, iprec_x, iprec_y, logx_y_f ]
3092
-
3093
- # end
3094
-
3095
- # public
3096
-
3097
- # #
3098
- # # calc the power of x with exponent y to the given precision as
3099
- # # LongDecimal. Only supports values of y such that exp(y) still
3100
- # # fits into a float (y <= 709)
3101
- # #
3102
- # def LongMath.power(x, y, prec, mode = LongMath.standard_mode)
3103
-
3104
- # raise TypeError, "x=#{x} must be numeric" unless x.kind_of? Numeric
3105
- # raise TypeError, "y=#{y} must be numeric" unless y.kind_of? Numeric
3106
- # raise TypeError, "x=#{x.inspect} must not be greater #{MAX_FLOATABLE}" unless x.abs <= MAX_FLOATABLE
3107
- # raise TypeError, "y=#{y.inspect} must not be greater #{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
3108
- # # raise TypeError, "y=#{y.inspect} must not be greater #{MAX_EXP_ABLE}" unless y <= MAX_EXP_ABLE
3109
- # # raise TypeError, "x=#{x.inspect} must not negative" unless x >= 0 || (y.kind_of? Integer) || (y.kind_of? LongDecimalBase) && y.is_int?
3110
- # raise TypeError, "x=#{x.inspect} must not negative" unless x >= 0
3111
- # check_is_prec(prec, "prec")
3112
- # check_is_mode(mode, "mode")
3113
-
3114
- # # handle the special cases where base or exponent are 0 or 1 explicitely
3115
- # if y.zero? then
3116
- # return LongDecimal.one!(prec)
3117
- # elsif x.zero? then
3118
- # return LongDecimal.zero!(prec)
3119
- # elsif y.one? then
3120
- # return x.to_ld(prec, mode)
3121
- # elsif x.one? then
3122
- # return LongDecimal.one!(prec)
3123
- # end
3124
-
3125
- # # els
3126
- # # could be result with our precision
3127
- # # x ** y <= 10**-s/2 <=> y * log(x) <= -s log(10) - log(2)
3128
-
3129
- # iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
3130
- # if (x < 1 && y > 0 || x > 1 && y < 0) then
3131
- # if (logx_y_f <= - prec * LOG10 - LOG2) then
3132
- # return LongDecimal.zero!(prec)
3133
- # end
3134
- # end
3135
- # # puts("x=#{x} y=#{y} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y} prec=#{prec}")
3136
-
3137
- # unless (x.kind_of? LongDecimalBase) || (x.kind_of? Integer)
3138
- # x = x.to_ld(iprec_x, mode)
3139
- # end
3140
- # unless (y.kind_of? LongDecimalBase) || (y.kind_of? Integer)
3141
- # y = y.to_ld(iprec_y, mode)
3142
- # end
3143
-
3144
- # # try shortcut if exponent is an integer
3145
- # if (y.kind_of? LongDecimalBase) && y.is_int? then
3146
- # y = y.to_i
3147
- # end
3148
- # unless (y.kind_of? Integer)
3149
- # y2 = y*2
3150
- # if (y2.kind_of? LongDecimalBase) && y2.is_int? then
3151
- # y2 = y2.to_i
3152
- # puts("y2=#{y2}")
3153
- # end
3154
- # if (y2.kind_of? Integer)
3155
- # x = LongMath.sqrt(x, 2*iprec_x, mode)
3156
- # y = y2
3157
- # end
3158
- # end
3159
- # if (y.kind_of? Integer)
3160
- # unless x.kind_of? LongDecimal
3161
- # # x = x.to_ld(prec)
3162
- # x = x.to_ld(iprec_x)
3163
- # end
3164
- # # z = x ** y
3165
- # z = LongMath.ipower(x, y, 2*iprec, mode)
3166
- # # puts("x=#{x} y=#{y} z=#{z} y int")
3167
- # return z.to_ld(prec, mode)
3168
- # end
3169
-
3170
- # # it can be assumed that the exponent is not an integer, so it should
3171
- # # be converted into LongDecimal
3172
- # unless (y.kind_of? LongDecimal)
3173
- # # y = y.to_ld(prec, mode)
3174
- # y = y.to_ld(iprec_y, mode)
3175
- # end
3176
-
3177
- # # if x < 1 && y < 0 then
3178
- # # working with x < 1 should be improved, less precision needed
3179
- # if x < 1 then
3180
- # # since we do not allow x < 0 and we have handled x = 0 already,
3181
- # # we can be sure that x is no integer, so it has been converted
3182
- # # if necessary to LongDecimalBase
3183
- # y = -y
3184
- # x = (1/x).round_to_scale(iprec_x*2, mode)
3185
- # iprec, iprec_x, iprec_y = calc_iprec_for_power(x, y, prec)
3186
- # end
3187
-
3188
- # # exponent is split in two parts, an integer part and a
3189
- # # LongDecimal with absolute value <= 0.5
3190
- # y0 = y.round_to_scale(0, LongMath.standard_imode).to_i
3191
- # # z0 = x**y0
3192
- # z0 = LongMath.ipower(x, y0, 2*iprec, mode)
3193
- # y1 = y - y0
3194
- # prec_extra = 0
3195
- # if (y0 > 0)
3196
- # prec_extra = (y0*Math.log10(x.to_f).abs).ceil
3197
- # end
3198
- # # z1 = LongMath.power_internal(x, y1, prec+prec_extra , mode)
3199
- # z1 = LongMath.power_internal(x, y1, prec+prec_extra + 4, mode)
3200
- # z = z0 * z1
3201
- # # puts("x=#{x} y=#{y} z=#{z} y not int")
3202
- # return z.to_ld(prec, mode)
3203
- # end
3204
-
3205
- # #
3206
- # # internal functionality to calculate the y-th power of x assuming
3207
- # # that y is an integer
3208
- # # prec is a hint on how much internal precision is needed at most
3209
- # # final rounding is left to the caller
3210
- # #
3211
- # def LongMath.ipower(x, y, prec, mode)
3212
-
3213
- # raise TypeError, "x=#{x} must be numeric" unless x.kind_of? Numeric
3214
- # raise TypeError, "y=#{y} must be integer" unless y.kind_of? Integer
3215
- # raise TypeError, "x=#{x.inspect} must not be greater #{MAX_FLOATABLE}" unless x.abs <= MAX_FLOATABLE
3216
- # raise TypeError, "y=#{y.inspect} must not be greater #{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
3217
- # check_is_prec(prec, "prec")
3218
- # check_is_mode(mode, "mode")
3219
-
3220
- # cnt = 0
3221
-
3222
- # if (y.zero?)
3223
- # return 1
3224
- # elsif ! (x.kind_of? LongDecimalBase) || x.scale * y.abs <= prec
3225
- # return x ** y
3226
- # elsif (y < 0)
3227
- # l = Math.log10(x.abs.to_f)
3228
- # if (l > 0)
3229
- # prec += (2*l).ceil
3230
- # end
3231
- # return 1/LongMath.ipower(x, -y, prec, mode)
3232
- # else
3233
- # # y > 0
3234
- # # puts("ipower y>0 x=#{x} y=#{y} prec=#{prec}")
3235
- # z = x
3236
- # while true do
3237
-
3238
- # cnt++
3239
- # y -= 1
3240
- # if (y.zero?)
3241
- # break
3242
- # end
3243
- # while (y & 0x01) == 0 do
3244
-
3245
- # cnt++
3246
- # y = y >> 1
3247
- # x = (x*x)
3248
- # if (x.kind_of? LongDecimalBase)
3249
- # x = x.round_to_scale(prec, mode)
3250
- # end
3251
- # if (cnt > 1000)
3252
- # puts("ipower x=#{x} y=#{y} cnt=#{cnt} z=#{z}")
3253
- # cnt = 0
3254
- # end
3255
-
3256
- # end
3257
- # z = (z*x)
3258
- # if (z.kind_of? LongDecimalBase)
3259
- # z = z.round_to_scale(prec, mode)
3260
- # end
3261
-
3262
- # end
3263
- # end
3264
- # return z
3265
- # end
3266
-
3267
- # #
3268
- # # internal functionality of exp. exposes some more parameters, that
3269
- # # should usually be set to defaut values, in order to allow better testing.
3270
- # # do not actually call this method unless you are testing exp.
3271
- # # create a bug report, if the default settings for the parameters do
3272
- # # not work correctly
3273
- # #
3274
- # def LongMath.power_internal(x, y, prec = nil, final_mode = LongMath.standard_mode, iprec = nil, mode = LongMath.standard_imode)
3275
-
3276
- # if (prec.nil?) then
3277
- # if (x.kind_of? LongDecimalBase) && (y.kind_of? LongDecimalBase)
3278
- # prec = [x.scale, y.scale].max
3279
- # elsif (x.kind_of? LongDecimalBase)
3280
- # prec = x.scale
3281
- # elsif (y.kind_of? LongDecimalBase)
3282
- # prec = y.scale
3283
- # else
3284
- # raise ArgumentError, "precision must be supplied either as precision of x=#{x} or explicitely"
3285
- # end
3286
- # end
3287
- # check_is_prec(prec, "prec")
3288
-
3289
- # if (final_mode.nil?)
3290
- # final_mode = LongMath.standard_mode
3291
- # end
3292
- # check_is_mode(final_mode, "final_mode")
3293
- # check_is_mode(mode, "mode")
3294
-
3295
- # if y.zero? then
3296
- # return LongDecimal.one!(prec)
3297
- # elsif x.zero? then
3298
- # return LongDecimal.zero!(prec)
3299
- # end
3300
-
3301
- # if (iprec.nil?) then
3302
- # iprec, iprec_x, iprec_y = calc_iprec_for_power(x, y, prec)
3303
- # end
3304
- # unless (x.kind_of? LongDecimal)
3305
- # # x = x.to_ld(iprec, mode)
3306
- # x = x.to_ld(iprec_x, mode)
3307
- # end
3308
- # unless (y.kind_of? LongDecimal)
3309
- # # y = y.to_ld(iprec, mode)
3310
- # y = y.to_ld(iprec_y, mode)
3311
- # end
3312
-
3313
- # # logx = log(x, iprec, mode)
3314
- # logx = log(x, iprec + 20, mode)
3315
- # logx_y = logx*y
3316
- # # xy = exp_internal(logx_y, prec + 1, mode)
3317
- # # xy = exp_internal(logx_y, prec + 4, mode)
3318
- # xy = exp_internal(logx_y, prec + 3, mode)
3319
- # xy.round_to_scale(prec, final_mode)
3320
-
3321
- # end # power_internal
3322
-
3323
3219
  @@standard_mode = ROUND_HALF_UP
3324
3220
 
3325
3221
  def LongMath.standard_mode
@@ -3327,7 +3223,7 @@ module LongMath
3327
3223
  end
3328
3224
 
3329
3225
  def LongMath.standard_mode=(x)
3330
- LongMath.check_is_mode
3226
+ LongMath.check_is_mode(x)
3331
3227
  @@standard_mode = x
3332
3228
  end
3333
3229
 
@@ -3338,7 +3234,7 @@ module LongMath
3338
3234
  end
3339
3235
 
3340
3236
  def LongMath.standard_imode=(x)
3341
- LongMath.check_is_mode
3237
+ LongMath.check_is_mode(x)
3342
3238
  @@standard_imode = x
3343
3239
  end
3344
3240