ruby-decimal 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,24 @@
1
1
  == 0.1.0 2009-06-19
2
2
 
3
- * Initial release 0.1.0
3
+ * Initial release
4
4
 
5
5
  == 0.2.0 2009-06-21
6
6
 
7
- * Release 0.2.0
8
- New functions implemented: exp(), ln(), log10(), power().
7
+ * New functions implemented:
8
+ exp(), ln(), log10(), power().
9
+
10
+
11
+
12
+ * Bug fixes:
13
+ - Decimal#inspect was always producing debug information; now it uses $DEBUG
14
+ - Raising some exceptions caused error, because too many parameters were being
15
+ passed to the exception's base class initializer.
16
+
17
+ * New functionality:
18
+ - ulp (unit in the last place)
19
+ - normalize (in the classic sense, not in the original GDA sense)
20
+ - maximum_finite, minimum_normal, minimum_nonzero value decimal constructors
21
+ - epsilon, strict_epsilon, half_epsilon
22
+ - setting context exponent limits with elimit
23
+ - require decimal/shortcut to use D for Decimal
9
24
 
@@ -7,6 +7,7 @@ lib/decimal.rb
7
7
  lib/decimal/version.rb
8
8
  lib/decimal/decimal.rb
9
9
  lib/decimal/support.rb
10
+ lib/decimal/shortcut.rb
10
11
  setup.rb
11
12
  test/all_tests.rb
12
13
  test/helper.rb
@@ -21,4 +22,7 @@ test/test_round.rb
21
22
  test/test_exact.rb
22
23
  test/test_to_int.rb
23
24
  test/test_to_rf.rb
25
+ test/test_epsilon.rb
26
+ test/test_ulp.rb
27
+ test/test_odd_even.rb
24
28
 
data/README.txt CHANGED
@@ -20,10 +20,10 @@ and the revised IEEE 754 standard (IEEE 754-2008).
20
20
 
21
21
  = Examples of use
22
22
 
23
- To install the library use gem from the command line: (you may not need sudo)
23
+ To install the library use gem from the command line: (you may not need +sudo+)
24
24
  sudo gem install ruby-decimal
25
25
 
26
- Then require the library in your code:
26
+ Then require the library in your code (if it fails you may need to <tt>require 'rubygems'</tt> first)
27
27
  require 'decimal'
28
28
 
29
29
  Now we can use the Decimal class simply like this:
@@ -79,8 +79,8 @@ And individual parameters can be assigned like this:
79
79
  puts Decimal.context.precision -> 9
80
80
  puts Decimal.context.rounding -> half_even
81
81
  Decimal.context(:rounding=>:down) do |context|
82
- puts context.precision
83
- puts context.rounding
82
+ puts context.precision -> 9
83
+ puts context.rounding -> down
84
84
  end
85
85
 
86
86
  Contexts created with the Decimal::Context() constructor
@@ -173,10 +173,48 @@ an interface compatible with the Ruby interface of Float:
173
173
  puts Decimal('101.5').truncate -> 101
174
174
 
175
175
  ==Special values
176
- TODO
176
+
177
+ In addition to finite numbers, a Decimal object can represent some special values:
178
+ * Infinity (+Infinity, -Infinity). The method Decimal#infinite? returns true for these to values.
179
+ Decimal.infinity Decimal.infinity(-1) can be used to get these values.
180
+ * NaN (not a number) represents indefined results. The method Decimal#nan? returns true for it and
181
+ Decimal.nan can be used to obtain it. There is a variant, sNaN (signaling NaN) that casues
182
+ an invalid operation condition if used; it can be detected with Decimal.snan?.
183
+ A NaN can also include diagnostic information in its sign and coefficient.
184
+
185
+ Any of the special values can be detected with Decimal#special?
186
+ Finite numbers can be clasified with
187
+ these methods:
188
+ * Decimal#zero? detects a zero value (note that there are two zero values: +0 and -0)
189
+ * Decimal#normal? detects normal values: those whose adjusted exponents are not less than the the emin.
190
+ * Decimal#subnormal? detects subnormal values: those whose adjusted exponents are less than the the emin.
177
191
 
178
192
  ==Exceptions
179
- TODO
193
+
194
+ Exceptional conditions that may arise during operations have corresponding classes that represent them:
195
+ * Decimal::InvalidOperation
196
+ * Decimal::DivisionByZero
197
+ * Decimal::DivisionImpossible
198
+ * Decimal::DivisionUndefined
199
+ * Decimal::Inexact
200
+ * Decimal::Overflow
201
+ * Decimal::Underflow
202
+ * Decimal::Clamped
203
+ * Decimal::InvalidContext
204
+ * Decimal::Rounded
205
+ * Decimal::Subnormal
206
+ * Decimal::ConversionSyntax
207
+
208
+ For each condition, a flag and a trap (boolean values) exist in the context.
209
+ When a condition occurs, the corresponding flag in the context takes the value true (and remains
210
+ set until cleared) and a exception is raised if the corresponding trap has the value true.
211
+
212
+ Decimal.context.traps[Decimal::DivisionByZero] = false
213
+ Decimal.context.flags[Decimal::DivisionByZero] = false
214
+ puts Decimal(1)/Decimal(0) -> Infinity
215
+ puts Decimal.context.flags[Decimal::DivisionByZero] -> true
216
+ Decimal.context.traps[Decimal::DivisionByZero] = true
217
+ puts Decimal(1)/Decimal(0) -> Exception : Decimal::DivisionByZero
180
218
 
181
219
  ==Numerical conversion
182
220
 
@@ -206,6 +244,7 @@ Or with a generic method:
206
244
  Conversion is also possible to Float:
207
245
  puts Decimal('1.1').to_f -> 1.1
208
246
  puts Decimal('1.1').convert_to(Float) -> 1.1
247
+ puts Float(Decimal('1.1')) -> 1.1
209
248
 
210
249
  And with GDAS style operations:
211
250
 
@@ -252,6 +291,46 @@ Note that the conversion we've defined depends on the context precision:
252
291
 
253
292
  Decimal.local_context(:precision=>12) { puts Decimal(0.1) } -> 0.100000000000
254
293
 
