long-decimal 1.00.02 → 1.00.03
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README +41 -25
- data/Rakefile +2 -1
- data/lib/long-decimal-extra.rb +37 -1
- data/lib/long-decimal.rb +208 -17
- data/lib/long-decimal/version.rb +1 -1
- data/test/testlongdecimal.rb +225 -5
- data/test/testlongdeclib.rb +46 -25
- data/test/testrandlib.rb +2 -1
- data/test/testrandom.rb +2 -1
- data/test/testrandpower.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4d758878cf5a3d2d5f20a4738e94a261114da04
|
4
|
+
data.tar.gz: 3db2e6b11a3f8aae44a7cccfc81ea902165ec4bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8aa62b76ff524e76b9c2d38dbb5cd660c38dfd1fdae8f575312da56ecf7438875860fdd1fae605ba2dc04409fc252a67fcdb596117d04b2784e724657d20e425
|
7
|
+
data.tar.gz: 4dde6badc8da94abaef63c8151a13452dda84658a41bb83bd5efc219d36e3a03cb32b6999ec20ef28f91392d11b2dbba5dc7ddcb0ef32f06b5531e75cb346519
|
data/README
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
Version
|
2
2
|
-------
|
3
3
|
|
4
|
-
This version (1.00.
|
5
|
-
It
|
6
|
-
version 1.01.00
|
4
|
+
This version (1.00.03) is fixing bugs from version 1.00.02.
|
5
|
+
It can be considered as a release candidate from the upcoming
|
6
|
+
version 1.01.00.
|
7
7
|
|
8
|
-
|
8
|
+
Change Log
|
9
|
+
----------
|
10
|
+
|
11
|
+
Improvements in 1.00.03
|
12
|
+
- tests improved
|
13
|
+
- bug fixes in mean calculation functionality for non-LongDecimal paramters
|
14
|
+
- calculation of sqrt on arguments that result in the exact square root being the boundary for geometric or quadratic rounding recognized and fixed
|
15
|
+
- calculation of cbrt on arguments that result in the exact cube root being the boundary for cubic rounding recognized and fixed
|
16
|
+
|
17
|
+
Improvements over the previous version in 1.00.02
|
9
18
|
|
10
19
|
- migration from CVS (rubyforge) to GIT (github)
|
11
20
|
- bug fixed with frozen string attempted to be changed when parsing a string for a long-decimal number.
|
@@ -17,19 +26,29 @@ Improvements over the previous version:
|
|
17
26
|
- moved power, log10, log2 etc. from long-decimal-extra.rb to long-decimal.rb
|
18
27
|
- added more unit tests
|
19
28
|
|
29
|
+
Road Map
|
30
|
+
--------
|
31
|
+
|
20
32
|
Work to do for 1.01.00:
|
21
33
|
- go through functions that are working with rounding modes as parameter (like transcendental functions, sqrt, cbrt etc.) to ensure that they work properly with all new rounding modes
|
22
34
|
- improve algorithm for rounding with sum constraint
|
23
35
|
- go through unit tests to see they are covering all rounding modes
|
24
36
|
- add unit tests for rounding with sum constraint
|
37
|
+
- caching of frequently used calculation results needs to be done independent of rounding mode
|
38
|
+
- add tests comparing results of transcendental functions for different rounding modes
|
25
39
|
- rubydoc-documentation
|
26
40
|
- external documentation
|
27
41
|
|
28
42
|
Work to do for 1.02.00 (or 2.00.00):
|
29
43
|
- add the following transcendental functions: sin, cos, tan, cot, sec, csc, sinh, cosh, tanh, coth, sech, csch, asin, acos, atan, atan2, acot, asec, acsc, asinh, acosh, atanh, acoth, asech, acsch
|
44
|
+
- support Complex of LongDecimal wherever it makes sense
|
30
45
|
- documentation
|
31
46
|
- external documentation
|
32
|
-
- interoperability with flt
|
47
|
+
- interoperability with gmp, mpfr, mpfi, flt and other libraries
|
48
|
+
- interoparability with rails
|
49
|
+
|
50
|
+
Status
|
51
|
+
------
|
33
52
|
|
34
53
|
The existing functionality did not show any bugs during intensive
|
35
54
|
testing, so it could be assumed that the whole library is good for
|
@@ -84,6 +103,11 @@ require 'long-decimal'
|
|
84
103
|
Test
|
85
104
|
----
|
86
105
|
|
106
|
+
Tests have been run with Ruby 1.8.7, 1.9.3, 2.0.0 and 2.1.1
|
107
|
+
Some tests do not work with 1.8.7 because of missing language features.
|
108
|
+
They are skipped. No major effort for adapting tests to this version
|
109
|
+
will be allocated.
|
110
|
+
|
87
111
|
Some runit tests have been included. They give some indication of the
|
88
112
|
correctness of this library and allow changes to be checked in order
|
89
113
|
to make sure that what was running before would still work afterwards.
|
@@ -99,27 +123,24 @@ ruby test/testlongdecimal.rb
|
|
99
123
|
|
100
124
|
This is the result of the test:
|
101
125
|
|
102
|
-
Finished in
|
103
|
-
|
126
|
+
Finished in 2952.440454s, 0.0660 runs/s, 7759.3877 assertions/s.
|
127
|
+
|
128
|
+
195 runs, 22909130 assertions, 0 failures, 0 errors, 0 skips
|
104
129
|
|
105
130
|
In addition random tests for exp, exp2, exp10, sqrt, log, log2 and
|
106
131
|
log10 can be run for a long time, using
|
107
132
|
|
108
133
|
ruby test/testrandom.rb.
|
109
134
|
|
110
|
-
The
|
111
|
-
more advanced and less tested methods, has its tests in
|
135
|
+
The power function did fail in some tests, which have been collected in
|
112
136
|
|
113
137
|
ruby test/testlongdecimal-extra.rb
|
114
138
|
|
115
|
-
|
139
|
+
some additional tests are in
|
116
140
|
|
117
141
|
ruby test/testrandom-extra.rb
|
118
142
|
|
119
|
-
|
120
|
-
|
121
|
-
Finished in 4115.851979 seconds.
|
122
|
-
12 tests, 976 assertions, 0 failures, 0 errors
|
143
|
+
They should be integrated into testrandom.rb
|
123
144
|
|
124
145
|
Likewise tests for powers x to the yth with random x and y (which also
|
125
146
|
resided in long-decimal-extra.rb) can be tested for a long time using
|
@@ -137,11 +158,10 @@ long-decimal-extra and find an error with it, please report it.
|
|
137
158
|
Install
|
138
159
|
-------
|
139
160
|
|
140
|
-
|
141
161
|
1. Using ruby-gems (preferred)
|
142
162
|
- open a shell window
|
143
163
|
- become root, unless the current user has the right to install gems
|
144
|
-
(which is usually the case on windows)
|
164
|
+
(which is usually the case on windows or when using rvm)
|
145
165
|
|
146
166
|
su
|
147
167
|
|
@@ -162,25 +182,21 @@ Install
|
|
162
182
|
where $RUBY_DIR is the directory containing your ruby-installation,
|
163
183
|
usually /usr/lib/ruby or /usr/local/lib/ruby on
|
164
184
|
Linux/Unix-systems.
|
165
|
-
$RUBY_VERSION is the major version of your Ruby, like 1
|
185
|
+
$RUBY_VERSION is the major version of your Ruby, like 2.1
|
166
186
|
$LONG_DECIMAL_VERSION is the version of long-decimal that you
|
167
|
-
have installed, like
|
168
|
-
on my machine that would be
|
169
|
-
/usr/local/lib/ruby/gems/1.8/doc/long-decimal-0.02.01/rdoc/index.html
|
187
|
+
have installed, like 1.00.03
|
170
188
|
|
171
189
|
2. Installing from the sources (it is preferred to use the
|
172
190
|
gem-installation, but since long-decimal is open-source-software you
|
173
191
|
are off course granted the right to download the source and change
|
174
192
|
it and install your own version.)
|
175
193
|
|
176
|
-
- download the newest source-tar.gz-file from long-decimal project at
|
194
|
+
- download the newest source-tar.gz-file from long-decimal project at github
|
177
195
|
which can be found by
|
178
|
-
http://rubyforge.org/projects/long-decimal/ -> Files
|
179
|
-
( http://rubyforge.org/frs/?group_id=1334 )
|
180
196
|
- open a shell window
|
181
197
|
cd to the directory where you have downloaded the .tar.gz-file
|
182
198
|
unpack the file using tar
|
183
|
-
tar xfzvv long-decimal
|
199
|
+
tar xfzvv long-decimal-*.tar.gz
|
184
200
|
cd long-decimal
|
185
201
|
- now you can use rake for several operations
|
186
202
|
- rake test
|
@@ -238,7 +254,7 @@ License
|
|
238
254
|
|
239
255
|
Ruby's license or LGPL
|
240
256
|
Find copies of these licenses on http://www.gnu.org/ or http://www.ruby-lang.org/
|
241
|
-
� Karl Brodowsky (IT Sky Consulting GmbH) 2006-
|
257
|
+
� Karl Brodowsky (IT Sky Consulting GmbH) 2006-2015
|
242
258
|
http://www.it-sky-consulting.com/
|
243
259
|
|
244
260
|
Warranty
|
data/Rakefile
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
#
|
4
4
|
# Rakefile for long-decimal project
|
5
5
|
#
|
6
|
-
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-
|
6
|
+
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2015
|
7
7
|
#
|
8
|
+
# TAG: $TAG v1.00.03$
|
8
9
|
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/Rakefile,v 1.4 2009/04/15 19:29:37 bk1 Exp $
|
9
10
|
# CVS-Label: $Name: $
|
10
11
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
data/lib/long-decimal-extra.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
#
|
2
2
|
# long-decimal-extra.rb -- Arbitrary precision decimals with fixed decimal point
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# additional features: all functionality in this file is experimental
|
5
|
+
# and can be removed without notice in future versions. Or moved to
|
6
|
+
# long-decimal.rb, if useful.
|
5
7
|
#
|
8
|
+
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2015
|
9
|
+
#
|
10
|
+
# TAG: $TAG v1.00.03$
|
6
11
|
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal-extra.rb,v 1.29 2011/02/04 23:17:21 bk1 Exp $
|
7
12
|
# CVS-Label: $Name: $
|
8
13
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
@@ -320,12 +325,14 @@ class LongDecimal
|
|
320
325
|
elsif dividend < divisor
|
321
326
|
# self is between 0 and 1 and dividend > LongMath::MAX_FLOATABLE
|
322
327
|
# return LongDecimal(dividend.div(LongMath.npower10(digits)), scale -digits).to_f
|
328
|
+
# puts "via s (1): #{self.inspect}"
|
323
329
|
return self.to_s.to_f
|
324
330
|
else
|
325
331
|
q = dividend.abs / divisor
|
326
332
|
if (q.abs > 1000000000000000000000)
|
327
333
|
return q.to_f
|
328
334
|
else
|
335
|
+
# puts "via s (2): #{self.inspect}"
|
329
336
|
return self.to_s.to_f
|
330
337
|
end
|
331
338
|
end
|
@@ -456,4 +463,33 @@ class Bignum
|
|
456
463
|
|
457
464
|
end
|
458
465
|
|
466
|
+
def LongMath.continued_fraction(x, steps)
|
467
|
+
if (x == 0)
|
468
|
+
x
|
469
|
+
end
|
470
|
+
arr = []
|
471
|
+
steps.times do
|
472
|
+
xi = x.to_ld(0, LongMath::ROUND_FLOOR)
|
473
|
+
xd = x-xi
|
474
|
+
if xd.zero?
|
475
|
+
return arr
|
476
|
+
end
|
477
|
+
x = 1/xd
|
478
|
+
arr.push(xi.to_i)
|
479
|
+
end
|
480
|
+
arr
|
481
|
+
end
|
482
|
+
|
483
|
+
def LongMath.continued_fraction_to_r(arr)
|
484
|
+
result = nil
|
485
|
+
arr.reverse.each do |x|
|
486
|
+
if (result.nil?)
|
487
|
+
result = Rational(x)
|
488
|
+
else
|
489
|
+
result = Rational(x) + 1/result
|
490
|
+
end
|
491
|
+
end
|
492
|
+
result
|
493
|
+
end
|
494
|
+
|
459
495
|
# end of file long-decimal-extra.rb
|
data/lib/long-decimal.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
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-
|
4
|
+
# (C) Karl Brodowsky (IT Sky Consulting GmbH) 2006-2015
|
5
5
|
#
|
6
6
|
# This class contains the basic functionality for working with LongDecimal
|
7
7
|
# additional functionality, mostly transcendental functions,
|
8
8
|
# may be found in long-decimal-extra.rb
|
9
9
|
#
|
10
|
+
# TAG: $TAG v1.00.03$
|
10
11
|
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.87 2011/01/30 20:01:40 bk1 Exp $
|
11
12
|
# CVS-Label: $Name: $
|
12
13
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
@@ -50,6 +51,8 @@ module LongDecimalRoundingMode
|
|
50
51
|
private
|
51
52
|
|
52
53
|
ALL_MINOR = [ MINOR_UP, MINOR_DOWN, MINOR_CEILING, MINOR_FLOOR, MINOR_EVEN, MINOR_ODD ]
|
54
|
+
# puts(ALL_MINOR)
|
55
|
+
# puts
|
53
56
|
|
54
57
|
NO_MINOR = [ MINOR_UNUSED ]
|
55
58
|
|
@@ -105,6 +108,9 @@ module LongDecimalRoundingMode
|
|
105
108
|
|
106
109
|
ALL_MAJOR_MODES = [ MAJOR_UP, MAJOR_DOWN, MAJOR_CEILING, MAJOR_FLOOR, MAJOR_UNNECESSARY, MAJOR_HALF, MAJOR_GEOMETRIC, MAJOR_HARMONIC, MAJOR_QUADRATIC, MAJOR_CUBIC ]
|
107
110
|
|
111
|
+
# puts("ALL_MAJOR_MODES:")
|
112
|
+
# puts(ALL_MAJOR_MODES)
|
113
|
+
# puts
|
108
114
|
|
109
115
|
MUL_INVERSE_MAJOR_MODE = {
|
110
116
|
MAJOR_UP => MAJOR_DOWN,
|
@@ -298,9 +304,9 @@ module LongDecimalRoundingMode
|
|
298
304
|
on_boundary = true
|
299
305
|
end
|
300
306
|
elsif (major == MAJOR_CUBIC)
|
301
|
-
cube = unrounded
|
307
|
+
cube = unrounded ** 3
|
302
308
|
lhs = 2 * cube
|
303
|
-
rhs = lower
|
309
|
+
rhs = lower ** 3 + upper ** 3
|
304
310
|
d = lhs <=> rhs
|
305
311
|
if (d < 0)
|
306
312
|
# unrounded < x_cubic(lower, upper)
|
@@ -382,7 +388,9 @@ module LongDecimalRoundingMode
|
|
382
388
|
end
|
383
389
|
|
384
390
|
ALL_ROUNDING_MODES.freeze
|
391
|
+
# puts(ALL_ROUNDING_MODES)
|
385
392
|
MODE_LOOKUP.freeze
|
393
|
+
# puts(MODE_LOOKUP)
|
386
394
|
|
387
395
|
ALL_ROUNDING_MODES.each do |rm|
|
388
396
|
majm = rm.major
|
@@ -391,6 +399,7 @@ module LongDecimalRoundingMode
|
|
391
399
|
MUL_INVERSE_MODE[rm] = mul_inv
|
392
400
|
add_inv = MODE_LOOKUP[[ ADD_INVERSE_MAJOR_MODE[majm], ADD_INVERSE_MINOR_MODE[minm]]]
|
393
401
|
ADD_INVERSE_MODE[rm] = add_inv
|
402
|
+
# puts("rm=#{rm} mul_inv=#{mul_inv} add_inv=#{add_inv}")
|
394
403
|
end
|
395
404
|
|
396
405
|
MUL_INVERSE_MODE.freeze
|
@@ -614,6 +623,7 @@ class Integer
|
|
614
623
|
end
|
615
624
|
lower = self - (r_self - r_lower)
|
616
625
|
upper = self + (r_upper - r_self)
|
626
|
+
# puts "round_to_allowed_remainders(remainders_param=#{remainders_param} modulus=#{modulus} rounding_mode=#{rounding_mode} zero_rounding_mode=#{zero_rounding_mode}) remainders=#{remainders} lower=#{lower} upper=#{upper} r_lower=#{r_lower} r_upper=#{r_upper} r_self=#{r_self}"
|
617
627
|
|
618
628
|
unless (lower < self && self < upper)
|
619
629
|
raise ArgumentError, "self=#{self} not in (#{lower}, #{upper}) with r_self=#{r_self} r_lower=#{r_lower} r_upper=#{r_upper}"
|
@@ -1440,6 +1450,7 @@ class LongDecimal < LongDecimalBase
|
|
1440
1450
|
# result 0.0 if int_val == 0
|
1441
1451
|
if (int_val == 0)
|
1442
1452
|
# t1
|
1453
|
+
# puts "t1 #{self.to_s}=#{self.inspect} -> 0.0"
|
1443
1454
|
return 0.0
|
1444
1455
|
end
|
1445
1456
|
|
@@ -1447,12 +1458,15 @@ class LongDecimal < LongDecimalBase
|
|
1447
1458
|
if (int_val.abs <= LongMath::MAX_FLOATABLE)
|
1448
1459
|
y = int_val.to_f
|
1449
1460
|
# t2
|
1461
|
+
# puts "t2 #{self.to_s}=#{self.inspect} -> #{y}"
|
1450
1462
|
return y
|
1451
1463
|
elsif int_val < 0
|
1452
1464
|
# t13
|
1465
|
+
# puts "t13 #{self.to_s}=#{self.inspect} -> -Infinity"
|
1453
1466
|
return -1.0/0.0
|
1454
1467
|
elsif int_val > 0
|
1455
1468
|
# t14
|
1469
|
+
# puts "t13 #{self.to_s}=#{self.inspect} -> Infinity"
|
1456
1470
|
return 1.0/0.0
|
1457
1471
|
end
|
1458
1472
|
end
|
@@ -1461,6 +1475,7 @@ class LongDecimal < LongDecimalBase
|
|
1461
1475
|
if (self < 0) then
|
1462
1476
|
y = -(-self).to_f
|
1463
1477
|
# t3
|
1478
|
+
# puts "t3 #{self.to_s}=#{self.inspect} -> #{y}"
|
1464
1479
|
return y
|
1465
1480
|
end
|
1466
1481
|
|
@@ -1468,6 +1483,7 @@ class LongDecimal < LongDecimalBase
|
|
1468
1483
|
if (int_val <= LongMath::MAX_FLOATABLE && scale <= Float::MAX_10_EXP)
|
1469
1484
|
y = to_f_simple(int_val, scale)
|
1470
1485
|
# t4
|
1486
|
+
# puts "t4 #{self.to_s}=#{self.inspect} -> #{y}"
|
1471
1487
|
return y
|
1472
1488
|
end
|
1473
1489
|
|
@@ -1477,6 +1493,7 @@ class LongDecimal < LongDecimalBase
|
|
1477
1493
|
# handle overflow: raise exception
|
1478
1494
|
if (int_val > divisor * LongMath::MAX_FLOATABLE) then
|
1479
1495
|
# t5
|
1496
|
+
# puts "t5 #{self.to_s}=#{self.inspect} -> Infinity"
|
1480
1497
|
return 1/0.0 # Infinity
|
1481
1498
|
end
|
1482
1499
|
|
@@ -1484,6 +1501,7 @@ class LongDecimal < LongDecimalBase
|
|
1484
1501
|
# handle underflow: return 0.0
|
1485
1502
|
if (int_val * LongMath::INV_MIN_FLOATABLE * 20 < divisor) then
|
1486
1503
|
# t6
|
1504
|
+
# puts "t6 #{self.to_s}=#{self.inspect} -> 0.0"
|
1487
1505
|
p = int_val * LongMath::INV_MIN_FLOATABLE * 20
|
1488
1506
|
d = divisor
|
1489
1507
|
n = int_val
|
@@ -1503,11 +1521,13 @@ class LongDecimal < LongDecimalBase
|
|
1503
1521
|
y *= q
|
1504
1522
|
if (y == 0.0)
|
1505
1523
|
# t7
|
1524
|
+
# puts "t7 #{self.to_s}=#{self.inspect} -> #{y}"
|
1506
1525
|
return y
|
1507
1526
|
end
|
1508
1527
|
s -= qe
|
1509
1528
|
end
|
1510
1529
|
# t8
|
1530
|
+
# puts "t8 #{self.to_s}=#{self.inspect} -> #{y}"
|
1511
1531
|
return y
|
1512
1532
|
end
|
1513
1533
|
|
@@ -1520,6 +1540,7 @@ class LongDecimal < LongDecimalBase
|
|
1520
1540
|
# scale = 0, 0 < int_val <= MAX_FLOATABLE
|
1521
1541
|
y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
|
1522
1542
|
# t9
|
1543
|
+
# puts "t9 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} -> #{y}"
|
1523
1544
|
return y
|
1524
1545
|
end
|
1525
1546
|
|
@@ -1530,6 +1551,7 @@ class LongDecimal < LongDecimalBase
|
|
1530
1551
|
|
1531
1552
|
if (cmp == 0)
|
1532
1553
|
# t10
|
1554
|
+
# puts "t10 #{self.to_s}=#{self.inspect} -> 1.0"
|
1533
1555
|
return 1.0
|
1534
1556
|
elsif (cmp > 0)
|
1535
1557
|
# self > 1, retain MAX_SIGNIFICANT_FLOATABLE_DIGITS
|
@@ -1537,6 +1559,7 @@ class LongDecimal < LongDecimalBase
|
|
1537
1559
|
# self >= LongMath::FLOATABLE_WITHOUT_FRACTION > self > 1, scale = 16,
|
1538
1560
|
y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
|
1539
1561
|
# t11
|
1562
|
+
# puts "t11 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} -> #{y}"
|
1540
1563
|
return y
|
1541
1564
|
else
|
1542
1565
|
# self < 1
|
@@ -1552,6 +1575,7 @@ class LongDecimal < LongDecimalBase
|
|
1552
1575
|
rounded_ld = round_to_scale(new_scale, ROUND_HALF_UP)
|
1553
1576
|
y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
|
1554
1577
|
# t12
|
1578
|
+
# puts "t12 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} sd=#{sd} #{self <=> 1} -> #{y}"
|
1555
1579
|
return y
|
1556
1580
|
end
|
1557
1581
|
end
|
@@ -1668,11 +1692,21 @@ class LongDecimal < LongDecimalBase
|
|
1668
1692
|
#
|
1669
1693
|
def sint_digits10
|
1670
1694
|
if (@digits10.nil?)
|
1671
|
-
|
1695
|
+
result = LongMath.int_digits10(int_val) - scale
|
1696
|
+
if frozen?
|
1697
|
+
return result
|
1698
|
+
end
|
1699
|
+
@digits10 = result
|
1672
1700
|
end
|
1673
1701
|
@digits10
|
1674
1702
|
end
|
1675
1703
|
|
1704
|
+
# freeze but calcuate sint_digits10 before
|
1705
|
+
def freeze_ld
|
1706
|
+
sint_digits10
|
1707
|
+
freeze
|
1708
|
+
end
|
1709
|
+
|
1676
1710
|
#
|
1677
1711
|
# number of decimal digits before the decimal point, not counting a
|
1678
1712
|
# single 0.
|
@@ -2191,9 +2225,11 @@ class LongDecimal < LongDecimalBase
|
|
2191
2225
|
# s, o = other.coerce(self.to_f)
|
2192
2226
|
if (RUNNING_19)
|
2193
2227
|
s, o = other.coerce(self)
|
2228
|
+
# puts "complex coerce 19: #{self}, #{other} -> #{s}, #{o}"
|
2194
2229
|
return o, s
|
2195
2230
|
else
|
2196
2231
|
s, o = other.coerce(Complex(self, 0))
|
2232
|
+
# puts "complex coerce 18/J: #{self}, #{other} -> #{s}, #{o}"
|
2197
2233
|
return o, s
|
2198
2234
|
end
|
2199
2235
|
# s, o = other.coerce(Complex(self.to_f, 0))
|
@@ -2529,6 +2565,7 @@ class LongDecimalQuot < LongDecimalBase
|
|
2529
2565
|
if (s.kind_of? LongDecimalQuot) then
|
2530
2566
|
LongDecimalQuot(s.rat - o.rat, [s.scale, o.scale].max)
|
2531
2567
|
else
|
2568
|
+
# puts "ldq-coerce: s=#{s} o=#{o} self=#{self} other=#{other}"
|
2532
2569
|
s - o
|
2533
2570
|
end
|
2534
2571
|
end
|
@@ -2803,6 +2840,9 @@ class Numeric
|
|
2803
2840
|
# optional second argument gives the rouding mode
|
2804
2841
|
#
|
2805
2842
|
def to_ld(prec = nil, mode = LongMath.standard_mode)
|
2843
|
+
if (kind_of? Complex)
|
2844
|
+
return Complex(real.to_ld(prec, mode), imaginary.to_ld(prec, mode))
|
2845
|
+
end
|
2806
2846
|
l = LongDecimal(self)
|
2807
2847
|
if (prec.nil?)
|
2808
2848
|
return l
|
@@ -2937,7 +2977,9 @@ class Rational
|
|
2937
2977
|
def to_f
|
2938
2978
|
num = numerator
|
2939
2979
|
den = denominator
|
2980
|
+
# puts("num=#{num} den=#{den}")
|
2940
2981
|
sign = num <=> 0
|
2982
|
+
# puts("num=#{num} den=#{den} sign=#{sign}")
|
2941
2983
|
if (sign.zero?)
|
2942
2984
|
return 0.0
|
2943
2985
|
elsif sign < 0
|
@@ -3022,7 +3064,9 @@ module LongMath
|
|
3022
3064
|
if (power.nil?)
|
3023
3065
|
power = powers_big_base ** n1
|
3024
3066
|
@@powers_of_big_base[n1] = power
|
3067
|
+
# puts "npower_of_big_base(n1=#{n1}) c->#{power.size}"
|
3025
3068
|
else
|
3069
|
+
# puts "npower_of_big_base(n1=#{n1}) c<-#{power.size}"
|
3026
3070
|
end
|
3027
3071
|
power
|
3028
3072
|
end
|
@@ -3173,6 +3217,21 @@ module LongMath
|
|
3173
3217
|
return
|
3174
3218
|
end
|
3175
3219
|
end
|
3220
|
+
key.freeze
|
3221
|
+
if (val.kind_of? LongDecimal)
|
3222
|
+
val.freeze_ld
|
3223
|
+
elsif (val.kind_of? Array)
|
3224
|
+
val.each do |entry|
|
3225
|
+
if (entry.kind_of? LongDecimal)
|
3226
|
+
entry.freeze_ld
|
3227
|
+
else
|
3228
|
+
entry.freeze
|
3229
|
+
end
|
3230
|
+
end
|
3231
|
+
val.freeze
|
3232
|
+
else
|
3233
|
+
val.freeze
|
3234
|
+
end
|
3176
3235
|
@@cache[key] = val
|
3177
3236
|
end
|
3178
3237
|
end
|
@@ -3244,8 +3303,11 @@ module LongMath
|
|
3244
3303
|
n1 = n >> POWERS_MED_EXP_PARAM
|
3245
3304
|
p = npower10_cached(n0)
|
3246
3305
|
if (n1 > 0) then
|
3306
|
+
# puts "n0=#{n0} n1=#{n1}"
|
3247
3307
|
p1 = npower_of_big_base(n1)
|
3308
|
+
# puts "n0=#{n0} n1=#{n1} p1"
|
3248
3309
|
p *= p1
|
3310
|
+
# puts "n0=#{n0} n1=#{n1} p"
|
3249
3311
|
end
|
3250
3312
|
return p
|
3251
3313
|
end
|
@@ -4031,7 +4093,7 @@ module LongMath
|
|
4031
4093
|
end
|
4032
4094
|
cache_key = nil
|
4033
4095
|
y_arr = nil
|
4034
|
-
unless (with_rem)
|
4096
|
+
unless (with_rem || mode.major == MAJOR_GEOMETRIC || mode.major == MAJOR_QUADRATIC)
|
4035
4097
|
cache_key = get_cache_key("sqrt", x, mode, [2, 3, 5, 6, 7, 8, 10])
|
4036
4098
|
y_arr = get_cached(cache_key, x, prec)
|
4037
4099
|
end
|
@@ -4046,8 +4108,43 @@ module LongMath
|
|
4046
4108
|
return y_arr
|
4047
4109
|
else
|
4048
4110
|
y, r = y_arr
|
4049
|
-
if (
|
4050
|
-
|
4111
|
+
if (mode.major == MAJOR_GEOMETRIC || mode.major == MAJOR_QUADRATIC)
|
4112
|
+
# we need to deal with the case that the square root is on the exact border
|
4113
|
+
y_lower = y.round_to_scale(prec, ROUND_DOWN)
|
4114
|
+
y_upper = y.round_to_scale(prec, ROUND_UP)
|
4115
|
+
# puts "mode=#{mode} x=#{x} y=#{y} r=#{r} y_lower=#{y_lower} y_upper=#{y_upper} prec=#{prec} prec1=#{prec1}"
|
4116
|
+
if (r == 0)
|
4117
|
+
if (y == y_lower)
|
4118
|
+
# puts "r=0 y=y_lower=#{y_lower} (x=#{x} y_upper=#{y_upper} mode=#{mode})"
|
4119
|
+
return y_lower
|
4120
|
+
elsif (y == y_upper)
|
4121
|
+
# puts "r=0 y=y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} mode=#{mode})"
|
4122
|
+
return y_upper
|
4123
|
+
end
|
4124
|
+
end
|
4125
|
+
# puts "mode=#{mode} x=#{x} gm2=#{y_lower * y_upper} qm2=#{arithmetic_mean(prec*2+1, ROUND_HALF_UP, y_lower*y_lower, y_upper*y_upper)}"
|
4126
|
+
if (mode.major == MAJOR_GEOMETRIC && x == y_lower * y_upper \
|
4127
|
+
|| mode.major == MAJOR_QUADRATIC && x == arithmetic_mean(prec1*2+1, ROUND_HALF_UP, y_lower*y_lower, y_upper*y_upper))
|
4128
|
+
if (mode.minor == MINOR_UP || mode.minor == MINOR_CEILING)
|
4129
|
+
# puts "r=0 y=#{y} on boundary: y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} mode=#{mode})"
|
4130
|
+
return y_upper;
|
4131
|
+
elsif (mode.minor == MINOR_DOWN || mode.minor == MINOR_FLOOR)
|
4132
|
+
# puts "r=0 y=#{y} on boundary: y_lower=#{y_lower} (x=#{x} y_upper=#{y_upper} mode=#{mode})"
|
4133
|
+
return y_lower;
|
4134
|
+
elsif (mode.minor == MINOR_EVEN && y_upper[0] == 0 || mode.minor == MINOR_ODD && y_upper[0] == 1)
|
4135
|
+
# puts "r=0 y=#{y} on boundary odd/even: y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} y_upper=#{y_upper} mode=#{mode})"
|
4136
|
+
return y_upper;
|
4137
|
+
elsif (mode.minor == MINOR_EVEN && y_lower[0] == 0 || mode.minor == MINOR_ODD && y_lower[0] == 1)
|
4138
|
+
# puts "r=0 y=#{y} on boundary odd/even: y_lower=#{y_lower} (x=#{x} y_lower=#{y_lower} y_upper=#{y_upper} mode=#{mode})"
|
4139
|
+
return y_lower;
|
4140
|
+
else
|
4141
|
+
raise ArgumentError, "unsupported combination: x=#{x} prec=#{prec} prec1=#{prec1} mode=#{mode} y=#{y} r=#{r} y_lower=#{y_lower} y_upper=#{y_upper}"
|
4142
|
+
end
|
4143
|
+
end
|
4144
|
+
end
|
4145
|
+
|
4146
|
+
if ((mode.minor == MINOR_EVEN || mode.minor == MINOR_ODD || mode.minor == MINOR_DOWN || mode.minor == MINOR_FLOOR) && r > 0) then
|
4147
|
+
mode = MODE_LOOKUP[[mode.major, MINOR_UP]];
|
4051
4148
|
end
|
4052
4149
|
y = y.round_to_scale(prec, mode)
|
4053
4150
|
return y
|
@@ -4099,7 +4196,7 @@ module LongMath
|
|
4099
4196
|
end
|
4100
4197
|
cache_key = nil
|
4101
4198
|
y_arr = nil
|
4102
|
-
unless (with_rem)
|
4199
|
+
unless (with_rem || mode.major == MAJOR_CUBIC)
|
4103
4200
|
cache_key = get_cache_key("cbrt", x, mode, [2, 3, 5, 6, 7, 8, 10])
|
4104
4201
|
y_arr = get_cached(cache_key, x, prec)
|
4105
4202
|
end
|
@@ -4114,8 +4211,42 @@ module LongMath
|
|
4114
4211
|
return y_arr
|
4115
4212
|
else
|
4116
4213
|
y, r = y_arr
|
4117
|
-
if (
|
4118
|
-
|
4214
|
+
if (mode.major == MAJOR_CUBIC)
|
4215
|
+
# we need to deal with the case that the square root is on the exact border
|
4216
|
+
y_lower = y.round_to_scale(prec, ROUND_DOWN)
|
4217
|
+
y_upper = y.round_to_scale(prec, ROUND_UP)
|
4218
|
+
# puts "mode=#{mode} x=#{x} y=#{y} r=#{r} y_lower=#{y_lower} y_upper=#{y_upper} prec=#{prec} prec1=#{prec1}"
|
4219
|
+
if (r == 0)
|
4220
|
+
if (y == y_lower)
|
4221
|
+
# puts "r=0 y=y_lower=#{y_lower} (x=#{x} y_upper=#{y_upper} mode=#{mode})"
|
4222
|
+
return y_lower
|
4223
|
+
elsif (y == y_upper)
|
4224
|
+
# puts "r=0 y=y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} mode=#{mode})"
|
4225
|
+
return y_upper
|
4226
|
+
end
|
4227
|
+
end
|
4228
|
+
# puts "mode=#{mode} x=#{x} gm2=#{y_lower * y_upper} qm2=#{arithmetic_mean(prec*2+1, ROUND_HALF_UP, y_lower*y_lower, y_upper*y_upper)}"
|
4229
|
+
if (mode.major == MAJOR_CUBIC && x == arithmetic_mean(prec1*3+1, ROUND_HALF_UP, y_lower.cube(), y_upper.cube()))
|
4230
|
+
if (mode.minor == MINOR_UP || mode.minor == MINOR_CEILING)
|
4231
|
+
# puts "r=0 y=#{y} on boundary: y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} mode=#{mode})"
|
4232
|
+
return y_upper;
|
4233
|
+
elsif (mode.minor == MINOR_DOWN || mode.minor == MINOR_FLOOR)
|
4234
|
+
# puts "r=0 y=#{y} on boundary: y_lower=#{y_lower} (x=#{x} y_upper=#{y_upper} mode=#{mode})"
|
4235
|
+
return y_lower;
|
4236
|
+
elsif (mode.minor == MINOR_EVEN && y_upper[0] == 0 || mode.minor == MINOR_ODD && y_upper[0] == 1)
|
4237
|
+
# puts "r=0 y=#{y} on boundary odd/even: y_upper=#{y_upper} (x=#{x} y_lower=#{y_lower} y_upper=#{y_upper} mode=#{mode})"
|
4238
|
+
return y_upper;
|
4239
|
+
elsif (mode.minor == MINOR_EVEN && y_lower[0] == 0 || mode.minor == MINOR_ODD && y_lower[0] == 1)
|
4240
|
+
# puts "r=0 y=#{y} on boundary odd/even: y_lower=#{y_lower} (x=#{x} y_lower=#{y_lower} y_upper=#{y_upper} mode=#{mode})"
|
4241
|
+
return y_lower;
|
4242
|
+
else
|
4243
|
+
raise ArgumentError, "unsupported combination: x=#{x} prec=#{prec} prec1=#{prec1} mode=#{mode} y=#{y} r=#{r} y_lower=#{y_lower} y_upper=#{y_upper}"
|
4244
|
+
end
|
4245
|
+
end
|
4246
|
+
end
|
4247
|
+
|
4248
|
+
if ((mode.minor == MINOR_EVEN || mode.minor == MINOR_ODD || mode.minor == MINOR_DOWN || mode.minor == MINOR_FLOOR) && r > 0) then
|
4249
|
+
mode = MODE_LOOKUP[[mode.major, MINOR_UP]];
|
4119
4250
|
end
|
4120
4251
|
y = y.round_to_scale(prec, mode)
|
4121
4252
|
return y
|
@@ -4661,6 +4792,7 @@ module LongMath
|
|
4661
4792
|
raise TypeError, "x=#{x.inspect} must not negative" unless x >= 0
|
4662
4793
|
prec = check_is_prec(prec, "prec")
|
4663
4794
|
check_is_mode(mode, "mode")
|
4795
|
+
# puts "LongMath.power(x=#{x} y=#{y} prec=#{prec} mode=#{mode})"
|
4664
4796
|
|
4665
4797
|
# handle the special cases where base or exponent are 0 or 1 explicitely
|
4666
4798
|
if y.zero? then
|
@@ -4677,8 +4809,10 @@ module LongMath
|
|
4677
4809
|
# x ** y <= 10**-s/2 <=> y * log(x) <= -s log(10) - log(2)
|
4678
4810
|
|
4679
4811
|
iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
|
4812
|
+
# 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}"
|
4680
4813
|
$stdout.flush
|
4681
4814
|
if (x < 1 && y > 0 || x > 1 && y < 0) then
|
4815
|
+
# puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
|
4682
4816
|
if (logx_y_f <= - prec * LOG10 - LOG2) then
|
4683
4817
|
return LongDecimal.zero!(prec)
|
4684
4818
|
end
|
@@ -4728,8 +4862,10 @@ module LongMath
|
|
4728
4862
|
y = -y
|
4729
4863
|
x = (1/x).round_to_scale(iprec_x*2, mode)
|
4730
4864
|
iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
|
4865
|
+
# 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}"
|
4731
4866
|
$stdout.flush
|
4732
4867
|
if (x < 1 && y > 0 || x > 1 && y < 0) then
|
4868
|
+
# puts "checking if zero logx_y_f=#{logx_y_f} <= #{- prec * LOG10 - LOG2}"
|
4733
4869
|
if (logx_y_f <= - prec * LOG10 - LOG2) then
|
4734
4870
|
return LongDecimal.zero!(prec)
|
4735
4871
|
end
|
@@ -4741,12 +4877,14 @@ module LongMath
|
|
4741
4877
|
y0 = y.round_to_scale(0, LongMath.standard_imode).to_i
|
4742
4878
|
x0 = x
|
4743
4879
|
point_shift = 0
|
4880
|
+
# puts "x0=#{x0} y0=#{y0}"
|
4744
4881
|
while x0 > LongMath::MAX_FLOATABLE
|
4745
4882
|
x0 = x0.move_point_left(100)
|
4746
4883
|
point_shift += 100
|
4747
4884
|
end
|
4748
4885
|
iprec2 = 2 * (iprec + point_shift)
|
4749
4886
|
iprec3 = [ iprec2, LongMath.prec_limit() - 24 ].min
|
4887
|
+
# puts "x0=#{x0} y0=#{y0} point_shift=#{point_shift} iprec=#{iprec} iprec2=#{iprec2} iprec3=#{iprec3}"
|
4750
4888
|
z0 = LongMath.ipower(x0, y0, iprec3, mode)
|
4751
4889
|
if (point_shift > 0)
|
4752
4890
|
unless z0.kind_of? LongDecimal
|
@@ -4762,6 +4900,7 @@ module LongMath
|
|
4762
4900
|
# z1 = LongMath.power_internal(x, y1, prec+prec_extra , mode)
|
4763
4901
|
z1 = LongMath.power_internal(x, y1, prec+prec_extra + 4, mode)
|
4764
4902
|
z = z0 * z1
|
4903
|
+
# puts("x=#{x} y=#{y} z=#{z} y not int")
|
4765
4904
|
return z.to_ld(prec, mode)
|
4766
4905
|
end
|
4767
4906
|
|
@@ -4780,10 +4919,12 @@ module LongMath
|
|
4780
4919
|
raise TypeError, "exponent y=#{y.inspect} must not be greater MAX_FLOATABLE=#{MAX_FLOATABLE}" unless y.abs <= MAX_FLOATABLE
|
4781
4920
|
prec = check_is_prec(prec, "prec")
|
4782
4921
|
check_is_mode(mode, "mode")
|
4922
|
+
# puts "LongMath.ipower(x=#{x} y=#{y} prec=#{prec} mode=#{mode})"
|
4783
4923
|
|
4784
4924
|
if (y.zero?)
|
4785
4925
|
return 1
|
4786
4926
|
elsif ! (x.kind_of? LongDecimalBase) || x.scale * y.abs <= prec
|
4927
|
+
# puts "x=#{x} y=#{y} using **"
|
4787
4928
|
return x ** y
|
4788
4929
|
elsif (y < 0)
|
4789
4930
|
l = Math.log10(x.abs.to_f)
|
@@ -4792,10 +4933,12 @@ module LongMath
|
|
4792
4933
|
end
|
4793
4934
|
# return (1/LongMath.ipower(x, -y, prec + 2, mode)).round_to_scale(prec, mode)
|
4794
4935
|
xi = 1/x
|
4936
|
+
# puts "x=#{x} y=#{y} prec=#{prec} using (1/x)**y xi=#{xi}"
|
4795
4937
|
xr = xi.round_to_scale(prec + 6, mode)
|
4796
4938
|
return LongMath.ipower(xr, -y, prec, mode)
|
4797
4939
|
else
|
4798
4940
|
# y > 0
|
4941
|
+
# puts "x=#{x} y=#{y} regular"
|
4799
4942
|
cnt = 0
|
4800
4943
|
z = x
|
4801
4944
|
y0 = y
|
@@ -4816,6 +4959,7 @@ module LongMath
|
|
4816
4959
|
x = x.round_to_scale(prec+4, mode)
|
4817
4960
|
end
|
4818
4961
|
if (cnt > 1000)
|
4962
|
+
# puts("ipower x=#{x} y=#{y} cnt=#{cnt} z=#{z} t=#{Time.now - t0}")
|
4819
4963
|
cnt = 0
|
4820
4964
|
end
|
4821
4965
|
|
@@ -4828,7 +4972,9 @@ module LongMath
|
|
4828
4972
|
end
|
4829
4973
|
end
|
4830
4974
|
end
|
4975
|
+
# puts "z=#{z} rounding prec=#{prec}"
|
4831
4976
|
z = z.round_to_scale(prec, mode)
|
4977
|
+
# puts "rounded -> z=#{z}"
|
4832
4978
|
return z
|
4833
4979
|
end
|
4834
4980
|
end
|
@@ -4934,7 +5080,7 @@ module LongMath
|
|
4934
5080
|
if (args.empty?)
|
4935
5081
|
raise ArgumentError, "cannot calculate average of empty array"
|
4936
5082
|
end
|
4937
|
-
sum = args.inject(
|
5083
|
+
sum = args.inject(LongDecimal.zero!((1.5*new_scale + 25).to_i)) do |psum,x|
|
4938
5084
|
psum + x
|
4939
5085
|
end
|
4940
5086
|
raw_result = if (sum.kind_of? Integer)
|
@@ -4943,6 +5089,21 @@ module LongMath
|
|
4943
5089
|
sum / args.size
|
4944
5090
|
end
|
4945
5091
|
result = raw_result.to_ld(new_scale, rounding_mode)
|
5092
|
+
# puts "sum=#{sum} args.size=#{args.size} raw_result=#{raw_result} result=#{result} new_scale=#{new_scale} rounding_mode=#{rounding_mode}"
|
5093
|
+
return result
|
5094
|
+
end
|
5095
|
+
|
5096
|
+
# arithmetic mean with LongDecimalQuot as result (experimental)
|
5097
|
+
# parameters arguments for which arithmetic mean is calculated
|
5098
|
+
# result is exact if parameters are Integer, LongDecimal, LongDecimalQuot or Rational
|
5099
|
+
def LongMath.arithmetic_mean_ldq(*args)
|
5100
|
+
if (args.empty?)
|
5101
|
+
raise ArgumentError, "cannot calculate average of empty array"
|
5102
|
+
end
|
5103
|
+
sum = args.inject(LongDecimalQuot(0, 0)) do |psum,x|
|
5104
|
+
psum + x
|
5105
|
+
end
|
5106
|
+
result = sum / args.size
|
4946
5107
|
return result
|
4947
5108
|
end
|
4948
5109
|
|
@@ -4959,7 +5120,7 @@ module LongMath
|
|
4959
5120
|
if (has_zero)
|
4960
5121
|
return LongDecimal.zero!(new_scale)
|
4961
5122
|
end
|
4962
|
-
prod = args.inject(
|
5123
|
+
prod = args.inject(LongDecimal.one!(new_scale + 20)) do |pprod, x|
|
4963
5124
|
pprod * x.abs
|
4964
5125
|
end
|
4965
5126
|
result = nil
|
@@ -4988,11 +5149,11 @@ module LongMath
|
|
4988
5149
|
if (has_zero)
|
4989
5150
|
raise ArgumentError, "cannot calculate harmonic mean of argument list containing zero #{args.inspect}"
|
4990
5151
|
end
|
4991
|
-
sum = args.inject(
|
5152
|
+
sum = args.inject(LongDecimal.zero!) do |psum, x|
|
4992
5153
|
psum + if (x.kind_of? Integer)
|
4993
5154
|
Rational(1, x)
|
4994
5155
|
else
|
4995
|
-
1/x
|
5156
|
+
LongDecimal.one!(new_scale+1)/x
|
4996
5157
|
end
|
4997
5158
|
end
|
4998
5159
|
raw_result = args.size / sum
|
@@ -5000,6 +5161,28 @@ module LongMath
|
|
5000
5161
|
return result
|
5001
5162
|
end
|
5002
5163
|
|
5164
|
+
# harmonic mean with LongDecimalQuot as result (experimental)
|
5165
|
+
# parameters arguments for which arithmetic mean is calculated
|
5166
|
+
# result is exact if parameters are Integer, LongDecimal, LongDecimalQuot or Rational
|
5167
|
+
def LongMath.harmonic_mean_ldq(*args)
|
5168
|
+
result_sign, all_same, has_neg, has_zero, has_pos = sign_check_for_mean(true, *args)
|
5169
|
+
if (all_same)
|
5170
|
+
return LongDecimalQuot(args)
|
5171
|
+
end
|
5172
|
+
if (has_zero)
|
5173
|
+
raise ArgumentError, "cannot calculate harmonic mean of argument list containing zero #{args.inspect}"
|
5174
|
+
end
|
5175
|
+
sum = args.inject(LongDecimalQuot(0, 0)) do |psum, x|
|
5176
|
+
psum + if (x.kind_of? Integer)
|
5177
|
+
Rational(1, x)
|
5178
|
+
else
|
5179
|
+
1 / x
|
5180
|
+
end
|
5181
|
+
end
|
5182
|
+
result = args.size / sum
|
5183
|
+
return result
|
5184
|
+
end
|
5185
|
+
|
5003
5186
|
# arithmetic-geometric mean (AGM)
|
5004
5187
|
def LongMath.arithmetic_geometric_mean(new_scale, rounding_mode, *args)
|
5005
5188
|
result_sign, all_same, has_neg, has_zero, has_pos = sign_check_for_mean(true, *args)
|
@@ -5044,7 +5227,10 @@ module LongMath
|
|
5044
5227
|
if (all_same)
|
5045
5228
|
return args[0].to_ld(new_scale, rounding_mode)
|
5046
5229
|
end
|
5047
|
-
sum = args.inject(
|
5230
|
+
sum = args.inject(LongDecimal.zero!) do |psum, x|
|
5231
|
+
if (! (x.kind_of? LongDecimalBase) && ! (x.kind_of? Rational))
|
5232
|
+
x = x.to_ld(2*new_scale + 20)
|
5233
|
+
end
|
5048
5234
|
psum + x*x
|
5049
5235
|
end
|
5050
5236
|
quot = if (sum.kind_of? Integer)
|
@@ -5065,11 +5251,14 @@ module LongMath
|
|
5065
5251
|
if (all_same)
|
5066
5252
|
return args[0].to_ld(new_scale, rounding_mode)
|
5067
5253
|
end
|
5068
|
-
sum = args.inject(
|
5254
|
+
sum = args.inject(LongDecimal.zero!) do |psum, x|
|
5069
5255
|
if (x.kind_of? Complex)
|
5070
5256
|
raise ArgumentError, "cubic mean not supported for complex numbers args=#{args.inspect}"
|
5071
5257
|
end
|
5072
|
-
|
5258
|
+
if (! (x.kind_of? LongDecimalBase) && ! (x.kind_of? Rational))
|
5259
|
+
x = x.to_ld(2*new_scale + 20)
|
5260
|
+
end
|
5261
|
+
psum + x ** 3
|
5073
5262
|
end
|
5074
5263
|
quot = if (sum.kind_of? Integer)
|
5075
5264
|
Rational(sum, args.size)
|
@@ -5107,6 +5296,7 @@ module LongMath
|
|
5107
5296
|
|
5108
5297
|
# round elements in such a way that round(new_scale, rounding_mode_sum, sum(elements)) = sum(elements_rounded)
|
5109
5298
|
# HAARE_NIEMEYER
|
5299
|
+
# (experimental)
|
5110
5300
|
def LongMath.round_sum_hm(new_scale, rounding_mode_sum, *elements)
|
5111
5301
|
if (elements.empty?)
|
5112
5302
|
return elements
|
@@ -5136,6 +5326,7 @@ module LongMath
|
|
5136
5326
|
|
5137
5327
|
# round elements in such a way that round(new_scale, rounding_mode, sum(elements)) = sum(elements_rounded)
|
5138
5328
|
# where rounding_mode_set is
|
5329
|
+
# (experimental)
|
5139
5330
|
def LongMath.round_sum_divisor(new_scale, rounding_mode_sum, rounding_mode_set, *elements)
|
5140
5331
|
if (elements.empty?)
|
5141
5332
|
return elements
|