long-decimal 0.01.01 → 0.01.02

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/README +17 -94
  2. data/VERSION +1 -1
  3. data/doc/classes/Integer.html +239 -0
  4. data/doc/classes/Integer.src/M000036.html +18 -0
  5. data/doc/classes/Integer.src/M000039.html +145 -0
  6. data/doc/classes/LongDecimal.html +453 -399
  7. data/doc/classes/LongDecimal.src/M000040.html +4 -4
  8. data/doc/classes/LongDecimal.src/M000041.html +4 -4
  9. data/doc/classes/LongDecimal.src/M000042.html +4 -6
  10. data/doc/classes/LongDecimal.src/M000043.html +4 -106
  11. data/doc/classes/LongDecimal.src/M000044.html +4 -21
  12. data/doc/classes/LongDecimal.src/M000045.html +4 -11
  13. data/doc/classes/LongDecimal.src/M000046.html +6 -27
  14. data/doc/classes/LongDecimal.src/M000047.html +103 -16
  15. data/doc/classes/LongDecimal.src/M000048.html +21 -4
  16. data/doc/classes/LongDecimal.src/M000049.html +10 -14
  17. data/doc/classes/LongDecimal.src/M000050.html +22 -36
  18. data/doc/classes/LongDecimal.src/M000051.html +34 -4
  19. data/doc/classes/LongDecimal.src/M000052.html +17 -6
  20. data/doc/classes/LongDecimal.src/M000053.html +4 -6
  21. data/doc/classes/LongDecimal.src/M000054.html +15 -4
  22. data/doc/classes/LongDecimal.src/M000055.html +44 -12
  23. data/doc/classes/LongDecimal.src/M000056.html +4 -7
  24. data/doc/classes/LongDecimal.src/M000057.html +8 -4
  25. data/doc/classes/LongDecimal.src/M000058.html +6 -15
  26. data/doc/classes/LongDecimal.src/M000059.html +4 -13
  27. data/doc/classes/LongDecimal.src/M000060.html +15 -4
  28. data/doc/classes/LongDecimal.src/M000061.html +7 -5
  29. data/doc/classes/LongDecimal.src/M000062.html +4 -4
  30. data/doc/classes/LongDecimal.src/M000063.html +15 -5
  31. data/doc/classes/LongDecimal.src/M000064.html +13 -5
  32. data/doc/classes/LongDecimal.src/M000065.html +4 -4
  33. data/doc/classes/LongDecimal.src/M000067.html +4 -8
  34. data/doc/classes/LongDecimal.src/M000068.html +5 -9
  35. data/doc/classes/LongDecimal.src/M000069.html +5 -9
  36. data/doc/classes/LongDecimal.src/M000070.html +4 -9
  37. data/doc/classes/LongDecimal.src/M000071.html +4 -4
  38. data/doc/classes/LongDecimal.src/M000072.html +6 -17
  39. data/doc/classes/LongDecimal.src/M000073.html +7 -7
  40. data/doc/classes/LongDecimal.src/M000074.html +7 -7
  41. data/doc/classes/LongDecimal.src/M000075.html +7 -19
  42. data/doc/classes/LongDecimal.src/M000076.html +4 -8
  43. data/doc/classes/LongDecimal.src/M000077.html +19 -5
  44. data/doc/classes/LongDecimal.src/M000078.html +7 -7
  45. data/doc/classes/LongDecimal.src/M000079.html +7 -7
  46. data/doc/classes/LongDecimal.src/M000080.html +19 -7
  47. data/doc/classes/LongDecimal.src/M000081.html +8 -4
  48. data/doc/classes/LongDecimal.src/M000082.html +5 -7
  49. data/doc/classes/LongDecimal.src/M000083.html +8 -6
  50. data/doc/classes/LongDecimal.src/M000084.html +9 -4
  51. data/doc/classes/LongDecimal.src/M000085.html +9 -4
  52. data/doc/classes/LongDecimal.src/M000086.html +4 -9
  53. data/doc/classes/LongDecimal.src/M000087.html +6 -8
  54. data/doc/classes/LongDecimal.src/M000088.html +7 -5
  55. data/doc/classes/LongDecimal.src/M000089.html +4 -9
  56. data/doc/classes/LongDecimal.src/M000090.html +4 -4
  57. data/doc/classes/LongDecimal.src/M000091.html +9 -4
  58. data/doc/classes/LongDecimal.src/M000092.html +9 -4
  59. data/doc/classes/LongDecimal.src/M000093.html +5 -4
  60. data/doc/classes/LongDecimal.src/M000094.html +7 -57
  61. data/doc/classes/LongDecimal.src/M000095.html +4 -4
  62. data/doc/classes/LongDecimal.src/M000096.html +4 -4
  63. data/doc/classes/LongDecimal.src/M000097.html +4 -5
  64. data/doc/classes/LongDecimal.src/M000098.html +4 -5
  65. data/doc/classes/LongDecimal.src/M000099.html +59 -5
  66. data/doc/classes/LongDecimal.src/M000100.html +4 -5
  67. data/doc/classes/LongDecimal.src/M000101.html +4 -4
  68. data/doc/classes/LongDecimal.src/M000104.html +19 -0
  69. data/doc/classes/LongDecimal.src/M000105.html +19 -0
  70. data/doc/classes/LongDecimal.src/M000106.html +18 -0
  71. data/doc/classes/LongDecimal.src/M000107.html +18 -0
  72. data/doc/classes/LongDecimal.src/M000108.html +18 -0
  73. data/doc/classes/LongDecimal.src/M000109.html +18 -0
  74. data/doc/classes/LongDecimalBase.html +69 -66
  75. data/doc/classes/LongDecimalBase.src/M000113.html +4 -9
  76. data/doc/classes/LongDecimalBase.src/M000114.html +4 -5
  77. data/doc/classes/LongDecimalBase.src/M000115.html +4 -9
  78. data/doc/classes/LongDecimalBase.src/M000116.html +4 -9
  79. data/doc/classes/LongDecimalBase.src/M000117.html +4 -5
  80. data/doc/classes/LongDecimalBase.src/M000118.html +23 -0
  81. data/doc/classes/LongDecimalBase.src/M000121.html +23 -0
  82. data/doc/classes/LongDecimalBase.src/M000122.html +19 -0
  83. data/doc/classes/LongDecimalBase.src/M000123.html +18 -0
  84. data/doc/classes/LongDecimalQuot.html +33 -27
  85. data/doc/classes/LongDecimalQuot.src/M000003.html +1 -1
  86. data/doc/classes/LongDecimalQuot.src/M000004.html +1 -1
  87. data/doc/classes/LongDecimalQuot.src/M000005.html +1 -1
  88. data/doc/classes/LongDecimalQuot.src/M000006.html +1 -1
  89. data/doc/classes/LongDecimalQuot.src/M000007.html +1 -1
  90. data/doc/classes/LongDecimalQuot.src/M000008.html +1 -1
  91. data/doc/classes/LongDecimalQuot.src/M000009.html +1 -1
  92. data/doc/classes/LongDecimalQuot.src/M000010.html +1 -1
  93. data/doc/classes/LongDecimalQuot.src/M000011.html +1 -1
  94. data/doc/classes/LongDecimalQuot.src/M000012.html +1 -1
  95. data/doc/classes/LongDecimalQuot.src/M000013.html +1 -1
  96. data/doc/classes/LongDecimalQuot.src/M000014.html +1 -1
  97. data/doc/classes/LongDecimalQuot.src/M000015.html +1 -1
  98. data/doc/classes/LongDecimalQuot.src/M000016.html +1 -1
  99. data/doc/classes/LongDecimalQuot.src/M000017.html +1 -1
  100. data/doc/classes/LongDecimalQuot.src/M000018.html +1 -1
  101. data/doc/classes/LongDecimalQuot.src/M000019.html +1 -1
  102. data/doc/classes/LongDecimalQuot.src/M000020.html +1 -1
  103. data/doc/classes/LongDecimalQuot.src/M000021.html +1 -1
  104. data/doc/classes/LongDecimalQuot.src/M000022.html +1 -1
  105. data/doc/classes/LongDecimalQuot.src/M000023.html +1 -1
  106. data/doc/classes/LongDecimalQuot.src/M000024.html +1 -1
  107. data/doc/classes/LongDecimalQuot.src/M000025.html +1 -1
  108. data/doc/classes/LongDecimalQuot.src/M000026.html +1 -1
  109. data/doc/classes/LongDecimalQuot.src/M000027.html +1 -1
  110. data/doc/classes/LongDecimalQuot.src/M000028.html +1 -1
  111. data/doc/classes/LongDecimalQuot.src/M000029.html +1 -1
  112. data/doc/classes/LongDecimalQuot.src/M000030.html +1 -1
  113. data/doc/classes/LongDecimalQuot.src/M000031.html +1 -1
  114. data/doc/classes/LongDecimalQuot.src/M000034.html +1 -1
  115. data/doc/classes/LongDecimalQuot.src/M000035.html +1 -1
  116. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.html +25 -24
  117. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000156.html +22 -0
  118. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000157.html +18 -0
  119. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000158.html +18 -0
  120. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000159.html +18 -0
  121. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000161.html +25 -0
  122. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000162.html +18 -0
  123. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000163.html +18 -0
  124. data/doc/classes/LongDecimalRoundingMode/RoundingModeClass.src/M000164.html +18 -0
  125. data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.html +178 -0
  126. data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.src/M000165.html +25 -0
  127. data/doc/classes/LongDecimalRoundingMode/ZeroRoundingModeClass.src/M000166.html +18 -0
  128. data/doc/classes/LongDecimalRoundingMode.html +41 -4
  129. data/doc/classes/LongMath/CacheKey.html +10 -10
  130. data/doc/classes/LongMath/CacheKey.src/M000155.html +36 -0
  131. data/doc/classes/LongMath/CacheKey.src/M000160.html +36 -0
  132. data/doc/classes/LongMath.html +246 -235
  133. data/doc/classes/LongMath.src/M000124.html +5 -18
  134. data/doc/classes/LongMath.src/M000125.html +4 -18
  135. data/doc/classes/LongMath.src/M000126.html +4 -5
  136. data/doc/classes/LongMath.src/M000127.html +5 -29
  137. data/doc/classes/LongMath.src/M000128.html +4 -5
  138. data/doc/classes/LongMath.src/M000129.html +14 -53
  139. data/doc/classes/LongMath.src/M000130.html +17 -20
  140. data/doc/classes/LongMath.src/M000131.html +5 -36
  141. data/doc/classes/LongMath.src/M000132.html +29 -6
  142. data/doc/classes/LongMath.src/M000133.html +5 -33
  143. data/doc/classes/LongMath.src/M000134.html +47 -41
  144. data/doc/classes/LongMath.src/M000135.html +21 -7
  145. data/doc/classes/LongMath.src/M000136.html +36 -4
  146. data/doc/classes/LongMath.src/M000137.html +6 -4
  147. data/doc/classes/LongMath.src/M000138.html +31 -70
  148. data/doc/classes/LongMath.src/M000139.html +45 -38
  149. data/doc/classes/LongMath.src/M000140.html +7 -4
  150. data/doc/classes/LongMath.src/M000141.html +4 -4
  151. data/doc/classes/LongMath.src/M000142.html +4 -6
  152. data/doc/classes/LongMath.src/M000143.html +67 -14
  153. data/doc/classes/LongMath.src/M000144.html +39 -14
  154. data/doc/classes/LongMath.src/M000145.html +4 -44
  155. data/doc/classes/LongMath.src/M000146.html +5 -339
  156. data/doc/classes/LongMath.src/M000147.html +6 -25
  157. data/doc/classes/LongMath.src/M000148.html +14 -75
  158. data/doc/classes/LongMath.src/M000149.html +33 -0
  159. data/doc/classes/LongMath.src/M000150.html +58 -0
  160. data/doc/classes/LongMath.src/M000151.html +406 -0
  161. data/doc/classes/LongMath.src/M000152.html +63 -0
  162. data/doc/classes/LongMath.src/M000153.html +117 -0
  163. data/doc/classes/LongMath.src/M000154.html +150 -0
  164. data/doc/classes/LongMath.src/M000155.html +63 -0
  165. data/doc/classes/LongMath.src/M000156.html +18 -0
  166. data/doc/classes/LongMath.src/M000157.html +19 -0
  167. data/doc/classes/LongMath.src/M000158.html +18 -0
  168. data/doc/classes/LongMath.src/M000159.html +19 -0
  169. data/doc/classes/Numeric.html +23 -21
  170. data/doc/classes/Numeric.src/M000106.html +18 -0
  171. data/doc/classes/Numeric.src/M000110.html +23 -0
  172. data/doc/classes/Numeric.src/M000111.html +18 -0
  173. data/doc/classes/Rational.html +18 -16
  174. data/doc/classes/Rational.src/M000107.html +23 -0
  175. data/doc/classes/Rational.src/M000112.html +23 -0
  176. data/doc/created.rid +1 -1
  177. data/doc/dot/f_0.dot +23 -1
  178. data/doc/dot/f_0.png +0 -0
  179. data/doc/dot/m_0_0.png +0 -0
  180. data/doc/dot/m_0_1.dot +13 -0
  181. data/doc/dot/m_0_1.png +0 -0
  182. data/doc/files/lib/long-decimal_rb.html +15 -13
  183. data/doc/files/lib/long-decimal_rb.src/M000001.html +1 -1
  184. data/doc/files/lib/long-decimal_rb.src/M000002.html +1 -1
  185. data/doc/fr_class_index.html +2 -0
  186. data/doc/fr_method_index.html +131 -124
  187. data/lib/long-decimal.rb +373 -49
  188. data/test/testlongdecimal.rb +689 -7
  189. data/test/testlongdeclib.rb +51 -11
  190. data/test/testrandlib.rb +23 -7
  191. data/test/testrandom.rb +4 -4
  192. data/test/testrandpower.rb +11 -9
  193. 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.43 2006/05/01 12:22:12 bk1 Exp $
