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.
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)