294
+ Decimal.local_context(:exact=>true) { puts Decimal(0.1) } -> 0.1000000000000000055511151231257827021181583404541015625
295
+
296
+ == Abbreviation
297
+
298
+ The use of Decimal can be made less verbose by requiring:
299
+
300
+ require 'decimal/shortcut'
301
+
302
+ This file defines +D+ as a synonym for +Decimal+:
303
+
304
+ D.context.precision = 3
305
+ puts +D('1.234') -> 1.23
306
+
307
+ == Error analysis
308
+
309
+ The Decimal#ulp() method returns the value of a "unit in the last place" for a given number
310
+
311
+ D.context.precision = 4
312
+ puts D('1.5').ulp -> 0.001
313
+ puts D('1.5E10').ulp -> 1E+7
314
+
315
+ Whe can compute the error in ulps of an approximation +aprx+ to correclty rounded value +exct+ with:
316
+
317
+ def ulps(exct, aprx)
318
+ (aprx-exct).abs/exct.ulp
319
+ end
320
+
321
+ puts ulps(Decimal('0.5000'), Decimal('0.5003')) -> 3
322
+ puts ulps(Decimal('0.5000'), Decimal('0.4997')) -> 3
323
+
324
+ puts ulps(Decimal('0.1000'), Decimal('0.1003')) -> 3E+1
325
+ puts ulps(Decimal('0.1000'), Decimal('0.0997')) -> 3E+1
326
+
327
+ puts ulps(Decimal(1), Decimal(10).next_minus) -> 8.999E+4
328
+ puts ulps(Decimal(1), Decimal(10).next_plus) -> 9.01E+4
329
+
330
+ Note that in the definition of ulps we use exct.ulp. If we had use aprx.ulp Decimal(10).next_plus
331
+ would seem to be a better approximation to Decimal(1) than Decimal(10).next_minus. (Admittedly,
332
+ such bad approximations should not be common.)
333
+
255
334
  == More Information
256
335
 
257
336
  Consult the documentation for the classes Decimal and Decimal::Context.
@@ -265,25 +344,33 @@ EXPAND-
265
344
  Decimal solves some of the difficulties of using BigDecimal.
266
345
 
267
346
  One of the major problems with BigDecimal is that it's not easy to control the number of
268
- significant digits: while addition, subtraction and multiplication are exact (unless a limit is used),
269
- divisions will need to be passed precision explicitly or they will loose an indeterminate number of digits.
270
- With Decimal, Context objects are used to specify the exact number of digits to be used for all operations:
347
+ significant digits of the results. While addition, subtraction and multiplication are exact (unless a limit is used),
348
+ divisions will need to be passed precision explicitly or else an indeterminate number of significant digits will be lost.
349
+ Part of the problem is that numbers don't keep track of its precision (0.1000 is not distinguishable from 0.1.)
350
+
351
+ With Decimal, Context objects are used to specify the exact number of digits to be used for all operations making
352
+ the code cleaner and the results more easily predictable.
353
+
271
354
  Decimal.context.precision = 10
272
355
  puts Decimal(1)/Decimal(3)
273
356
  Contexts are thread-safe and can be used for individual operations:
274
- puts Decimal(1).divide(Decimal(e), Decimal::Context.new(:precision=>4))
357
+ puts Decimal(1).divide(Decimal(e), Decimal::Context(:precision=>4))
358
+ Which can be abbreviated:
359
+ puts Decimal(1).divide(Decimal(e), :precision=>4)
275
360
  Or use locally in a block without affecting other code:
