long-decimal 1.00.02 → 1.00.03
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.
- 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
|