5
- # CVS-Label: $Name: ALPHA_01_01 $
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
- else
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.43 2006/05/01 12:22:12 bk1 Exp $-'
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.43 2006/05/01 12:22:12 bk1 Exp $-'
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! /\s/, ""
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! /^-/, "" then
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 /[Ee]/
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
- divisor = denominator
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 numerator.to_f
564
- elsif numerator.abs <= LongMath::MAX_FLOATABLE then
832
+ return dividend.to_f
833
+ elsif dividend.abs <= LongMath::MAX_FLOATABLE then
565
834
  if (divisor.abs > LongMath::MAX_FLOATABLE) then
566
- q = 10**(scale - Float::MAX_10_EXP)
567
- f = (numerator / q).to_f
568
- d = divisor / q
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 = numerator.to_f
840
+ f = dividend.to_f
572
841
  return f / divisor
573
842
  end
574
- elsif numerator.abs < divisor
843
+ elsif dividend.abs < divisor
575
844
  # self is between -1 and 1
576
845
 
577
- # factor = numerator.abs.div(LongMath::MAX_FLOATABLE)
846
+ # factor = dividend.abs.div(LongMath::MAX_FLOATABLE)
578
847
  # digits = factor.to_ld.int_digits10
579
- # return LongDecimal(numerator.div(10**digits), scale -digits).to_f
848
+ # return LongDecimal(dividend.div(10**digits), scale -digits).to_f
580
849
  return self.to_s.to_f
581
850
  else
582
- q = numerator.abs / divisor
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.43 2006/05/01 12:22:12 bk1 Exp $-'
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 == nil) then
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 == nil)
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 == nil || k == nil then
2751
+ if j.nil? || k.nil? then
2482
2752
  s1 = (prec * LOG10 / LOG2) ** (1.0/3.0)
2483
- if (j == nil) then
2753
+ if (j.nil?) then
2484
2754
  j = s1.round
2485
2755
  end
2486
- if (k == nil) then
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 == nil) then
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 == nil) then
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 == nil)
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 == nil) then
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
- x_f = x.to_f
2843
- y_f = y.to_f
2844
- # if (x_f - 1).abs < 0.1
2845
- # # x_f += 1e-6
2846
- # x_f = x.square.to_f + 1e-4
2847
- # end
2848
- logx_f = Math.log(x_f.abs)
2849
- logy_f = Math.log(y_f.abs)
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 (logy_f < 0)
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
- iprec, iprec_x, iprec_y = calc_iprec_for_power(x, y, prec)
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 == nil) then
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 == nil)
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 == nil) then
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)