276
- Decimal.local_context {
361
+ Decimal.context {
277
362
  Decimal.context.precision = 3
278
363
  puts Decimal(1)/Decimal(3)
279
364
  }
280
365
  puts Decimal.context.precision
366
+ Which can also be abbreviated:
367
+ Decimal.context(:precision=>3) { puts Decimal(1)/Decimal(3) }
281
368
 
282
369
  This allows in general to write simpler code; e.g. this is an exponential function, adapted from the
283
370
  'recipes' in Python's Decimal:
284
- def exp(x,c=nil)
371
+ def exp(x, c=nil)
285
372
  i, lasts, s, fact, num = 0, 0, 1, 1, 1
286
- Decimal.local_context(c) do |context|
373
+ Decimal.context(c) do |context|
287
374
  context.precision += 2
288
375
  while s != lasts
289
376
  lasts = s
@@ -295,9 +382,11 @@ This allows in general to write simpler code; e.g. this is an exponential functi
295
382
  end
296
383
  return +s
297
384
  end
385
+
298
386
  The final unary + applied to the result forces it to be rounded to the current precision
299
387
  (because we have computed it with two extra digits)
300
- The result of this method does not have trailing insignificant digits, as is common with BigDecimal.
388
+ The result of this method does not have trailing non-significant digits, as is common with BigDecimal
389
+ (e.g. in the exp implementation available in the standard Ruby library, in bigdecimal/math)
301
390
 
302
391
  --
303
392
  EXPAND+
@@ -305,5 +394,7 @@ EXPAND+
305
394
 
306
395
  = Roadmap
307
396
 
308
- * Version 0.3.0: Implement the remaining of GDA functions
309
- * Complete documentation (README sections on special values & exceptions, etc. and method descriptions.)
397
+ * Version 0.3.0: Implement the missing GDA functions:
398
+ rotate, shift, trim, and, or, xor, invert,
399
+ max, min, maxmag, minmag, comparetotal, comparetotmag
400
+
@@ -109,7 +109,7 @@ class Decimal
109
109
  end
110
110
  def initialize(context=nil, *args)
111
111
  @value = args.first if args.size>0
112
- super
112
+ super context
113
113
  end
114
114
  end
115
115
 
@@ -123,7 +123,7 @@ class Decimal
123
123
  end
124
124
  def initialize(context=nil, sign=nil, *args)
125
125
  @sign = sign
126
- super
126
+ super context
127
127
  end
128
128
  end
129
129
 
@@ -203,7 +203,7 @@ class Decimal
203
203
  end
204
204
  def initialize(context=nil, sign=nil, *args)
205
205
  @sign = sign
206
- super
206
+ super context
207
207
  end
208
208
  end
209
209
 
@@ -295,11 +295,15 @@ class Decimal
295
295
  # * :rounding : one of :half_even, :half_down, :half_up, :floor,
296
296
  # :ceiling, :down, :up, :up05
297
297
  # * :precision : number of digits (or 0 for exact precision)
298
- # * :exact : true or false (precision is ignored when true)
298
+ # * :exact : if true precision is ignored and Inexact conditions are trapped,
299
+ # if :quiet it set exact precision but no trapping;
299
300
  # * :traps : a Flags object with the exceptions to be trapped
300
301
  # * :flags : a Flags object with the raised flags
301
302
  # * :ignored_flags : a Flags object with the exceptions to be ignored
302
- # * :emin, :emax : minimum and maximum exponents
303
+ # * :emin, :emax : minimum and maximum adjusted exponents
304
+ # * :elimit : the exponent limits can also be defined by a single value;
305
+ # if positive it is taken as emax and emin=1-emax; otherwiae it is
306
+ # taken as emin and emax=1-emin. Such limits comply with IEEE 754-2008
303
307
  # * :capitals : (true or false) to use capitals in text representations
304
308
  # * :clamp : (true or false) enables clamping
305
309
  #
@@ -310,6 +314,9 @@ class Decimal
310
314
  base = options.shift
311
315
  copy_from base
312
316
  else
317
+ @rounding = @emin = @emax = nil
318
+ @capitals = false
319
+ @clamp = false
313
320
  @ignored_flags = Decimal::Flags()
314
321
  @traps = Decimal::Flags()
315
322
  @flags = Decimal::Flags()
@@ -346,16 +353,25 @@ class Decimal
346
353
  @ignored_flags.clear(*flags)
347
354
  end
348
355
 
349
- # 'tiny' exponet (emin - precision + 1)
356
+ # 'tiny' exponent (emin - precision + 1)
357
+ # is the minimum valid value for the (integral) exponent
350
358
  def etiny
351
359
  emin - precision + 1
352
360
  end
353
361
 
354
- # maximum exponent (emax - precision + 1)
362
+ # top exponent (emax - precision + 1)
363
+ # is the maximum valid value for the (integral) exponent
355
364
  def etop
356
365
  emax - precision + 1
357
366
  end
358
367
 
368
+ # Set the exponent limits, according to IEEE 754-2008
369
+ # if e > 0 it is taken as emax and emin=1-emax
370
+ # if e < 0 it is taken as emin and emax=1-emin
371
+ def elimit=(e)
372
+ @emin, @emax = [elimit, 1-elimit].sort
373
+ end
374
+
359
375
  # synonym for precision()
360
376
  def digits
361
377
  self.precision
@@ -420,6 +436,9 @@ class Decimal
420
436
  @traps = Decimal::Flags(options[:traps]) unless options[:traps].nil?
421
437
  @flags = Decimal::Flags(options[:flags]) unless options[:flags].nil?
422
438
  @ignored_flags = Decimal::Flags(options[:ignored_flags]) unless options[:ignored_flags].nil?
439
+ if elimit=options[:elimit]
440
+ @emin, @emax = [elimit, 1-elimit].sort
441
+ end
423
442
  @emin = options[:emin] unless options[:emin].nil?
424
443
  @emax = options[:emax] unless options[:emax].nil?
425
444
  @capitals = options[:capitals ] unless options[:capitals ].nil?
@@ -526,6 +545,12 @@ class Decimal
526
545
  _convert(x).reduce(self)
527
546
  end
528
547
 
548
+ # normalizes so that the coefficient has precision digits
549
+ # (this is not the old GDA normalize function)
550
+ def normalize(x)
551
+ _convert(x).reduce(self)
552
+ end
553
+
529
554
  # Adjusted exponent of x returned as a Decimal value.
530
555
  def logb(x)
531
556
  _convert(x).logb(self)
@@ -562,14 +587,14 @@ class Decimal
562
587
  # normalized to precision digits. (minimum exponent)
563
588
  def normalized_integral_exponent(x)
564
589
  x = _convert(x)
565
- x.integral_exponent - (precision - x.number_of_digits)
590
+ x.exponent - (precision - x.number_of_digits)
566
591
  end
567
592
 
568
593
  # Significand normalized to precision digits
569
594
  # x == normalized_integral_significand(x) * radix**(normalized_integral_exponent)
570
595
  def normalized_integral_significand(x)
571
596
  x = _convert(x)
572
- x.integral_significand*(Decimal.int_radix_power(precision - x.number_of_digits))
597
+ x.coefficient*(Decimal.int_radix_power(precision - x.number_of_digits))
573
598
  end
574
599
 
575
600
  # Returns both the (signed) normalized integral significand and the corresponding exponent
@@ -726,13 +751,87 @@ class Decimal
726
751
  _convert(x).next_toward(y, self)
727
752
  end
728
753
 
754
+ # ulp (unit in the last place) according to the definition proposed by J.M. Muller in
755
+ # "On the definition of ulp(x)" INRIA No. 5504
756
+ def ulp(x=nil)
757
+ x ||= 1
758
+ _convert(x).ulp(self)
759
+ end
760
+
761
+ # Some singular Decimal values that depend on the context
762
+
763
+ # Maximum finite number
764
+ def maximum_finite(sign=+1)
765
+ return exception(InvalidOperation, "Exact context maximum finite value") if exact?
766
+ # equals +Decimal(+1, 1, emax)
767
+ # equals Decimal.infinity.next_minus(self)
768
+ Decimal(sign, Decimal.int_radix_power(precision)-1, etop)
769
+ end
770
+
771
+ # Minimum positive normal number
772
+ def minimum_normal(sign=+1)
773
+ return exception(InvalidOperation, "Exact context maximum normal value") if exact?
774
+ Decimal(sign, 1, emin)
775
+ end
776
+
777
+ # Maximum subnormal number
778
+ def maximum_subnormal(sign=+1)
779
+ return exception(InvalidOperation, "Exact context maximum subnormal value") if exact?
780
+ # equals mininum_normal.next_minus(self)
781
+ Decimal(sign, Decimal.int_radix_power(precision-1)-1, etiny)
782
+ end
783
+
784
+ # Minimum nonzero positive number (minimum positive subnormal)
785
+ def minimum_nonzero(sign=+1)
786
+ return exception(InvalidOperation, "Exact context minimum nonzero value") if exact?
787
+ Decimal(sign, 1, etiny)
788
+ end
789
+
790
+ # This is the difference between 1 and the smallest Decimal
791
+ # value greater than 1: (Decimal(1).next_plus - Decimal(1))
792
+ def epsilon(sign=+1)
793
+ return exception(InvalidOperation, "Exact context epsilon") if exact?
794
+ Decimal(sign, 1, 1-precision)
795
+ end
796
+
797
+ # The strict epsilon is the smallest value that produces something different from 1
798
+ # wehen added to 1. It may be smaller than the general epsilon, because
799
+ # of the particular rounding rules used.
800
+ def strict_epsilon(sign=+1)
801
+ return exception(InvalidOperation, "Exact context strict epsilon") if exact?
802
+ coeff = 1
803
+ exp = 1-precision
804
+ # assume radix is even (Decimal.radix%2 == 0)
805
+ case rounding
806
+ when :down, :floor
807
+ exp = 1-precision
808
+ coeff = 1
809
+ when :half_even, :half_down #, :up # :up # :down, :half_down, :up05, :floor
810
+ exp = 1-2*precision
811
+ coeff = 1 + Decimal.int_radix_power(precision)/2
812
+ when :half_up
813
+ exp = 1-2*precision
814
+ coeff = Decimal.int_radix_power(precision)/2
815
+ when :up, :ceiling, :up05
816
+ return minimum_nonzero(sign)
817
+ end
818
+ return Decimal(sign, coeff, exp)
819
+ end
820
+
821
+ # This is the maximum relative error corresponding to 1/2 ulp:
822
+ # (radix/2)*radix**(-precision) == epsilon/2
823
+ # This is called "machine epsilon" in Goldberg's "What Every Computer Scientist..."
824
+ def half_epsilon(sign=+1)
825
+ Decimal(sign, Decimal.radix/2, -precision)
826
+ end
827
+
729
828
  def to_s
730
829
  inspect
731
830
  end
732
831
 
733
832
  def inspect
734
833
  "<#{self.class}:\n" +
735
- instance_variables.map { |v| " #{v}: #{eval(v)}"}.join("\n") +
834
+ instance_variables.map { |v| " #{v}: #{eval(v).inspect}"}.join("\n") +
736
835
  ">\n"
737
836
  end
738
837
 
@@ -809,10 +908,16 @@ class Decimal
809
908
  end
810
909
 
811
910
  def update_precision
911
+ if @emax && !@emin
912
+ @emin = 1 - @emax
913
+ elsif @emin && !@emax
914
+ @emax = 1 - @emin
915
+ end
812
916
  if @exact || @precision==0
917
+ quiet = (@exact == :quiet)
813
918
  @exact = true
814
919
  @precision = 0
815
- @traps << Inexact
920
+ @traps << Inexact unless quiet
816
921
  @ignored_flags[Inexact] = false
817
922
  else
818
923
  @traps[Inexact] = false
@@ -1003,6 +1108,16 @@ class Decimal
1003
1108
  # * Given a precision p = 8, the normalized integral representation is 12040000 with exponent -9
1004
1109
  # * The normalized fractional representation is 0.1204 with exponent -1
1005
1110
  #
1111
+ # ==Exponent limits
1112
+ #
1113
+ # The (integral) exponent e must be within this limits: etiny <= e <= etop
1114
+ # The adjusted exponent a must: emin <= a <= emax
1115
+ # emin, emax are the limite of the exponent shown in scientific notation and are use to defined
1116
+ # the exponent limits in the contexts.
1117
+ # etiny = emin-precision+1 and etop=emax-precision+1 are the limits of the internal exponent.
1118
+ # Note that for significands with less than precision digits we can use exponents greater than etop
1119
+ # without causing overflow: +Decimal(+1,1,emax) == Decimal(+1,K,etop) where K=10**(precision-1)
1120
+ #
1006
1121
  # =Interoperatibility with other numeric types
1007
1122
  #
1008
1123
  # For some numeric types implicit conversion to Decimal is defined through these methods:
@@ -1044,14 +1159,26 @@ class Decimal
1044
1159
  arg.delete :exponent
1045
1160
  context ||= arg
1046
1161
  end
1162
+ args = args.first if args.size==1 && args.first.is_a?(Array)
1047
1163
 
1048
1164
  context = Decimal.define_context(context)
1049
1165
 
1050
1166
  case args.size
1051
1167
  when 3
1168
+ # internal representation
1052
1169
  @sign, @coeff, @exp = args
1053
1170
  # TO DO: validate
1054
1171
 
1172
+ when 2
1173
+ # signed integer and scale
1174
+ @coeff, @exp = args
1175
+ if @coeff < 0
1176
+ @sign = -1
1177
+ @coeff = -@coeff
1178
+ else
1179
+ @sign = +1
1180
+ end
1181
+
1055
1182
  when 1
1056
1183
  arg = args.first
1057
1184
  case arg
@@ -1108,19 +1235,17 @@ class Decimal
1108
1235
  @exp = :inf
1109
1236
  end
1110
1237
  end
1111
- when Array
1112
- @sign, @coeff, @exp = arg
1113
1238
  else
1114
1239
  raise TypeError, "invalid argument #{arg.inspect}"
1115
1240
  end
1116
1241
  else
1117
- raise ArgumentError, "wrong number of arguments (#{args.size} for 1 or 3)"
1242
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 1, 2 or 3)"
1118
1243
  end
