long-decimal 0.01.01 → 0.01.02
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 +17 -94
- data/VERSION +1 -1
- data/doc/classes/Integer.html +239 -0
- data/doc/classes/Integer.src/M000036.html +18 -0
- data/doc/classes/Integer.src/M000039.html +145 -0
- data/doc/classes/LongDecimal.html +453 -399
- data/doc/classes/LongDecimal.src/M000040.html +4 -4
- data/doc/classes/LongDecimal.src/M000041.html +4 -4
- data/doc/classes/LongDecimal.src/M000042.html +4 -6
- data/doc/classes/LongDecimal.src/M000043.html +4 -106
- data/doc/classes/LongDecimal.src/M000044.html +4 -21
- data/doc/classes/LongDecimal.src/M000045.html +4 -11
- data/doc/classes/LongDecimal.src/M000046.html +6 -27
- data/doc/classes/LongDecimal.src/M000047.html +103 -16
- data/doc/classes/LongDecimal.src/M000048.html +21 -4
- data/doc/classes/LongDecimal.src/M000049.html +10 -14
- data/doc/classes/LongDecimal.src/M000050.html +22 -36
- data/doc/classes/LongDecimal.src/M000051.html +34 -4
- data/doc/classes/LongDecimal.src/M000052.html +17 -6
- data/doc/classes/LongDecimal.src/M000053.html +4 -6
- data/doc/classes/LongDecimal.src/M000054.html +15 -4
- data/doc/classes/LongDecimal.src/M000055.html +44 -12
- data/doc/classes/LongDecimal.src/M000056.html +4 -7
- data/doc/classes/LongDecimal.src/M000057.html +8 -4
- data/doc/classes/LongDecimal.src/M000058.html +6 -15
- data/doc/classes/LongDecimal.src/M000059.html +4 -13
- data/doc/classes/LongDecimal.src/M000060.html +15 -4
- data/doc/classes/LongDecimal.src/M000061.html +7 -5
- data/doc/classes/LongDecimal.src/M000062.html +4 -4
- data/doc/classes/LongDecimal.src/M000063.html +15 -5
- data/doc/classes/LongDecimal.src/M000064.html +13 -5
- data/doc/classes/LongDecimal.src/M000065.html +4 -4
- data/doc/classes/LongDecimal.src/M000067.html +4 -8
- data/doc/classes/LongDecimal.src/M000068.html +5 -9
- data/doc/classes/LongDecimal.src/M000069.html +5 -9
- data/doc/classes/LongDecimal.src/M000070.html +4 -9
- data/doc/classes/LongDecimal.src/M000071.html +4 -4
- data/doc/classes/LongDecimal.src/M000072.html +6 -17
- data/doc/classes/LongDecimal.src/M000073.html +7 -7
- data/doc/classes/LongDecimal.src/M000074.html +7 -7
- data/doc/classes/LongDecimal.src/M000075.html +7 -19
- data/doc/classes/LongDecimal.src/M000076.html +4 -8
- data/doc/classes/LongDecimal.src/M000077.html +19 -5
- data/doc/classes/LongDecimal.src/M000078.html +7 -7
- data/doc/classes/LongDecimal.src/M000079.html +7 -7
- data/doc/classes/LongDecimal.src/M000080.html +19 -7
- data/doc/classes/LongDecimal.src/M000081.html +8 -4
- data/doc/classes/LongDecimal.src/M000082.html +5 -7
- data/doc/classes/LongDecimal.src/M000083.html +8 -6
- data/doc/classes/LongDecimal.src/M000084.html +9 -4
- data/doc/classes/LongDecimal.src/M000085.html +9 -4
- data/doc/classes/LongDecimal.src/M000086.html +4 -9
- data/doc/classes/LongDecimal.src/M000087.html +6 -8
- data/doc/classes/LongDecimal.src/M000088.html +7 -5
- data/doc/classes/LongDecimal.src/M000089.html +4 -9
- data/doc/classes/LongDecimal.src/M000090.html +4 -4
- data/doc/classes/LongDecimal.src/M000091.html +9 -4
- data/doc/classes/LongDecimal.src/M000092.html +9 -4
- data/doc/classes/LongDecimal.src/M000093.html +5 -4
- data/doc/classes/LongDecimal.src/M000094.html +7 -57
- data/doc/classes/LongDecimal.src/M000095.html +4 -4
- data/doc/classes/LongDecimal.src/M000096.html +4 -4
- data/doc/classes/LongDecimal.src/M000097.html +4 -5
- data/doc/classes/LongDecimal.src/M000098.html +4 -5
- data/doc/classes/LongDecimal.src/M000099.html +59 -5
- data/doc/classes/LongDecimal.src/M000100.html +4 -5
- data/doc/classes/LongDecimal.src/M000101.html +4 -4
- data/doc/classes/LongDecimal.src/M000104.html +19 -0
- data/doc/classes/LongDecimal.src/M000105.html +19 -0
- data/doc/classes/LongDecimal.src/M000106.html +18 -0
- data/doc/classes/LongDecimal.src/M000107.html +18 -0
- data/doc/classes/LongDecimal.src/M000108.html +18 -0
- data/doc/classes/LongDecimal.src/M000109.html +18 -0
- data/doc/classes/LongDecimalBase.html +69 -66
- data/doc/classes/LongDecimalBase.src/M000113.html +4 -9
- data/doc/classes/LongDecimalBase.src/M000114.html +4 -5
- data/doc/classes/LongDecimalBase.src/M000115.html +4 -9
- data/doc/classes/LongDecimalBase.src/M000116.html +4 -9
- data/doc/classes/LongDecimalBase.src/M000117.html +4 -5
- data/doc/classes/LongDecimalBase.src/M000118.html +23 -0
- data/doc/classes/LongDecimalBase.src/M000121.html +23 -0
- data/doc/classes/LongDecimalBase.src/M000122.html +19 -0
- data/doc/classes/LongDecimalBase.src/M000123.html +18 -0
- data/doc/classes/LongDecimalQuot.html +33 -27
- data/doc/classes/LongDecimalQuot.src/M000003.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000004.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000005.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000006.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000007.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000008.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000009.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000010.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000011.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000012.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000013.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000014.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000015.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000016.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000017.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000018.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000019.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000020.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000021.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000022.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000023.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000024.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000025.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000026.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000027.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000028.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000029.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000030.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000031.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000034.html +1 -1
- data/doc/classes/LongDecimalQuot.src/M000035.html +1 -1
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.html +25 -24
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000156.html +22 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000157.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000158.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000159.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000161.html +25 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000162.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000163.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000164.html +18 -0
- data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.html +178 -0
- data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.src/M000165.html +25 -0
- data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.src/M000166.html +18 -0
- data/doc/classes/LongDecimalRoundingMode.html +41 -4
- data/doc/classes/LongMath/CacheKey.html +10 -10
- data/doc/classes/LongMath/CacheKey.src/M000155.html +36 -0
- data/doc/classes/LongMath/CacheKey.src/M000160.html +36 -0
- data/doc/classes/LongMath.html +246 -235
- data/doc/classes/LongMath.src/M000124.html +5 -18
- data/doc/classes/LongMath.src/M000125.html +4 -18
- data/doc/classes/LongMath.src/M000126.html +4 -5
- data/doc/classes/LongMath.src/M000127.html +5 -29
- data/doc/classes/LongMath.src/M000128.html +4 -5
- data/doc/classes/LongMath.src/M000129.html +14 -53
- data/doc/classes/LongMath.src/M000130.html +17 -20
- data/doc/classes/LongMath.src/M000131.html +5 -36
- data/doc/classes/LongMath.src/M000132.html +29 -6
- data/doc/classes/LongMath.src/M000133.html +5 -33
- data/doc/classes/LongMath.src/M000134.html +47 -41
- data/doc/classes/LongMath.src/M000135.html +21 -7
- data/doc/classes/LongMath.src/M000136.html +36 -4
- data/doc/classes/LongMath.src/M000137.html +6 -4
- data/doc/classes/LongMath.src/M000138.html +31 -70
- data/doc/classes/LongMath.src/M000139.html +45 -38
- data/doc/classes/LongMath.src/M000140.html +7 -4
- data/doc/classes/LongMath.src/M000141.html +4 -4
- data/doc/classes/LongMath.src/M000142.html +4 -6
- data/doc/classes/LongMath.src/M000143.html +67 -14
- data/doc/classes/LongMath.src/M000144.html +39 -14
- data/doc/classes/LongMath.src/M000145.html +4 -44
- data/doc/classes/LongMath.src/M000146.html +5 -339
- data/doc/classes/LongMath.src/M000147.html +6 -25
- data/doc/classes/LongMath.src/M000148.html +14 -75
- data/doc/classes/LongMath.src/M000149.html +33 -0
- data/doc/classes/LongMath.src/M000150.html +58 -0
- data/doc/classes/LongMath.src/M000151.html +406 -0
- data/doc/classes/LongMath.src/M000152.html +63 -0
- data/doc/classes/LongMath.src/M000153.html +117 -0
- data/doc/classes/LongMath.src/M000154.html +150 -0
- data/doc/classes/LongMath.src/M000155.html +63 -0
- data/doc/classes/LongMath.src/M000156.html +18 -0
- data/doc/classes/LongMath.src/M000157.html +19 -0
- data/doc/classes/LongMath.src/M000158.html +18 -0
- data/doc/classes/LongMath.src/M000159.html +19 -0
- data/doc/classes/Numeric.html +23 -21
- data/doc/classes/Numeric.src/M000106.html +18 -0
- data/doc/classes/Numeric.src/M000110.html +23 -0
- data/doc/classes/Numeric.src/M000111.html +18 -0
- data/doc/classes/Rational.html +18 -16
- data/doc/classes/Rational.src/M000107.html +23 -0
- data/doc/classes/Rational.src/M000112.html +23 -0
- data/doc/created.rid +1 -1
- data/doc/dot/f_0.dot +23 -1
- data/doc/dot/f_0.png +0 -0
- data/doc/dot/m_0_0.png +0 -0
- data/doc/dot/m_0_1.dot +13 -0
- data/doc/dot/m_0_1.png +0 -0
- data/doc/files/lib/long-decimal_rb.html +15 -13
- data/doc/files/lib/long-decimal_rb.src/M000001.html +1 -1
- data/doc/files/lib/long-decimal_rb.src/M000002.html +1 -1
- data/doc/fr_class_index.html +2 -0
- data/doc/fr_method_index.html +131 -124
- data/lib/long-decimal.rb +373 -49
- data/test/testlongdecimal.rb +689 -7
- data/test/testlongdeclib.rb +51 -11
- data/test/testrandlib.rb +23 -7
- data/test/testrandom.rb +4 -4
- data/test/testrandpower.rb +11 -9
- metadata +48 -3
data/lib/long-decimal.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#
|
|
2
2
|
# long-decimal.rb -- Arbitrary precision decimals with fixed decimal point
|
|
3
3
|
#
|
|
4
|
-
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.
|
|
5
|
-
# CVS-Label: $Name:
|
|
4
|
+
# CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.50 2007/07/12 20:46:59 bk1 Exp $
|
|
5
|
+
# CVS-Label: $Name: ALPHA_01_02 $
|
|
6
6
|
# Author: $Author: bk1 $ (Karl Brodowsky)
|
|
7
7
|
#
|
|
8
8
|
require "complex"
|
|
@@ -32,8 +32,11 @@ module LongDecimalRoundingMode
|
|
|
32
32
|
def <=>(o)
|
|
33
33
|
if o.respond_to?:num
|
|
34
34
|
self.num <=> o.num
|
|
35
|
-
|
|
35
|
+
elsif o.kind_of? Numeric
|
|
36
36
|
self.num <=> o
|
|
37
|
+
else
|
|
38
|
+
puts("stack=#{caller.join("\n")}")
|
|
39
|
+
raise TypeError, "o=#{o.inspect} must be numeric or RoundingMode";
|
|
37
40
|
end
|
|
38
41
|
end
|
|
39
42
|
|
|
@@ -97,13 +100,219 @@ module LongDecimalRoundingMode
|
|
|
97
100
|
ROUND_UNNECESSARY => ROUND_UNNECESSARY
|
|
98
101
|
}
|
|
99
102
|
|
|
103
|
+
ZeroRoundingModeClass = Struct.new(:name, :num)
|
|
104
|
+
|
|
105
|
+
#
|
|
106
|
+
# enumeration class to express the possible rounding modes that are
|
|
107
|
+
# supported by LongDecimal
|
|
108
|
+
#
|
|
109
|
+
class ZeroRoundingModeClass
|
|
110
|
+
include Comparable
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
# introduce some ordering for rounding modes
|
|
114
|
+
#
|
|
115
|
+
def <=>(o)
|
|
116
|
+
if o.respond_to?:num
|
|
117
|
+
self.num <=> o.num
|
|
118
|
+
elsif o.kind_of? Numeric
|
|
119
|
+
self.num <=> o
|
|
120
|
+
else
|
|
121
|
+
puts("stack=#{caller.join("\n")}")
|
|
122
|
+
raise TypeError, "o=#{o.inspect} must be numeric or ZeroRoundingMode";
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def hash
|
|
127
|
+
num
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# rounding modes as constants
|
|
134
|
+
#
|
|
135
|
+
ZERO_ROUND_TO_PLUS = ZeroRoundingModeClass.new(:ZERO_ROUND_TO_PLUS, 0)
|
|
136
|
+
ZERO_ROUND_TO_MINUS = ZeroRoundingModeClass.new(:ZERO_ROUND_TO_MINUS, 1)
|
|
137
|
+
ZERO_ROUND_TO_CLOSEST_PREFER_PLUS = ZeroRoundingModeClass.new(:ZERO_ROUND_TO_CLOSEST_PREFER_PLUS, 2)
|
|
138
|
+
ZERO_ROUND_TO_CLOSEST_PREFER_MINUS = ZeroRoundingModeClass.new(:ZERO_ROUND_TO_CLOSEST_PREFER_MINUS, 3)
|
|
139
|
+
ZERO_ROUND_UNNECESSARY = ZeroRoundingModeClass.new(:ZERO_ROUND_UNNECESSARY, 4)
|
|
140
|
+
|
|
100
141
|
end # LongDecimalRoundingMode
|
|
101
142
|
|
|
143
|
+
#
|
|
144
|
+
# add one method to Integer
|
|
145
|
+
#
|
|
146
|
+
class Integer
|
|
147
|
+
|
|
148
|
+
#
|
|
149
|
+
# get the sign of self
|
|
150
|
+
# -1 if self < 0
|
|
151
|
+
# 0 if self is 0 (with any number of 0s after the decimal point)
|
|
152
|
+
# +1 if self > 0
|
|
153
|
+
#
|
|
154
|
+
def sgn
|
|
155
|
+
self <=> 0
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
alias signum sgn
|
|
159
|
+
alias sign sgn
|
|
160
|
+
|
|
161
|
+
#
|
|
162
|
+
# create copy of self round in such a way that the result is
|
|
163
|
+
# congruent modulo modulus to one of the members of remainders
|
|
164
|
+
#
|
|
165
|
+
# param1: remainders array of allowed remainders
|
|
166
|
+
# param2: modulus modulus of the remainders
|
|
167
|
+
# param3: rounding_mode rounding mode to be applied when information is
|
|
168
|
+
# lost. defaults to ROUND_UNNECESSARY, which
|
|
169
|
+
# means that an exception is thrown if rounding
|
|
170
|
+
# would actually loose any information.
|
|
171
|
+
# param4: zero_rounding_mode if self is zero, but zero is not among
|
|
172
|
+
# the available remainders, it has to be
|
|
173
|
+
# rounded to positive or negative value.
|
|
174
|
+
# If the rounding_mode does not allow to
|
|
175
|
+
# determine which of the two values to
|
|
176
|
+
# use, zero_rounding_mode has to be used
|
|
177
|
+
# to decide.
|
|
178
|
+
#
|
|
179
|
+
def round_to_allowed_remainders(remainders,
|
|
180
|
+
modulus,
|
|
181
|
+
rounding_mode = LongDecimalRoundingMode::ROUND_UNNECESSARY,
|
|
182
|
+
zero_rounding_mode = LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY)
|
|
183
|
+
|
|
184
|
+
raise TypeError, "remainders must be Array" unless remainders.kind_of? Array
|
|
185
|
+
raise TypeError, "remainders must be non-empty Array" unless remainders.length > 0
|
|
186
|
+
raise TypeError, "modulus #{modulus.inspect} must be integer" unless modulus.kind_of? Integer
|
|
187
|
+
raise TypeError, "modulus #{modulus.inspect} must be >= 2" unless modulus >= 2
|
|
188
|
+
raise TypeError, "rounding_mode #{rounding_mode.inspect} must be legal rounding rounding_mode" unless rounding_mode.kind_of? LongDecimalRoundingMode::RoundingModeClass
|
|
189
|
+
raise TypeError, "ROUND_HALF_EVEN is not applicable here" if rounding_mode == LongDecimalRoundingMode::ROUND_HALF_EVEN
|
|
190
|
+
raise TypeError, "zero_rounding_mode #{zero_rounding_mode.inspect} must be legal zero_rounding zero_rounding_mode" unless zero_rounding_mode.kind_of? LongDecimalRoundingMode::ZeroRoundingModeClass
|
|
191
|
+
|
|
192
|
+
r_self = self % modulus
|
|
193
|
+
r_self_00 = r_self
|
|
194
|
+
remainders = remainders.collect do |r|
|
|
195
|
+
raise TypeError, "remainders must be numbers" unless r.kind_of? Integer
|
|
196
|
+
r % modulus
|
|
197
|
+
end
|
|
198
|
+
remainders.sort!.uniq!
|
|
199
|
+
r_first = remainders[0]
|
|
200
|
+
r_last = remainders[-1]
|
|
201
|
+
r_first_again = r_first + modulus
|
|
202
|
+
remainders.push r_first_again
|
|
203
|
+
if (r_self < r_first) then
|
|
204
|
+
r_self += modulus
|
|
205
|
+
end
|
|
206
|
+
# puts "r_self=#{r_self_00}->#{r_self} r_first=#{r_first} r_last=#{r_last} r_first_again=#{r_first_again}"
|
|
207
|
+
r_lower = -1
|
|
208
|
+
r_upper = -1
|
|
209
|
+
remainders.each_index do |i|
|
|
210
|
+
r = remainders[i]
|
|
211
|
+
if (r == r_self) then
|
|
212
|
+
return self
|
|
213
|
+
elsif (r < r_self) then
|
|
214
|
+
r_lower = r
|
|
215
|
+
elsif (r > r_self) then
|
|
216
|
+
r_upper = r
|
|
217
|
+
break
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
lower = self - (r_self - r_lower)
|
|
221
|
+
upper = self + (r_upper - r_self)
|
|
222
|
+
# puts "r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
|
|
223
|
+
|
|
224
|
+
unless (lower < self && self < upper)
|
|
225
|
+
raise Error, "self=#{self} not in (#{lower}, #{upper})"
|
|
226
|
+
end
|
|
227
|
+
if (rounding_mode == LongDecimalRoundingMode::ROUND_UNNECESSARY) then
|
|
228
|
+
raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, self=#{self.to_s} is in open interval (#{lower}, #{upper})"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then
|
|
232
|
+
# return lower
|
|
233
|
+
# elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
|
|
234
|
+
# return upper
|
|
235
|
+
# end
|
|
236
|
+
|
|
237
|
+
sign_self = self.sign
|
|
238
|
+
if (sign_self == 0) then
|
|
239
|
+
if (rounding_mode == LongDecimalRoundingMode::ROUND_UP || rounding_mode == LongDecimalRoundingMode::ROUND_DOWN \
|
|
240
|
+
|| lower == -upper && (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_UP || rounding_mode == LongDecimalRoundingMode::ROUND_HALF_DOWN))
|
|
241
|
+
if (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY) then
|
|
242
|
+
raise ArgumentError, "self=#{self.to_s} is 0 in open interval (#{lower}, #{upper}) and cannot be resolved with ZERO_ROUND_UNNECESSARY"
|
|
243
|
+
elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_PLUS \
|
|
244
|
+
|| zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_MINUS) then
|
|
245
|
+
diff = lower.abs <=> upper.abs
|
|
246
|
+
if (diff < 0) then
|
|
247
|
+
return lower
|
|
248
|
+
elsif (diff > 0) then
|
|
249
|
+
return upper
|
|
250
|
+
elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_PLUS) then
|
|
251
|
+
return upper
|
|
252
|
+
elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_MINUS) then
|
|
253
|
+
return lower
|
|
254
|
+
else
|
|
255
|
+
raise Error, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
|
|
256
|
+
end
|
|
257
|
+
elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_PLUS) then
|
|
258
|
+
return upper
|
|
259
|
+
elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_MINUS) then
|
|
260
|
+
return lower
|
|
261
|
+
else
|
|
262
|
+
raise Error, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# now we can assume that sign_self (and self) is != 0, which allows to decide on the rounding_mode
|
|
268
|
+
|
|
269
|
+
if (rounding_mode == LongDecimalRoundingMode::ROUND_UP)
|
|
270
|
+
# ROUND_UP goes to the closest possible value away from zero
|
|
271
|
+
rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_FLOOR : LongDecimalRoundingMode::ROUND_CEILING
|
|
272
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_DOWN)
|
|
273
|
+
# ROUND_DOWN goes to the closest possible value towards zero or beyond zero
|
|
274
|
+
rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_CEILING : LongDecimalRoundingMode::ROUND_FLOOR
|
|
275
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_UP)
|
|
276
|
+
# ROUND_HALF_UP goes to the closest possible value preferring away from zero
|
|
277
|
+
rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_HALF_FLOOR : LongDecimalRoundingMode::ROUND_HALF_CEILING
|
|
278
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_DOWN)
|
|
279
|
+
# ROUND_HALF_DOWN goes to the closest possible value preferring towards zero or beyond zero
|
|
280
|
+
rounding_mode = (sign_self < 0) ? LongDecimalRoundingMode::ROUND_HALF_CEILING : LongDecimalRoundingMode::ROUND_HALF_FLOOR
|
|
281
|
+
end
|
|
282
|
+
if (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_FLOOR \
|
|
283
|
+
|| rounding_mode == LongDecimalRoundingMode::ROUND_HALF_CEILING) then
|
|
284
|
+
d_lower = self - lower
|
|
285
|
+
d_upper = upper - self
|
|
286
|
+
if (d_lower < d_upper) then
|
|
287
|
+
return lower
|
|
288
|
+
elsif (d_upper < d_lower) then
|
|
289
|
+
return upper
|
|
290
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_FLOOR) then
|
|
291
|
+
rounding_mode = LongDecimalRoundingMode::ROUND_FLOOR
|
|
292
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_CEILING) then
|
|
293
|
+
rounding_mode = LongDecimalRoundingMode::ROUND_CEILING
|
|
294
|
+
else
|
|
295
|
+
raise Error, "this case can never happen: rounding_mode=#{rounding_mode}"
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then
|
|
300
|
+
# puts "floor/lower r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
|
|
301
|
+
return lower
|
|
302
|
+
elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
|
|
303
|
+
# puts "ceiling/upper r_lower=#{r_lower} r_upper=#{r_upper} lower=#{lower} upper=#{upper} s=#{self}"
|
|
304
|
+
return upper
|
|
305
|
+
else
|
|
306
|
+
raise Error, "this case can never happen: rounding_mode=#{rounding_mode}"
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
102
311
|
#
|
|
103
312
|
# common base class for LongDecimal and LongDecimalQuot
|
|
104
313
|
#
|
|
105
314
|
class LongDecimalBase < Numeric
|
|
106
|
-
@RCS_ID='-$Id: long-decimal.rb,v 1.
|
|
315
|
+
@RCS_ID='-$Id: long-decimal.rb,v 1.50 2007/07/12 20:46:59 bk1 Exp $-'
|
|
107
316
|
|
|
108
317
|
include LongDecimalRoundingMode
|
|
109
318
|
|
|
@@ -211,7 +420,7 @@ end # class LongDecimalBase
|
|
|
211
420
|
# digits and the other one the position of the decimal point.
|
|
212
421
|
#
|
|
213
422
|
class LongDecimal < LongDecimalBase
|
|
214
|
-
@RCS_ID='-$Id: long-decimal.rb,v 1.
|
|
423
|
+
@RCS_ID='-$Id: long-decimal.rb,v 1.50 2007/07/12 20:46:59 bk1 Exp $-'
|
|
215
424
|
|
|
216
425
|
# MINUS_ONE = LongDecimal(-1)
|
|
217
426
|
# ZERO = LongDecimal(0)
|
|
@@ -343,18 +552,18 @@ class LongDecimal < LongDecimalBase
|
|
|
343
552
|
raise TypeError, "1st arg must not be empty string. \"#{num_str.inspect}\"" if len == 0
|
|
344
553
|
|
|
345
554
|
# remove spaces and underscores
|
|
346
|
-
num_str.gsub!
|
|
347
|
-
num_str.gsub!
|
|
555
|
+
num_str.gsub!(/\s/, "")
|
|
556
|
+
num_str.gsub!(/_/, "")
|
|
348
557
|
|
|
349
558
|
# handle sign
|
|
350
|
-
num_str.gsub!
|
|
559
|
+
num_str.gsub!(/^\+/, "")
|
|
351
560
|
negative = false
|
|
352
|
-
if num_str.gsub!
|
|
561
|
+
if num_str.gsub!(/^-/, "") then
|
|
353
562
|
negative = true
|
|
354
563
|
end
|
|
355
564
|
|
|
356
565
|
# split in parts before and after decimal point
|
|
357
|
-
num_arr = num_str.split
|
|
566
|
+
num_arr = num_str.split(/\./)
|
|
358
567
|
if num_arr.length > 2 then
|
|
359
568
|
raise TypeError, "1st arg contains more than one . \"#{num_str.inspect}\""
|
|
360
569
|
end
|
|
@@ -363,7 +572,7 @@ class LongDecimal < LongDecimalBase
|
|
|
363
572
|
num_frac = nil
|
|
364
573
|
num_exp = nil
|
|
365
574
|
unless num_rem.nil? then
|
|
366
|
-
num_arr = num_rem.split
|
|
575
|
+
num_arr = num_rem.split(/[Ee]/)
|
|
367
576
|
num_frac = num_arr[0]
|
|
368
577
|
num_exp = num_arr[1]
|
|
369
578
|
end
|
|
@@ -480,6 +689,60 @@ class LongDecimal < LongDecimalBase
|
|
|
480
689
|
end
|
|
481
690
|
end
|
|
482
691
|
|
|
692
|
+
#
|
|
693
|
+
# create copy of self round in such a way that the result times
|
|
694
|
+
# 10**scale is congruent modulo modulus to one of the members of
|
|
695
|
+
# remainders
|
|
696
|
+
#
|
|
697
|
+
# param1: new_scale new scale for result
|
|
698
|
+
# param2: remainders array of allowed remainders
|
|
699
|
+
# param3: modulus modulus of the remainders
|
|
700
|
+
# param4: rounding_mode rounding mode to be applied when information is
|
|
701
|
+
# lost. defaults to ROUND_UNNECESSARY, which
|
|
702
|
+
# means that an exception is thrown if rounding
|
|
703
|
+
# would actually loose any information.
|
|
704
|
+
# param5: zero_rounding_mode if self is zero, but zero is not among
|
|
705
|
+
# the available remainders, it has to be
|
|
706
|
+
# rounded to positive or negative value.
|
|
707
|
+
# If the rounding_mode does not allow to
|
|
708
|
+
# determine which of the two values to
|
|
709
|
+
# use, zero_rounding_mode has to be used
|
|
710
|
+
# to decide.
|
|
711
|
+
#
|
|
712
|
+
def round_to_allowed_remainders(new_scale,
|
|
713
|
+
remainders,
|
|
714
|
+
modulus,
|
|
715
|
+
rounding_mode = LongDecimalRoundingMode::ROUND_UNNECESSARY,
|
|
716
|
+
zero_rounding_mode = LongDecimalRoundingMode::ZERO_ROUND_UNNECESSARY)
|
|
717
|
+
|
|
718
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
|
|
719
|
+
raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
|
|
720
|
+
raise TypeError, "remainders must be Array" unless remainders.kind_of? Array
|
|
721
|
+
raise TypeError, "remainders must be non-empty Array" unless remainders.length > 0
|
|
722
|
+
raise TypeError, "modulus #{modulus.inspect} must be integer" unless modulus.kind_of? Integer
|
|
723
|
+
raise TypeError, "modulus #{modulus.inspect} must be >= 2" unless modulus >= 2
|
|
724
|
+
raise TypeError, "rounding_mode #{rounding_mode.inspect} must be legal rounding rounding_mode" unless rounding_mode.kind_of? RoundingModeClass
|
|
725
|
+
raise TypeError, "ROUND_HALF_EVEN is not applicable here" if rounding_mode == LongDecimalRoundingMode::ROUND_HALF_EVEN
|
|
726
|
+
raise TypeError, "zero_rounding_mode #{zero_rounding_mode.inspect} must be legal zero_rounding zero_rounding_mode" unless zero_rounding_mode.kind_of? ZeroRoundingModeClass
|
|
727
|
+
|
|
728
|
+
if @scale < new_scale then
|
|
729
|
+
expanded = self.round_to_scale(new_scale, rounding_mode)
|
|
730
|
+
return expanded.round_to_allowed_remainders(new_scale, remainders, modulus, rounding_mode, zero_rounding_mode)
|
|
731
|
+
elsif @scale > new_scale
|
|
732
|
+
factor = 10**(@scale - new_scale)
|
|
733
|
+
remainders = remainders.collect do |r|
|
|
734
|
+
r * factor
|
|
735
|
+
end
|
|
736
|
+
modulus *= factor
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
int_val_2 = @int_val.round_to_allowed_remainders(remainders, modulus, rounding_mode, zero_rounding_mode)
|
|
740
|
+
self_2 = LongDecimal.new(int_val_2, @scale)
|
|
741
|
+
|
|
742
|
+
result = self_2.round_to_scale(new_scale, rounding_mode)
|
|
743
|
+
return result
|
|
744
|
+
end
|
|
745
|
+
|
|
483
746
|
#
|
|
484
747
|
# convert self into String, which is the decimal representation.
|
|
485
748
|
# Use trailing zeros, if int_val has them.
|
|
@@ -558,28 +821,34 @@ class LongDecimal < LongDecimalBase
|
|
|
558
821
|
return 0.0
|
|
559
822
|
end
|
|
560
823
|
|
|
561
|
-
|
|
824
|
+
if (self < 0) then
|
|
825
|
+
return -(-self).to_f
|
|
826
|
+
end
|
|
827
|
+
|
|
828
|
+
dividend = numerator
|
|
829
|
+
divisor = denominator
|
|
830
|
+
|
|
562
831
|
if (divisor == 1) then
|
|
563
|
-
return
|
|
564
|
-
elsif
|
|
832
|
+
return dividend.to_f
|
|
833
|
+
elsif dividend.abs <= LongMath::MAX_FLOATABLE then
|
|
565
834
|
if (divisor.abs > LongMath::MAX_FLOATABLE) then
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
835
|
+
q = 10**(scale - Float::MAX_10_EXP)
|
|
836
|
+
f = (dividend / q).to_f
|
|
837
|
+
d = divisor / q
|
|
569
838
|
return f / d
|
|
570
839
|
else
|
|
571
|
-
f =
|
|
840
|
+
f = dividend.to_f
|
|
572
841
|
return f / divisor
|
|
573
842
|
end
|
|
574
|
-
elsif
|
|
843
|
+
elsif dividend.abs < divisor
|
|
575
844
|
# self is between -1 and 1
|
|
576
845
|
|
|
577
|
-
# factor =
|
|
846
|
+
# factor = dividend.abs.div(LongMath::MAX_FLOATABLE)
|
|
578
847
|
# digits = factor.to_ld.int_digits10
|
|
579
|
-
# return LongDecimal(
|
|
848
|
+
# return LongDecimal(dividend.div(10**digits), scale -digits).to_f
|
|
580
849
|
return self.to_s.to_f
|
|
581
850
|
else
|
|
582
|
-
q =
|
|
851
|
+
q = dividend.abs / divisor
|
|
583
852
|
if (q.abs > 1000000000000000000000)
|
|
584
853
|
return q.to_f
|
|
585
854
|
else
|
|
@@ -1269,7 +1538,7 @@ end # LongDecimal
|
|
|
1269
1538
|
#
|
|
1270
1539
|
class LongDecimalQuot < LongDecimalBase
|
|
1271
1540
|
|
|
1272
|
-
@RCS_ID='-$Id: long-decimal.rb,v 1.
|
|
1541
|
+
@RCS_ID='-$Id: long-decimal.rb,v 1.50 2007/07/12 20:46:59 bk1 Exp $-'
|
|
1273
1542
|
|
|
1274
1543
|
#
|
|
1275
1544
|
# constructor
|
|
@@ -2452,7 +2721,7 @@ module LongMath
|
|
|
2452
2721
|
#
|
|
2453
2722
|
def LongMath.exp_internal(x, prec = nil, final_mode = LongMath.standard_mode, j = nil, k = nil, iprec = nil, mode = LongMath.standard_imode, cache_result = true) # down?
|
|
2454
2723
|
|
|
2455
|
-
if (prec
|
|
2724
|
+
if (prec.nil?) then
|
|
2456
2725
|
if (x.kind_of? LongDecimalBase)
|
|
2457
2726
|
prec = x.scale
|
|
2458
2727
|
else
|
|
@@ -2461,7 +2730,7 @@ module LongMath
|
|
|
2461
2730
|
end
|
|
2462
2731
|
check_is_prec(prec, "prec")
|
|
2463
2732
|
|
|
2464
|
-
if (final_mode
|
|
2733
|
+
if (final_mode.nil?)
|
|
2465
2734
|
final_mode = LongMath.standard_mode
|
|
2466
2735
|
end
|
|
2467
2736
|
check_is_mode(final_mode, "final_mode")
|
|
@@ -2469,7 +2738,8 @@ module LongMath
|
|
|
2469
2738
|
|
|
2470
2739
|
# if the result would come out to zero anyway, cut the work
|
|
2471
2740
|
xi = x.to_i
|
|
2472
|
-
if (xi < -LongMath::MAX_FLOATABLE) || -((xi.to_f - 1) / LOG10) > prec+10 then
|
|
2741
|
+
# if (xi < -LongMath::MAX_FLOATABLE) || -((xi.to_f - 1) / LOG10) > prec+10 then
|
|
2742
|
+
if (xi < -LongMath::MAX_FLOATABLE) || xi + 1 < -prec * LOG10 - LOG2 then
|
|
2473
2743
|
return LongDecimal(25, prec+2).round_to_scale(prec, final_mode)
|
|
2474
2744
|
end
|
|
2475
2745
|
x_was_neg = false
|
|
@@ -2478,12 +2748,12 @@ module LongMath
|
|
|
2478
2748
|
x_was_neg = true
|
|
2479
2749
|
end
|
|
2480
2750
|
|
|
2481
|
-
if j
|
|
2751
|
+
if j.nil? || k.nil? then
|
|
2482
2752
|
s1 = (prec * LOG10 / LOG2) ** (1.0/3.0)
|
|
2483
|
-
if (j
|
|
2753
|
+
if (j.nil?) then
|
|
2484
2754
|
j = s1.round
|
|
2485
2755
|
end
|
|
2486
|
-
if (k
|
|
2756
|
+
if (k.nil?) then
|
|
2487
2757
|
k = (s1 + Math.log([1, prec].max) / LOG2).round
|
|
2488
2758
|
end
|
|
2489
2759
|
if (x > 1) then
|
|
@@ -2499,7 +2769,7 @@ module LongMath
|
|
|
2499
2769
|
check_is_int(j, "j")
|
|
2500
2770
|
check_is_int(k, "k")
|
|
2501
2771
|
|
|
2502
|
-
if (iprec
|
|
2772
|
+
if (iprec.nil?) then
|
|
2503
2773
|
iprec = calc_iprec_for_exp(x, prec, x_was_neg)
|
|
2504
2774
|
end
|
|
2505
2775
|
check_is_prec(iprec, "iprec")
|
|
@@ -2704,7 +2974,7 @@ module LongMath
|
|
|
2704
2974
|
def LongMath.log_internal(x, prec = nil, final_mode = LongMath.standard_mode, iprec = nil, mode = LongMath.standard_imode, cache_result = true)
|
|
2705
2975
|
|
|
2706
2976
|
raise TypeError, "x=#{x.inspect} must not be positive" unless x > 0
|
|
2707
|
-
if (prec
|
|
2977
|
+
if (prec.nil?) then
|
|
2708
2978
|
if (x.kind_of? LongDecimalBase)
|
|
2709
2979
|
prec = x.scale
|
|
2710
2980
|
else
|
|
@@ -2713,13 +2983,13 @@ module LongMath
|
|
|
2713
2983
|
end
|
|
2714
2984
|
check_is_prec(prec, "prec")
|
|
2715
2985
|
|
|
2716
|
-
if (final_mode
|
|
2986
|
+
if (final_mode.nil?)
|
|
2717
2987
|
final_mode = LongMath.standard_mode
|
|
2718
2988
|
end
|
|
2719
2989
|
check_is_mode(final_mode, "final_mode")
|
|
2720
2990
|
check_is_mode(mode, "mode")
|
|
2721
2991
|
|
|
2722
|
-
if (iprec
|
|
2992
|
+
if (iprec.nil?) then
|
|
2723
2993
|
# iprec = ((prec+10)*1.20).round
|
|
2724
2994
|
iprec = ((prec+12)*1.20).round
|
|
2725
2995
|
end
|
|
@@ -2839,27 +3109,51 @@ module LongMath
|
|
|
2839
3109
|
# internal helper method for calculating the internal precision for power
|
|
2840
3110
|
#
|
|
2841
3111
|
def LongMath.calc_iprec_for_power(x, y, prec)
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
3112
|
+
|
|
3113
|
+
logx_f = nil
|
|
3114
|
+
if (x.abs <= LongMath::MAX_FLOATABLE)
|
|
3115
|
+
x_f = x.to_f
|
|
3116
|
+
logx_f = Math.log(x_f.abs)
|
|
3117
|
+
else
|
|
3118
|
+
logx_f = LongMath.log(x, 15, LongMath::ROUND_UP)
|
|
3119
|
+
end
|
|
3120
|
+
|
|
3121
|
+
y_f = nil
|
|
3122
|
+
if (y.abs <= LongMath::MAX_FLOATABLE) then
|
|
3123
|
+
y_f = y.to_f
|
|
3124
|
+
else
|
|
3125
|
+
y_f = y.round_to_scale(15, LongMath::ROUND_UP)
|
|
3126
|
+
end
|
|
3127
|
+
|
|
2850
3128
|
logx_y_f = logx_f * y_f
|
|
3129
|
+
if (logx_y_f.abs > LongMath::MAX_FLOATABLE) then
|
|
3130
|
+
raise ArgumentError, "power would be way too big: y*log(x)=#{logx_y_f}";
|
|
3131
|
+
end
|
|
3132
|
+
logx_y_f = logx_y_f.to_f unless logx_y_f.kind_of? Float
|
|
3133
|
+
|
|
2851
3134
|
iprec_x = calc_iprec_for_exp(logx_y_f.abs.ceil, prec, logx_y_f < 0)
|
|
2852
|
-
# iprec_x = calc_iprec_for_exp(logx_y_f, prec, logx_y_f < 0) + 10
|
|
2853
3135
|
iprec_y = iprec_x
|
|
2854
3136
|
iprec = iprec_x + 2
|
|
2855
3137
|
if (logx_f < 0)
|
|
2856
3138
|
iprec_x -= (logx_f/LOG10).round
|
|
2857
3139
|
end
|
|
2858
|
-
if (
|
|
3140
|
+
if (y_f.abs < 1)
|
|
3141
|
+
logy_f = nil
|
|
3142
|
+
if (y_f.kind_of? Float) then
|
|
3143
|
+
logy_f = Math.log(y_f.abs)
|
|
3144
|
+
else
|
|
3145
|
+
logy_f = LongMath.log(y_f.abs, 15, LongMath::ROUND_UP)
|
|
3146
|
+
if (logy_f.abs > LongMath::MAX_FLOATABLE) then
|
|
3147
|
+
raise ArgumentError, "exponent would be way too big: y=#{y} logy_f=#{logy_f}";
|
|
3148
|
+
end
|
|
3149
|
+
logy_f = logy_f.to_f
|
|
3150
|
+
end
|
|
3151
|
+
# 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")
|
|
2859
3152
|
iprec_y -= (logy_f/LOG10).round
|
|
2860
3153
|
end
|
|
3154
|
+
# 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")
|
|
2861
3155
|
# puts("\niprec: x=#{x} y=#{y} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y}\n")
|
|
2862
|
-
[ iprec, iprec_x, iprec_y ]
|
|
3156
|
+
[ iprec, iprec_x, iprec_y, logx_y_f ]
|
|
2863
3157
|
|
|
2864
3158
|
end
|
|
2865
3159
|
|
|
@@ -2893,7 +3187,16 @@ module LongMath
|
|
|
2893
3187
|
return LongDecimal.one!(prec)
|
|
2894
3188
|
end
|
|
2895
3189
|
|
|
2896
|
-
|
|
3190
|
+
# els
|
|
3191
|
+
# could be result with our precision
|
|
3192
|
+
# x ** y <= 10**-s/2 <=> y * log(x) <= -s log(10) - log(2)
|
|
3193
|
+
|
|
3194
|
+
iprec, iprec_x, iprec_y, logx_y_f = calc_iprec_for_power(x, y, prec)
|
|
3195
|
+
if (x < 1 && y > 0 || x > 1 && y < 0) then
|
|
3196
|
+
if (logx_y_f <= - prec * LOG10 - LOG2) then
|
|
3197
|
+
return LongDecimal.zero!(prec)
|
|
3198
|
+
end
|
|
3199
|
+
end
|
|
2897
3200
|
# puts("x=#{x} y=#{y} iprec=#{iprec} iprec_x=#{iprec_x} iprec_y=#{iprec_y} prec=#{prec}")
|
|
2898
3201
|
|
|
2899
3202
|
unless (x.kind_of? LongDecimalBase) || (x.kind_of? Integer)
|
|
@@ -2904,9 +3207,20 @@ module LongMath
|
|
|
2904
3207
|
end
|
|
2905
3208
|
|
|
2906
3209
|
# try shortcut if exponent is an integer
|
|
2907
|
-
if (y.kind_of? LongDecimalBase) && y.is_int?
|
|
3210
|
+
if (y.kind_of? LongDecimalBase) && y.is_int? then
|
|
2908
3211
|
y = y.to_i
|
|
2909
3212
|
end
|
|
3213
|
+
unless (y.kind_of? Integer)
|
|
3214
|
+
y2 = y*2
|
|
3215
|
+
if (y2.kind_of? LongDecimalBase) && y2.is_int? then
|
|
3216
|
+
y2 = y2.to_i
|
|
3217
|
+
puts("y2=#{y2}")
|
|
3218
|
+
end
|
|
3219
|
+
if (y2.kind_of? Integer)
|
|
3220
|
+
x = LongMath.sqrt(x, 2*iprec_x, mode)
|
|
3221
|
+
y = y2
|
|
3222
|
+
end
|
|
3223
|
+
end
|
|
2910
3224
|
if (y.kind_of? Integer)
|
|
2911
3225
|
unless x.kind_of? LongDecimal
|
|
2912
3226
|
# x = x.to_ld(prec)
|
|
@@ -2925,6 +3239,8 @@ module LongMath
|
|
|
2925
3239
|
y = y.to_ld(iprec_y, mode)
|
|
2926
3240
|
end
|
|
2927
3241
|
|
|
3242
|
+
# if x < 1 && y < 0 then
|
|
3243
|
+
# working with x < 1 should be improved, less precision needed
|
|
2928
3244
|
if x < 1 then
|
|
2929
3245
|
# since we do not allow x < 0 and we have handled x = 0 already,
|
|
2930
3246
|
# we can be sure that x is no integer, so it has been converted
|
|
@@ -2966,6 +3282,8 @@ module LongMath
|
|
|
2966
3282
|
check_is_prec(prec, "prec")
|
|
2967
3283
|
check_is_mode(mode, "mode")
|
|
2968
3284
|
|
|
3285
|
+
cnt = 0
|
|
3286
|
+
|
|
2969
3287
|
if (y.zero?)
|
|
2970
3288
|
return 1
|
|
2971
3289
|
elsif ! (x.kind_of? LongDecimalBase) || x.scale * y.abs <= prec
|
|
@@ -2982,17 +3300,23 @@ module LongMath
|
|
|
2982
3300
|
z = x
|
|
2983
3301
|
while true do
|
|
2984
3302
|
|
|
3303
|
+
cnt++
|
|
2985
3304
|
y -= 1
|
|
2986
3305
|
if (y.zero?)
|
|
2987
3306
|
break
|
|
2988
3307
|
end
|
|
2989
3308
|
while (y & 0x01) == 0 do
|
|
2990
3309
|
|
|
3310
|
+
cnt++
|
|
2991
3311
|
y = y >> 1
|
|
2992
3312
|
x = (x*x)
|
|
2993
3313
|
if (x.kind_of? LongDecimalBase)
|
|
2994
3314
|
x = x.round_to_scale(prec, mode)
|
|
2995
3315
|
end
|
|
3316
|
+
if (cnt > 1000)
|
|
3317
|
+
puts("ipower x=#{x} y=#{y} cnt=#{cnt} z=#{z}")
|
|
3318
|
+
cnt = 0
|
|
3319
|
+
end
|
|
2996
3320
|
|
|
2997
3321
|
end
|
|
2998
3322
|
z = (z*x)
|
|
@@ -3014,7 +3338,7 @@ module LongMath
|
|
|
3014
3338
|
#
|
|
3015
3339
|
def LongMath.power_internal(x, y, prec = nil, final_mode = LongMath.standard_mode, iprec = nil, mode = LongMath.standard_imode)
|
|
3016
3340
|
|
|
3017
|
-
if (prec
|
|
3341
|
+
if (prec.nil?) then
|
|
3018
3342
|
if (x.kind_of? LongDecimalBase) && (y.kind_of? LongDecimalBase)
|
|
3019
3343
|
prec = [x.scale, y.scale].max
|
|
3020
3344
|
elsif (x.kind_of? LongDecimalBase)
|
|
@@ -3027,7 +3351,7 @@ module LongMath
|
|
|
3027
3351
|
end
|
|
3028
3352
|
check_is_prec(prec, "prec")
|
|
3029
3353
|
|
|
3030
|
-
if (final_mode
|
|
3354
|
+
if (final_mode.nil?)
|
|
3031
3355
|
final_mode = LongMath.standard_mode
|
|
3032
3356
|
end
|
|
3033
3357
|
check_is_mode(final_mode, "final_mode")
|
|
@@ -3039,7 +3363,7 @@ module LongMath
|
|
|
3039
3363
|
return LongDecimal.zero!(prec)
|
|
3040
3364
|
end
|
|
3041
3365
|
|
|
3042
|
-
if (iprec
|
|
3366
|
+
if (iprec.nil?) then
|
|
3043
3367
|
iprec, iprec_x, iprec_y = calc_iprec_for_power(x, y, prec)
|
|
3044
3368
|
end
|
|
3045
3369
|
unless (x.kind_of? LongDecimal)
|