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/README +130 -74
- data/Rakefile +4 -2
- data/VERSION +1 -1
- data/install.rb +6 -0
- data/lib/long-decimal-extra.rb +241 -44
- data/lib/long-decimal.rb +231 -335
- data/make_doc.rb +6 -0
- data/test/testlongdecimal-extra.rb +20 -7
- data/test/testlongdecimal.rb +309 -11
- data/test/testlongdeclib.rb +91 -22
- data/test/testrandlib.rb +7 -4
- data/test/testrandom-extra.rb +6 -4
- data/test/testrandom.rb +8 -4
- data/test/testrandpower.rb +6 -8
- data/version.rb +4 -3
- metadata +53 -46
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.
|
9
|
-
# CVS-Label: $Name:
|
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
|
-
|
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
|
-
|
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 =
|
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
|
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
|
-
|
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
|
2152
|
-
|
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�
|
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(
|
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
|
|