1119
1244
  end
1120
1245
 
1121
1246
  # Returns the internal representation of the number, composed of:
1122
1247
  # * a sign which is +1 for plus and -1 for minus
1123
- # * a coefficient (significand) which is an integer
1248
+ # * a coefficient (significand) which is a nonnegative integer
1124
1249
  # * an exponent (an integer) or :inf, :nan or :snan for special values
1125
1250
  # The value of non-special numbers is sign*coefficient*10^exponent
1126
1251
  def split
@@ -1289,7 +1414,7 @@ class Decimal
1289
1414
  return Decimal(other) if other.infinite?
1290
1415
  end
1291
1416
 
1292
- exp = [self.integral_exponent, other.integral_exponent].min
1417
+ exp = [self.exponent, other.exponent].min
1293
1418
  negativezero = (context.rounding == ROUND_FLOOR && self.sign != other.sign)
1294
1419
 
1295
1420
  if self.zero? && other.zero?
@@ -1300,12 +1425,12 @@ class Decimal
1300
1425
  end
1301
1426
 
1302
1427
  if self.zero?
1303
- exp = [exp, other.integral_exponent - context.precision - 1].max unless context.exact?
1428
+ exp = [exp, other.exponent - context.precision - 1].max unless context.exact?
1304
1429
  return other._rescale(exp, context.rounding)._fix(context)
1305
1430
  end
1306
1431
 
1307
1432
  if other.zero?
1308
- exp = [exp, self.integral_exponent - context.precision - 1].max unless context.exact?
1433
+ exp = [exp, self.exponent - context.precision - 1].max unless context.exact?
1309
1434
  return self._rescale(exp, context.rounding)._fix(context)
1310
1435
  end
1311
1436
 
@@ -1313,8 +1438,8 @@ class Decimal
1313
1438
 
1314
1439
  result_sign = result_coeff = result_exp = nil
1315
1440
  if op1.sign != op2.sign
1316
- return ans = Decimal.new([negativezero ? -1 : +1, 0, exp])._fix(context) if op1.integral_significand == op2.integral_significand
1317
- op1,op2 = op2,op1 if op1.integral_significand < op2.integral_significand
1441
+ return ans = Decimal.new([negativezero ? -1 : +1, 0, exp])._fix(context) if op1.coefficient == op2.coefficient
1442
+ op1,op2 = op2,op1 if op1.coefficient < op2.coefficient
1318
1443
  result_sign = op1.sign
1319
1444
  op1,op2 = op1.copy_negate, op2.copy_negate if result_sign < 0
1320
1445
  elsif op1.sign < 0
@@ -1325,12 +1450,12 @@ class Decimal
1325
1450
  end
1326
1451
 
1327
1452
  if op2.sign == +1
1328
- result_coeff = op1.integral_significand + op2.integral_significand
1453
+ result_coeff = op1.coefficient + op2.coefficient
1329
1454
  else
1330
- result_coeff = op1.integral_significand - op2.integral_significand
1455
+ result_coeff = op1.coefficient - op2.coefficient
1331
1456
  end
1332
1457
 
1333
- result_exp = op1.integral_exponent
1458
+ result_exp = op1.exponent
1334
1459
 
1335
1460
  return Decimal([result_sign, result_coeff, result_exp])._fix(context)
1336
1461
 
@@ -1369,13 +1494,13 @@ class Decimal
1369
1494
  end
1370
1495
  end
1371
1496
 
1372
- resultexp = self.integral_exponent + other.integral_exponent
1497
+ resultexp = self.exponent + other.exponent
1373
1498
 
1374
1499
  return Decimal([resultsign, 0, resultexp])._fix(context) if self.zero? || other.zero?
1375
- #return Decimal([resultsign, other.integral_significand, resultexp])._fix(context) if self.integral_significand==1
1376
- #return Decimal([resultsign, self.integral_significand, resultexp])._fix(context) if other.integral_significand==1
1500
+ #return Decimal([resultsign, other.coefficient, resultexp])._fix(context) if self.coefficient==1
1501
+ #return Decimal([resultsign, self.coefficient, resultexp])._fix(context) if other.coefficient==1
1377
1502
 
1378
- return Decimal([resultsign, other.integral_significand*self.integral_significand, resultexp])._fix(context)
1503
+ return Decimal([resultsign, other.coefficient*self.coefficient, resultexp])._fix(context)
1379
1504
 
1380
1505
  end
1381
1506
 
@@ -1403,22 +1528,22 @@ class Decimal
1403
1528
  end
1404
1529
 
1405
1530
  if self.zero?
1406
- exp = self.integral_exponent - other.integral_exponent
1531
+ exp = self.exponent - other.exponent
1407
1532
  coeff = 0
1408
1533
  else
1409
1534
  prec = context.exact? ? self.number_of_digits + 4*other.number_of_digits : context.precision # this assumes radix==10
1410
1535
  shift = other.number_of_digits - self.number_of_digits + prec + 1
1411
- exp = self.integral_exponent - other.integral_exponent - shift
1536
+ exp = self.exponent - other.exponent - shift
1412
1537
  if shift >= 0
1413
- coeff, remainder = (self.integral_significand*Decimal.int_radix_power(shift)).divmod(other.integral_significand)
1538
+ coeff, remainder = (self.coefficient*Decimal.int_radix_power(shift)).divmod(other.coefficient)
1414
1539
  else
1415
- coeff, remainder = self.integral_significand.divmod(other.integral_significand*Decimal.int_radix_power(-shift))
1540
+ coeff, remainder = self.coefficient.divmod(other.coefficient*Decimal.int_radix_power(-shift))
1416
1541
  end
1417
1542
  if remainder != 0
1418
1543
  return context.exception(Inexact) if context.exact?
1419
1544
  coeff += 1 if (coeff%(Decimal.radix/2)) == 0
1420
1545
  else
1421
- ideal_exp = self.integral_exponent - other.integral_exponent
1546
+ ideal_exp = self.exponent - other.exponent
1422
1547
  while (exp < ideal_exp) && ((coeff % Decimal.radix)==0)
1423
1548
  coeff /= Decimal.radix
1424
1549
  exp += 1
@@ -1794,7 +1919,7 @@ class Decimal
1794
1919
  return Decimal.new(self)._fix(context)
1795
1920
  end
1796
1921
 
1797
- ideal_exp = [self.integral_exponent, other.integral_exponent].min
1922
+ ideal_exp = [self.exponent, other.exponent].min
1798
1923
  if self.zero?
1799
1924
  return Decimal([self.sign, 0, ideal_exp])._fix(context)
1800
1925
  end
@@ -1806,9 +1931,9 @@ class Decimal
1806
1931
  return self._rescale(ideal_exp, context.rounding)._fix(context)
1807
1932
  end
1808
1933
 
1809
- self_coeff = self.integral_significand
1810
- other_coeff = other.integral_significand
1811
- de = self.integral_exponent - other.integral_exponent
1934
+ self_coeff = self.coefficient
1935
+ other_coeff = other.coefficient
1936
+ de = self.exponent - other.exponent
1812
1937
  if de >= 0
1813
1938
  self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
1814
1939
  else
@@ -1848,15 +1973,30 @@ class Decimal
1848
1973
 
1849
1974
  exp_max = context.clamp? ? context.etop : context.emax
1850
1975
  end_d = nd = dup.number_of_digits
1851
- exp = dup.integral_exponent
1852
- coeff = dup.integral_significand
1976
+ exp = dup.exponent
1977
+ coeff = dup.coefficient
1853
1978
  dgs = dup.digits
1854
1979
  while (dgs[end_d-1]==0) && (exp < exp_max)
1855
1980
  exp += 1
1856
1981
  end_d -= 1
1857
1982
  end
1858
1983
  return Decimal.new([dup.sign, coeff/Decimal.int_radix_power(nd-end_d), exp])
1984
+ end
1859
1985
 
1986
+ # normalizes so that the coefficient has precision digits
1987
+ # (this is not the old GDA normalize function)
1988
+ def normalize(context=nil)
1989
+ context = Decimal.define_context(context)
1990
+ return Decimal(self) if self.special? || self.zero?
1991
+ return context.exception(InvalidOperation, "Normalize in exact context") if context.exact?
1992
+ return context.exception(Subnormal, "Cannot normalize subnormal") if self.subnormal?
1993
+ min_normal_coeff = Decimal.int_radix_power(context.precision-1)
1994
+ sign, coeff, exp = self._fix(context).split
1995
+ while coeff < min_normal_coeff
1996
+ coeff *= Decimal.radix
1997
+ exp -= 1
1998
+ end
1999
+ Decimal(sign, coeff, exp)
1860
2000
  end
1861
2001
 
1862
2002
  # Returns the exponent of the magnitude of the most significant digit.
@@ -1881,7 +2021,7 @@ class Decimal
1881
2021
  other = _convert(other)
1882
2022
  ans = _check_nans(context, other)
1883
2023
  return ans if ans
1884
- return context.exception(InvalidOperation) if other.infinite? || other.integral_exponent != 0
2024
+ return context.exception(InvalidOperation) if other.infinite? || other.exponent != 0
1885
2025
  unless context.exact?
1886
2026
  liminf = -2 * (context.emax + context.precision)
1887
2027
  limsup = 2 * (context.emax + context.precision)
@@ -1996,10 +2136,50 @@ class Decimal
1996
2136
  end
1997
2137
  end
1998
2138
 
2139
+ # ulp (unit in the last place) according to the definition proposed by J.M. Muller in
2140
+ # "On the definition of ulp(x)" INRIA No. 5504
2141
+ def ulp(context = nil)
2142
+ context = Decimal.define_context(context)
2143
+
2144
+ return context.exception(InvalidOperation, "ulp in exact context") if context.exact?
2145
+
2146
+ if self.nan?
2147
+ return Decimal(self)
2148
+ elsif self.infinite?
2149
+ # The ulp here is context.maximum_finite - context.maximum_finite.next_minus
2150
+ return Decimal(+1, 1, context.etop)
2151
+ elsif self.zero? || self.adjusted_exponent <= context.emin
2152
+ # This is the ulp value for self.abs <= context.minimum_normal*Decimal.context
2153
+ # Here we use it for self.abs < context.minimum_normal*Decimal.context;
2154
+ # because of the simple exponent check; the remaining cases are handled below.
2155
+ return context.minimum_nonzero
2156
+ else
2157
+ # The next can compute the ulp value for the values that
2158
+ # self.abs > context.minimum_normal && self.abs <= context.maximum_finite
2159
+ # The cases self.abs < context.minimum_normal*Decimal.context have been handled above.
2160
+
2161
+ # assert self.normal? && self.abs>context.minimum_nonzero
2162
+ norm = self.normalize
2163
+ exp = norm.integral_exponent
2164
+ sig = norm.integral_significand
2165
+
2166
+ # Powers of the radix, r**n, are between areas with different ulp values: r**(n-p-1) and r**(n-p)
2167
+ # (p is context.precision).
2168
+ # This method and the ulp definitions by Muller, Kahan and Harrison assign the smaller ulp value
2169
+ # to r**n; the definition by Goldberg assigns it to the larger ulp.
2170
+ # The next line selects the smaller ulp for powers of the radix:
2171
+ exp -= 1 if sig == Decimal.int_radix_power(context.precision-1)
2172
+
2173
+ return Decimal(+1, 1, exp)
2174
+ end
2175
+ end
2176
+
1999
2177
  def inspect
2000
- #"Decimal('#{self}')"
2001
- #debug:
2002
- "Decimal('#{self}') [coeff:#{@coeff.inspect} exp:#{@exp.inspect} s:#{@sign.inspect}]"
2178
+ if $DEBUG
2179
+ "Decimal('#{self}') [coeff:#{@coeff.inspect} exp:#{@exp.inspect} s:#{@sign.inspect}]"
2180
+ else
2181
+ "Decimal('#{self}')"
2182
+ end
2003
2183
  end
2004
2184
 
2005
2185
  # Internal comparison operator: returns -1 if the first number is less than the second,
@@ -2033,8 +2213,8 @@ class Decimal
2033
2213
  self_adjusted = self.adjusted_exponent
2034
2214
  other_adjusted = other.adjusted_exponent
2035
2215
  if self_adjusted == other_adjusted
2036
- self_padded,other_padded = self.integral_significand,other.integral_significand
2037
- d = self.integral_exponent - other.integral_exponent
2216
+ self_padded,other_padded = self.coefficient,other.coefficient
2217
+ d = self.exponent - other.exponent
2038
2218
  if d>0
2039
2219
  self_padded *= Decimal.int_radix_power(d)
2040
2220
  else
@@ -2115,12 +2295,12 @@ class Decimal
2115
2295
  @coeff.to_s.size
2116
2296
  end
2117
2297
 
2118
- # Significand as an integer, unsigned
2298
+ # Significand as an integer, unsigned. Synonym of coefficient
2119
2299
  def integral_significand
2120
2300
  @coeff
2121
2301
  end
2122
2302
 
2123
- # Exponent of the significand as an integer
2303
+ # Exponent of the significand as an integer. Synonym of exponent
2124
2304
  def integral_exponent
2125
2305
  # fractional_exponent - number_of_digits
2126
2306
  @exp
@@ -2131,7 +2311,17 @@ class Decimal
2131
2311
  @sign
2132
2312
  end
2133
2313
 
2134
- # Return the value of the number as an integer and a scale.
2314
+ # Significand as an integer, unsigned
2315
+ def coefficient
2316
+ @coeff
2317
+ end
2318
+
2319
+ # Exponent of the significand as an integer.
2320
+ def exponent
2321
+ @exp
2322
+ end
2323
+
2324
+ # Return the value of the number as an signed integer and a scale.
2135
2325
  def to_int_scale
2136
2326
  if special?
2137
2327
  nil
@@ -2252,7 +2442,7 @@ class Decimal
2252
2442
  return context.exception(InvalidOperation, 'quantize with one INF')
2253
2443
  end
2254
2444
  end
2255
- exp = exp.integral_exponent
2445
+ exp = exp.exponent
2256
2446
  _watched_rescale(exp, context, watch_exp)
2257
2447
  end
2258
2448
 
@@ -2267,7 +2457,7 @@ class Decimal
2267
2457
  if self.special? || other.special?
2268
2458
  return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
2269
2459
  end
2270
- return self.integral_exponent == other.integral_exponent
2460
+ return self.exponent == other.exponent
2271
2461
  end
2272
2462
 
2273
2463
  # Rounds to a nearby integer. May raise Inexact or Rounded.
@@ -2392,7 +2582,7 @@ class Decimal
2392
2582
  product = Decimal.infinity(self.sign*other.sign)
2393
2583
  end
2394
2584
  else
2395
- product = Decimal.new([self.sign*other.sign,self.integral_significand*other.integral_significand, self.integral_exponent+other.integral_exponent])
2585
+ product = Decimal.new([self.sign*other.sign,self.coefficient*other.coefficient, self.exponent+other.exponent])
2396
2586
  end
2397
2587
  return product.add(third, context)
2398
2588
  end
@@ -2486,7 +2676,7 @@ class Decimal
2486
2676
  multiplier = other.to_i
2487
2677
  end
2488
2678
 
2489
- exp = _self.integral_exponent * multiplier
2679
+ exp = _self.exponent * multiplier
2490
2680
  if exp < 1-context.precision
2491
2681
  exp = 1-context.precision
2492
2682
  context.exception Rounded
@@ -2551,7 +2741,7 @@ class Decimal
2551
2741
  end
2552
2742
  ans = _self._power_exact(other, test_precision)
2553
2743
  if !ans.nil? && (result_sign == -1)
2554
- ans = Decimal(-1, ans.integral_significand, ans.integral_exponent)
2744
+ ans = Decimal(-1, ans.coefficient, ans.exponent)
2555
2745
  end
2556
2746
  end
2557
2747
 
@@ -2562,10 +2752,10 @@ class Decimal
2562
2752
  return context.exception(Inexact, "Inexact power") if context.exact?
2563
2753
 
2564
2754
  p = context.precision
2565
- xc = _self.integral_significand
2566
- xe = _self.integral_exponent
2567
- yc = other.integral_significand
2568
- ye = other.integral_exponent
2755
+ xc = _self.coefficient
2756
+ xe = _self.exponent
2757
+ yc = other.coefficient
2758
+ ye = other.exponent
2569
2759
  yc = -yc if other.sign == -1
2570
2760
 
2571
2761
  # compute correctly rounded result: start with precision +3,
@@ -2591,7 +2781,7 @@ class Decimal
2591
2781
  # pad with zeros up to length context.precision+1 if necessary
2592
2782
  if ans.number_of_digits <= context.precision
2593
2783
  expdiff = context.precision+1 - ans.number_of_digits
2594
- ans = Decimal(ans.sign, Decimal.int_mult_radix_power(ans.integral_significand, expdiff), ans.integral_exponent-expdiff)
2784
+ ans = Decimal(ans.sign, Decimal.int_mult_radix_power(ans.coefficient, expdiff), ans.exponent-expdiff)
2595
2785
  end
2596
2786
  context.exception Underflow if ans.adjusted_exponent < context.emin
2597
2787
  end
@@ -2621,13 +2811,13 @@ class Decimal
2621
2811
  # log10(10**n) = n
2622
2812
  if digits.first == 1 && digits[1..-1].all?{|d| d==0}
2623
2813
  # answer may need rounding
2624
- ans = Decimal(self.integral_exponent + digits.size - 1)
2814
+ ans = Decimal(self.exponent + digits.size - 1)
2625
2815
  return ans if context.exact?
2626
2816
  else
2627
2817
  # result is irrational, so necessarily inexact
2628
2818
  return context.exception(Inexact, "Inexact power") if context.exact?
2629
- c = self.integral_significand
2630
- e = self.integral_exponent
2819
+ c = self.coefficient
2820
+ e = self.exponent
2631
2821
  p = context.precision
2632
2822
 
2633
2823
  # correctly rounded result: repeatedly increase precision
@@ -2694,8 +2884,8 @@ class Decimal
2694
2884
  ans = Decimal(+1, Decimal.int_radix_power(p+1)-1, -p-1)
2695
2885
  else
2696
2886
  # general case
2697
- c = self.integral_significand
2698
- e = self.integral_exponent
2887
+ c = self.coefficient
2888
+ e = self.exponent
2699
2889
  c = -c if self.sign == -1
2700
2890
 
2701
2891
  # compute correctly rounded result: increase precision by
@@ -2744,8 +2934,8 @@ class Decimal
2744
2934
  # result is irrational, so necessarily inexact
2745
2935
  return context.exception(Inexact, 'Inexact exp') if context.exact?
2746
2936
 
2747
- c = self.integral_significand
2748
- e = self.integral_exponent
2937
+ c = self.coefficient
2938
+ e = self.exponent
2749
2939
  p = context.precision
2750
2940
 
2751
2941
  # correctly rounded result: repeatedly increase precision by 3
@@ -2798,9 +2988,9 @@ class Decimal
2798
2988
 
2799
2989
  return Decimal.new(self) if special?
2800
2990
  return Decimal.new([sign, 0, exp]) if zero?
2801
- return Decimal.new([sign, @coeff*Decimal.int_radix_power(self.integral_exponent - exp), exp]) if self.integral_exponent > exp
2802
- #nd = number_of_digits + self.integral_exponent - exp
2803
- nd = exp - self.integral_exponent
2991
+ return Decimal.new([sign, @coeff*Decimal.int_radix_power(self.exponent - exp), exp]) if self.exponent > exp
2992
+ #nd = number_of_digits + self.exponent - exp
2993
+ nd = exp - self.exponent
2804
2994
  if number_of_digits < nd
2805
2995
  slf = Decimal.new([sign, 1, exp-1])
2806
2996
  nd = number_of_digits
@@ -2817,7 +3007,7 @@ class Decimal
2817
3007
  def _watched_rescale(exp, context, watch_exp)
2818
3008
  if !watch_exp
2819
3009
  ans = _rescale(exp, context.rounding)
2820
- context.exception(Rounded) if ans.integral_exponent > self.integral_exponent
3010
+ context.exception(Rounded) if ans.exponent > self.exponent
2821
3011
  context.exception(Inexact) if ans != self
2822
3012
  return ans
2823
3013
  end
@@ -2835,7 +3025,7 @@ class Decimal
2835
3025
  ans = _rescale(exp, context.rounding)
2836
3026
  return context.exception(InvalidOperation,"exponent of rescale result too large for current context") if ans.adjusted_exponent > context.emax
2837
3027
  return context.exception(InvalidOperation,"rescale result has too many digits for current context") if (ans.number_of_digits > context.precision) && !context.exact?
2838
- if ans.integral_exponent > self.integral_exponent
3028
+ if ans.exponent > self.exponent
2839
3029
  context.exception(Rounded)
2840
3030
  context.exception(Inexact) if ans!=self
2841
3031
  end
@@ -2941,7 +3131,7 @@ class Decimal
2941
3131
  d = Decimal.new(self)
2942
3132
  end
2943
3133
  changed = d._round(context.rounding, dg)
2944
- coeff = Decimal.int_div_radix_power(d.integral_significand, dg)
3134
+ coeff = Decimal.int_div_radix_power(d.coefficient, dg)
2945
3135
  coeff += 1 if changed==1
2946
3136
  ans = Decimal.new([sign, coeff, exp_min])
2947
3137
  if changed!=0
@@ -2952,8 +3142,8 @@ class Decimal
2952
3142
  context.exception Clamped
2953
3143
  end
2954
3144
  elsif ans.number_of_digits == context.precision+1
2955
- if ans.integral_exponent< etop
2956
- ans = Decimal.new([ans.sign, Decimal.int_div_radix_power(ans.integral_significand,1), ans.integral_exponent+1])
3145
+ if ans.exponent< etop
3146
+ ans = Decimal.new([ans.sign, Decimal.int_div_radix_power(ans.coefficient,1), ans.exponent+1])
2957
3147
  else
2958
3148
  ans = context.exception(Overflow, 'above Emax', d.sign)
2959
3149
  end
@@ -2994,9 +3184,9 @@ class Decimal
2994
3184
  context = Decimal.define_context(context)
2995
3185
  sign = self.sign * other.sign
2996
3186
  if other.infinite?
2997
- ideal_exp = self.integral_exponent
3187
+ ideal_exp = self.exponent
2998
3188
  else
2999
- ideal_exp = [self.integral_exponent, other.integral_exponent].min
3189
+ ideal_exp = [self.exponent, other.exponent].min
3000
3190
  end
3001
3191
 
3002
3192
  expdiff = self.adjusted_exponent - other.adjusted_exponent
@@ -3004,9 +3194,9 @@ class Decimal
3004
3194
  return [Decimal.new([sign, 0, 0]), _rescale(ideal_exp, context.rounding)]
3005
3195
  end
3006
3196
  if (expdiff <= context.precision) || context.exact?
3007
- self_coeff = self.integral_significand
3008
- other_coeff = other.integral_significand
3009
- de = self.integral_exponent - other.integral_exponent
3197
+ self_coeff = self.coefficient
3198
+ other_coeff = other.coefficient
3199
+ de = self.exponent - other.exponent
3010
3200
  if de >= 0
3011
3201
  self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
3012
3202
  else
@@ -3027,9 +3217,9 @@ class Decimal
3027
3217
  context = Decimal.define_context(context)
3028
3218
  sign = self.sign * other.sign
3029
3219
  if other.infinite?
3030
- ideal_exp = self.integral_exponent
3220
+ ideal_exp = self.exponent
3031
3221
  else
3032
- ideal_exp = [self.integral_exponent, other.integral_exponent].min
3222
+ ideal_exp = [self.exponent, other.exponent].min
3033
3223
  end
3034
3224
 
3035
3225
  expdiff = self.adjusted_exponent - other.adjusted_exponent
@@ -3037,9 +3227,9 @@ class Decimal
3037
3227
  return [Decimal.new([sign, 0, 0]), _rescale(ideal_exp, context.rounding)]
3038
3228
  end
3039
3229
  if (expdiff <= context.precision) || context.exact?
3040
- self_coeff = self.integral_significand*self.sign
3041
- other_coeff = other.integral_significand*other.sign
3042
- de = self.integral_exponent - other.integral_exponent
3230
+ self_coeff = self.coefficient*self.sign
3231
+ other_coeff = other.coefficient*other.sign
3232
+ de = self.exponent - other.exponent
3043
3233
  if de >= 0
3044
3234
  self_coeff = Decimal.int_mult_radix_power(self_coeff, de)
3045
3235
  else
@@ -3108,12 +3298,12 @@ class Decimal
3108
3298
  sign = other.even? ? +1 : -1
3109
3299
  modulo = modulo.to_i.abs
3110
3300
 
3111
- base = (self.integral_significand % modulo * (Decimal.int_radix_power(self.integral_exponent) % modulo)) % modulo
3301
+ base = (self.coefficient % modulo * (Decimal.int_radix_power(self.exponent) % modulo)) % modulo
3112
3302
 
3113
- other.integral_exponent.times do
3303
+ other.exponent.times do
3114
3304
  base = (base**Decimal.radix) % modulo
3115
3305
  end
3116
- base = (base**other.integral_significand) % modulo
3306
+ base = (base**other.coefficient) % modulo
3117
3307
 
3118
3308
  Decimal(sign, base, 0)
3119
3309
  end
@@ -3127,8 +3317,8 @@ class Decimal
3127
3317
  # Assumes that elimination of special cases has already been
3128
3318
  # performed: self and other must both be nonspecial; self must
3129
3319
  # be positive and not numerically equal to 1; other must be
3130
- # nonzero. For efficiency, other.integral_exponent should not be too large,
3131
- # so that 10**other.integral.exponent.abs is a feasible calculation.
3320
+ # nonzero. For efficiency, other.exponent should not be too large,
3321
+ # so that 10**other.exponent.abs is a feasible calculation.
3132
3322
  def _power_exact(other, p)
3133
3323
 
3134
3324
  # In the comments below, we write x for the value of self and
@@ -3176,15 +3366,15 @@ class Decimal
3176
3366
  # Similarly, len(str(abs(yc)*xc_bits)) <= -ye implies |y|
3177
3367
  # < 1/nbits(xc).
3178
3368
 
3179
- xc = self.integral_significand
3180
- xe = self.integral_exponent
3369
+ xc = self.coefficient
3370
+ xe = self.exponent
3181
3371
  while (xc % Decimal.radix) == 0
3182
3372
  xc /= Decimal.radix
3183
3373
  xe += 1
3184
3374
  end
3185
3375
 
3186
- yc = other.integral_significand
3187
- ye = other.integral_exponent
3376
+ yc = other.coefficient
3377
+ ye = other.exponent
3188
3378
  while (yc % Decimal.radix) == 0
3189
3379
  yc /= Decimal.radix
3190
3380
  ye += 1
@@ -3202,7 +3392,7 @@ class Decimal
3202
3392
  exponent = -exponent if other.sign == -1
3203
3393
  # if other is a nonnegative integer, use ideal exponent
3204
3394
  if other.integral? and (other.sign == +1)
3205
- ideal_exponent = self.integral_exponent*other.to_i
3395
+ ideal_exponent = self.exponent*other.to_i
3206
3396
  zeros = [exponent-ideal_exponent, p-1].min
3207
3397
  else
3208
3398
  zeros = 0
@@ -3320,7 +3510,7 @@ class Decimal
3320
3510
  # exponent, if necessary
3321
3511
  str_xc = xc.to_s
3322
3512
  if other.integral? && other.sign == +1
3323
- ideal_exponent = self.integral_exponent*other.to_i
3513
+ ideal_exponent = self.exponent*other.to_i
3324
3514
  zeros = [xe-ideal_exponent, p-str_xc.length].min
3325
3515
  else
3326
3516
  zeros = 0
@@ -3448,12 +3638,12 @@ class Decimal
3448
3638
  # 1-1/x <= log(x) <= x-1. If x > 1 we have |log10(x)| >
3449
3639
  # (1-1/x)/2.31 > 0. If x < 1 then |log10(x)| > (1-x)/2.31 > 0
3450
3640
 
3451
- adj = self.integral_exponent + number_of_digits - 1
3641
+ adj = self.exponent + number_of_digits - 1
3452
3642
  return adj.to_s.length - 1 if adj >= 1 # self >= 10
3453
3643
  return (-1-adj).to_s.length-1 if adj <= -2 # self < 0.1
3454
3644
 
3455
- c = self.integral_significand
3456
- e = self.integral_exponent
3645
+ c = self.coefficient
3646
+ e = self.exponent
3457
3647
  if adj == 0
3458
3648
  # 1 < self < 10
3459
3649
  num = (c - Decimal.int_radix_power(-e)).to_s
@@ -3470,7 +3660,7 @@ class Decimal
3470
3660
  # that self is finite and positive and that self != 1.
3471
3661
  def _ln_exp_bound
3472
3662
  # for 0.1 <= x <= 10 we use the inequalities 1-1/x <= ln(x) <= x-1
3473
- adj = self.integral_exponent + number_of_digits - 1
3663
+ adj = self.exponent + number_of_digits - 1
3474
3664
  if adj >= 1
3475
3665
  # argument >= 10; we use 23/10 = 2.3 as a lower bound for ln(10)
3476
3666
  return (adj*23/10).to_s.length - 1
@@ -3479,8 +3669,8 @@ class Decimal
3479
3669
  # argument <= 0.1
3480
3670
  return ((-1-adj)*23/10).to_s.length - 1
3481
3671
  end
3482
- c = self.integral_significand
3483
- e = self.integral_exponent
3672
+ c = self.coefficient
3673
+ e = self.exponent
3484
3674
  if adj == 0
3485
3675
  # 1 < self < 10
3486
3676
  num = (c-(10**-e)).to_s
@@ -3519,7 +3709,7 @@ class Decimal
3519
3709
 
3520
3710
  # Normalizes op1, op2 to have the same exp and length of coefficient. Used for addition.
3521
3711
  def _normalize(op1, op2, prec=0)
3522
- if op1.integral_exponent < op2.integral_exponent
3712
+ if op1.exponent < op2.exponent
3523
3713
  swap = true
3524
3714
  tmp,other = op2,op1
3525
3715
  else
@@ -3528,13 +3718,13 @@ class Decimal
3528
3718
  end
3529
3719
  tmp_len = tmp.number_of_digits
3530
3720
  other_len = other.number_of_digits
3531
- exp = tmp.integral_exponent + [-1, tmp_len - prec - 2].min
3532
- if (other_len+other.integral_exponent-1 < exp) && prec>0
3721
+ exp = tmp.exponent + [-1, tmp_len - prec - 2].min
3722
+ if (other_len+other.exponent-1 < exp) && prec>0
3533
3723
  other = Decimal.new([other.sign, 1, exp])
3534
3724
  end
3535
3725
  tmp = Decimal.new(tmp.sign,
3536
- Decimal.int_mult_radix_power(tmp.integral_significand, tmp.integral_exponent-other.integral_exponent),
3537
- other.integral_exponent)
3726
+ Decimal.int_mult_radix_power(tmp.coefficient, tmp.exponent-other.exponent),
3727
+ other.exponent)
3538
3728
  return swap ? [other, tmp] : [tmp, other]
3539
3729
  end
3540
3730