ruby-decimal 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
1
  == 0.1.0 2009-06-19
2
2
 
3
- * Initial release
3
+ * Initial release 0.1.0
4
+
5
+ == 0.2.0 2009-06-21
6
+
7
+ * Release 0.2.0
8
+ New functions implemented: exp(), ln(), log10(), power().
9
+
data/README.txt CHANGED
@@ -9,6 +9,10 @@ define a nice feature-set and API for Decimal and have a good test suite for its
9
9
  specification. Then an efficient implementation could be written, for example
10
10
  by using a C extension wrapper around the decNumber library.
11
11
 
12
+ The documentation for this package is available at http://ruby-decimal.rubyforge.org/
13
+
14
+ The code is at http://github.com/jgoizueta/ruby-decimal/
15
+
12
16
  == Standars compliance.
13
17
 
14
18
  Decimal pretends to be conformant to the General Decimal Arithmetic Specification
@@ -248,7 +252,7 @@ Note that the conversion we've defined depends on the context precision:
248
252
 
249
253
  Decimal.local_context(:precision=>12) { puts Decimal(0.1) } -> 0.100000000000
250
254
 
251
- == Available functionality
255
+ == More Information
252
256
 
253
257
  Consult the documentation for the classes Decimal and Decimal::Context.
254
258
 
@@ -301,6 +305,5 @@ EXPAND+
301
305
 
302
306
  = Roadmap
303
307
 
308
+ * Version 0.3.0: Implement the remaining of GDA functions
304
309
  * Complete documentation (README sections on special values & exceptions, etc. and method descriptions.)
305
- * Version 0.2.0: Implement GDAS exp(), power(), ln() log10() and also the Ruby-style operator **.
306
- * Version 0.3.0:
@@ -37,6 +37,16 @@ class Decimal
37
37
  attr_reader :base_conversions
38
38
  end
39
39
 
40
+ #--
41
+ # Some functions use the next methods instead of 10, 10**x, etc.
42
+ # This has been done for two reasons:
43
+ # * Much of the code of Decimal is generic enough to work for non-decimal floating-point numbers.
44
+ # In the future a binary (or arbitrary radix) class could be derived from Decimal.
45
+ # * The radix power operations could be optimized (specinally for binary)
46
+ # But note that some code (e.g. powers & logarithms, auxiliar funtions) use algorithms
47
+ # that assume radix=10.
48
+ #++
49
+
40
50
  # Numerical base of Decimal.
41
51
  def self.radix
42
52
  10
@@ -146,8 +156,12 @@ class Decimal
146
156
  # This occurs and signals inexact whenever the result of an operation is
147
157
  # not exact (that is, it needed to be rounded and any discarded digits
148
158
  # were non-zero), or if an overflow or underflow condition occurs. The
149
- # result in all cases is unchanged.
159
+ # result in all cases is unchanged unless the context has exact precision,
160
+ # in which case the result is Nan
150
161
  class Inexact < Exception
162
+ def self.handle(context, *args)
163
+ Decimal.nan if context.exact?
164
+ end
151
165
  end
152
166
 
153
167
  # Overflow Exception.
@@ -308,6 +322,13 @@ class Decimal
308
322
 
309
323
  attr_accessor :rounding, :emin, :emax, :flags, :traps, :ignored_flags, :capitals, :clamp
310
324
 
325
+ # TODO: consider the convenience of adding accessors of this kind:
326
+ # def rounding(new_rounding=nil)
327
+ # old_rounding = @rounding
328
+ # @rounding = new_rounding unless new_rounding.nil?
329
+ # old_rounding
330
+ # end
331
+
311
332
  # Ignore all flags if they are raised
312
333
  def ignore_all_flags
313
334
  #@ignored_flags << EXCEPTIONS
@@ -450,42 +471,42 @@ class Decimal
450
471
 
451
472
  # Addition of two decimal numbers
452
473
  def add(x,y)
453
- Decimal._convert(x).add(y,self)
474
+ _convert(x).add(y,self)
454
475
  end
455
476
 
456
477
  # Subtraction of two decimal numbers
457
478
  def subtract(x,y)
458
- Decimal._convert(x).subtract(y,self)
479
+ _convert(x).subtract(y,self)
459
480
  end
460
481
 
461
482
  # Multiplication of two decimal numbers
462
483
  def multiply(x,y)
463
- Decimal._convert(x).multiply(y,self)
484
+ _convert(x).multiply(y,self)
464
485
  end
465
486
 
466
487
  # Division of two decimal numbers
467
488
  def divide(x,y)
468
- Decimal._convert(x).divide(y,self)
489
+ _convert(x).divide(y,self)
469
490
  end
470
491
 
471
492
  # Absolute value of a decimal number
472
493
  def abs(x)
473
- Decimal._convert(x).abs(self)
494
+ _convert(x).abs(self)
474
495
  end
475
496
 
476
497
  # Unary prefix plus operator
477
498
  def plus(x)
478
- Decimal._convert(x).plus(self)
499
+ _convert(x).plus(self)
479
500
  end
480
501
 
481
502
  # Unary prefix minus operator
482
503
  def minus(x)
483
- Decimal._convert(x)._neg(self)
504
+ _convert(x)._neg(self)
484
505
  end
485
506
 
486
507
  # Converts a number to a string
487
508
  def to_string(x, eng=false)
488
- Decimal._convert(x)._fix(self).to_s(eng, self)
509
+ _convert(x)._fix(self).to_s(eng, self)
489
510
  end
490
511
 
491
512
  # Converts a number to a string, using scientific notation
@@ -502,106 +523,125 @@ class Decimal
502
523
  # by removing trailing 0s and incrementing the exponent.
503
524
  # (formerly called normalize in GDAS)
504
525
  def reduce(x)
505
- Decimal._convert(x).reduce(self)
526
+ _convert(x).reduce(self)
506
527
  end
507
528
 
508
529
  # Adjusted exponent of x returned as a Decimal value.
509
530
  def logb(x)
510
- Decimal._convert(x).logb(self)
531
+ _convert(x).logb(self)
511
532
  end
512
533
 
513
534
  # Adds the second value to the exponent of the first: x*(radix**y)
514
535
  #
515
536
  # y must be an integer
516
537
  def scaleb(x, y)
517
- Decimal._convert(x).scaleb(y,self)
538
+ _convert(x).scaleb(y,self)
539
+ end
540
+
541
+ # Power. See Decimal#power()
542
+ def power(x,y,modulo=nil)
543
+ _convert(x).power(y,modulo,self)
544
+ end
545
+
546
+ # Returns the base 10 logarithm
547
+ def log10(x)
548
+ _convert(x).log10(self)
549
+ end
550
+
551
+ # Exponential function: e**x
552
+ def exp(x)
553
+ _convert(x).exp(self)
518
554
  end
519
555
 
556
+ # Returns the natural (base e) logarithm
557
+ def ln(x)
558
+ _convert(x).ln(self)
559
+ end
520
560
 
521
561
  # Exponent in relation to the significand as an integer
522
562
  # normalized to precision digits. (minimum exponent)
523
563
  def normalized_integral_exponent(x)
524
- x = Decimal._convert(x)
564
+ x = _convert(x)
525
565
  x.integral_exponent - (precision - x.number_of_digits)
526
566
  end
527
567
 
528
568
  # Significand normalized to precision digits
529
569
  # x == normalized_integral_significand(x) * radix**(normalized_integral_exponent)
530
570
  def normalized_integral_significand(x)
531
- x = Decimal._convert(x)
571
+ x = _convert(x)
532
572
  x.integral_significand*(Decimal.int_radix_power(precision - x.number_of_digits))
533
573
  end
534
574
 
535
575
  # Returns both the (signed) normalized integral significand and the corresponding exponent
536
576
  def to_normalized_int_scale(x)
537
- x = Decimal._convert(x)
577
+ x = _convert(x)
538
578
  [x.sign*normalized_integral_significand(x), normalized_integral_exponent(x)]
539
579
  end
540
580
 
541
581
  # Is a normal number?
542
582
  def normal?(x)
543
- Decimal._convert(x).normal?(self)
583
+ _convert(x).normal?(self)
544
584
  end
545
585
 
546
586
  # Is a subnormal number?
547
587
  def subnormal?(x)
548
- Decimal._convert(x).subnormal?(self)
588
+ _convert(x).subnormal?(self)
549
589
  end
550
590
 
551
591
  # Classifies a number as one of
552
592
  # 'sNaN', 'NaN', '-Infinity', '-Normal', '-Subnormal', '-Zero',
553
593
  # '+Zero', '+Subnormal', '+Normal', '+Infinity'
554
594
  def number_class(x)
555
- Decimal._convert(x).number_class(self)
595
+ _convert(x).number_class(self)
556
596
  end
557
597
 
558
598
  # Square root of a decimal number
559
599
  def sqrt(x)
560
- Decimal._convert(x).sqrt(self)
600
+ _convert(x).sqrt(self)
561
601
  end
562
602
 
563
603
  # Ruby-style integer division: (x/y).floor
564
604
  def div(x,y)
565
- Decimal._convert(x).div(y,self)
605
+ _convert(x).div(y,self)
566
606
  end
567
607
 
568
608
  # Ruby-style modulo: x - y*div(x,y)
569
609
  def modulo(x,y)
570
- Decimal._convert(x).modulo(y,self)
610
+ _convert(x).modulo(y,self)
571
611
  end
572
612
 
573
613
  # Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
574
614
  def divmod(x,y)
575
- Decimal._convert(x).divmod(y,self)
615
+ _convert(x).divmod(y,self)
576
616
  end
577
617
 
578
618
  # General Decimal Arithmetic Specification integer division: (x/y).truncate
579
619
  def divide_int(x,y)
580
- Decimal._convert(x).divide_int(y,self)
620
+ _convert(x).divide_int(y,self)
581
621
  end
582
622
 
583
623
  # General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
584
624
  def remainder(x,y)
585
- Decimal._convert(x).remainder(y,self)
625
+ _convert(x).remainder(y,self)
586
626
  end
587
627
 
588
628
  # General Decimal Arithmetic Specification remainder-near
589
629
  # x - y*round_half_even(x/y)
590
630
  def remainder_near(x,y)
591
- Decimal._convert(x).remainder_near(y,self)
631
+ _convert(x).remainder_near(y,self)
592
632
  end
593
633
 
594
634
  # General Decimal Arithmetic Specification integer division and remainder:
595
635
  # (x/y).truncate, x - y*(x/y).truncate
596
636
  def divrem(x,y)
597
- Decimal._convert(x).divrem(y,self)
637
+ _convert(x).divrem(y,self)
598
638
  end
599
639
 
600
640
  # Fused multiply-add.
601
641
  #
602
642
  # Computes (x*y+z) with no rounding of the intermediate product x*y.
603
643
  def fma(x,y,z)
604
- Decimal._convert(x).fma(y,z,self)
644
+ _convert(x).fma(y,z,self)
605
645
  end
606
646
 
607
647
  # Compares like <=> but returns a Decimal value.
@@ -610,33 +650,33 @@ class Decimal
610
650
  # * +1 if x > y
611
651
  # * NaN if x or y is NaN
612
652
  def compare(x,y)
613
- Decimal._convert(x).compare(y, self)
653
+ _convert(x).compare(y, self)
614
654
  end
615
655
 
616
656
  # Returns a copy of x with the sign set to +
617
657
  def copy_abs(x)
618
- Decimal._convert(x).copy_abs
658
+ _convert(x).copy_abs
619
659
  end
620
660
 
621
661
  # Returns a copy of x with the sign inverted
622
662
  def copy_negate(x)
623
- Decimal._convert(x).copy_negate
663
+ _convert(x).copy_negate
624
664
  end
625
665
 
626
666
  # Returns a copy of x with the sign of y
627
667
  def copy_sign(x,y)
628
- Decimal._convert(x).copy_sign(y)
668
+ _convert(x).copy_sign(y)
629
669
  end
630
670
 
631
671
  # Rescale x so that the exponent is exp, either by padding with zeros
632
672
  # or by truncating digits.
633
673
  def rescale(x, exp, watch_exp=true)
634
- Decimal._convert(x).rescale(exp, self, watch_exp)
674
+ _convert(x).rescale(exp, self, watch_exp)
635
675
  end
636
676
 
637
677
  # Quantize x so its exponent is the same as that of y.
638
678
  def quantize(x, y, watch_exp=true)
639
- Decimal._convert(x).quantize(y, self, watch_exp)
679
+ _convert(x).quantize(y, self, watch_exp)
640
680
  end
641
681
 
642
682
  # Return true if x and y have the same exponent.
@@ -646,7 +686,7 @@ class Decimal
646
686
  # * return true if both operands are NaNs
647
687
  # * otherwise, return false.
648
688
  def same_quantum?(x,y)
649
- Decimal._convert(x).same_quantum?(y)
689
+ _convert(x).same_quantum?(y)
650
690
  end
651
691
 
652
692
  # Rounds to a nearby integer.
@@ -654,7 +694,7 @@ class Decimal
654
694
  # See also: Decimal#to_integral_value(), which does exactly the same as
655
695
  # this method except that it doesn't raise Inexact or Rounded.
656
696
  def to_integral_exact(x)
657
- Decimal._convert(x).to_integral_exact(self)
697
+ _convert(x).to_integral_exact(self)
658
698
  end
659
699
 
660
700
  # Rounds to a nearby integerwithout raising inexact, rounded.
@@ -662,17 +702,17 @@ class Decimal
662
702
  # See also: Decimal#to_integral_exact(), which does exactly the same as
663
703
  # this method except that it may raise Inexact or Rounded.
664
704
  def to_integral_value(x)
665
- Decimal._convert(x).to_integral_value(self)
705
+ _convert(x).to_integral_value(self)
666
706
  end
667
707
 
668
708
  # Returns the largest representable number smaller than x.
669
709
  def next_minus(x)
670
- Decimal._convert(x).next_minus(self)
710
+ _convert(x).next_minus(self)
671
711
  end
672
712
 
673
713
  # Returns the smallest representable number larger than x.
674
714
  def next_plus(x)
675
- Decimal._convert(x).next_plus(self)
715
+ _convert(x).next_plus(self)
676
716
  end
677
717
 
678
718
  # Returns the number closest to x, in the direction towards y.
@@ -683,7 +723,7 @@ class Decimal
683
723
  # numerically equal, then the result is a copy of x with the
684
724
  # sign set to be the same as the sign of y.
685
725
  def next_toward(x, y)
686
- Decimal._convert(x).next_toward(y, self)
726
+ _convert(x).next_toward(y, self)
687
727
  end
688
728
 
689
729
  def to_s
@@ -763,6 +803,11 @@ class Decimal
763
803
  end
764
804
 
765
805
  private
806
+
807
+ def _convert(x)
808
+ AuxiliarFunctions._convert(x)
809
+ end
810
+
766
811
  def update_precision
767
812
  if @exact || @precision==0
768
813
  @exact = true
@@ -874,6 +919,13 @@ class Decimal
874
919
  keep = context.dup
875
920
  Decimal.context = define_context(*args)
876
921
  result = yield Decimal.context
922
+ # TODO: consider the convenience of copying the flags from Decimal.context to keep
923
+ # This way a local context does not affect the settings of the previous context,
924
+ # but flags are transferred.
925
+ # (this could be done always or be controlled by some option)
926
+ # keep.flags = Decimal.context.flags
927
+ # Another alternative to consider: logically or the flags:
928
+ # keep.flags ||= Decimal.context.flags # (this requires implementing || in Flags)
877
929
  Decimal.context = keep
878
930
  result
879
931
  end
@@ -958,7 +1010,7 @@ class Decimal
958
1010
  # and the left hand is another numeric type
959
1011
  # * Decimal#_bin_op() used internally to define binary operators and use the Ruby coerce protocol:
960
1012
  # if the right-hand operand is of known type it is converted with Decimal; otherwise use coerce
961
- # * Decimal._convert() converts known types to Decimal with Decimal() or raises an exception.
1013
+ # * _convert() converts known types to Decimal with Decimal() or raises an exception.
962
1014
  # * Decimal() casts known types and text representations of numbers to Decimal using the constructor.
963
1015
  # * Decimal#initialize performs the actual type conversion
964
1016
  #
@@ -1212,11 +1264,16 @@ class Decimal
1212
1264
  _bin_op :%, :modulo, other, context
1213
1265
  end
1214
1266
 
1267
+ # Power
1268
+ def **(other, context=nil)
1269
+ _bin_op :**, :power, other, context
1270
+ end
1271
+
1215
1272
  # Addition
1216
1273
  def add(other, context=nil)
1217
1274
 
1218
1275
  context = Decimal.define_context(context)
1219
- other = Decimal._convert(other)
1276
+ other = _convert(other)
1220
1277
 
1221
1278
  if self.special? || other.special?
1222
1279
  ans = _check_nans(context,other)
@@ -1252,7 +1309,7 @@ class Decimal
1252
1309
  return self._rescale(exp, context.rounding)._fix(context)
1253
1310
  end
1254
1311
 
1255
- op1, op2 = Decimal._normalize(self, other, context.precision)
1312
+ op1, op2 = _normalize(self, other, context.precision)
1256
1313
 
1257
1314
  result_sign = result_coeff = result_exp = nil
1258
1315
  if op1.sign != op2.sign
@@ -1267,9 +1324,6 @@ class Decimal
1267
1324
  result_sign = +1
1268
1325
  end
1269
1326
 
1270
- #puts "op1=#{op1.inspect} op2=#{op2.inspect}"
1271
-
1272
-
1273
1327
  if op2.sign == +1
1274
1328
  result_coeff = op1.integral_significand + op2.integral_significand
1275
1329
  else
@@ -1278,8 +1332,6 @@ class Decimal
1278
1332
 
1279
1333
  result_exp = op1.integral_exponent
1280
1334
 
1281
- #puts "->#{Decimal([result_sign, result_coeff, result_exp]).inspect}"
1282
-
1283
1335
  return Decimal([result_sign, result_coeff, result_exp])._fix(context)
1284
1336
 
1285
1337
  end
@@ -1289,7 +1341,7 @@ class Decimal
1289
1341
  def subtract(other, context=nil)
1290
1342
 
1291
1343
  context = Decimal.define_context(context)
1292
- other = Decimal._convert(other)
1344
+ other = _convert(other)
1293
1345
 
1294
1346
  if self.special? || other.special?
1295
1347
  ans = _check_nans(context,other)
@@ -1301,7 +1353,7 @@ class Decimal
1301
1353
  # Multiplication
1302
1354
  def multiply(other, context=nil)
1303
1355
  context = Decimal.define_context(context)
1304
- other = Decimal._convert(other)
1356
+ other = _convert(other)
1305
1357
  resultsign = self.sign * other.sign
1306
1358
  if self.special? || other.special?
1307
1359
  ans = _check_nans(context,other)
@@ -1330,7 +1382,7 @@ class Decimal
1330
1382
  # Division
1331
1383
  def divide(other, context=nil)
1332
1384
  context = Decimal.define_context(context)
1333
- other = Decimal._convert(other)
1385
+ other = _convert(other)
1334
1386
  resultsign = self.sign * other.sign
1335
1387
  if self.special? || other.special?
1336
1388
  ans = _check_nans(context,other)
@@ -1414,6 +1466,8 @@ class Decimal
1414
1466
  end
1415
1467
  end
1416
1468
 
1469
+ return context.exception(InvalidOperation, 'Exact next minus') if context.exact?
1470
+
1417
1471
  result = nil
1418
1472
  Decimal.local_context(context) do |local|
1419
1473
  local.rounding = :floor
@@ -1429,6 +1483,7 @@ class Decimal
1429
1483
  # Smallest representable number larger than itself
1430
1484
  def next_plus(context=nil)
1431
1485
  context = Decimal.define_context(context)
1486
+
1432
1487
  if special?
1433
1488
  ans = _check_nans(context)
1434
1489
  return ans if ans
@@ -1443,6 +1498,8 @@ class Decimal
1443
1498
  end
1444
1499
  end
1445
1500
 
1501
+ return context.exception(InvalidOperation, 'Exact next plus') if context.exact?
1502
+
1446
1503
  result = nil
1447
1504
  Decimal.local_context(context) do |local|
1448
1505
  local.rounding = :ceiling
@@ -1459,10 +1516,12 @@ class Decimal
1459
1516
  # Returns the number closest to self, in the direction towards other.
1460
1517
  def next_toward(other, context=nil)
1461
1518
  context = Decimal.define_context(context)
1462
- other = Decimal._convert(other)
1519
+ other = _convert(other)
1463
1520
  ans = _check_nans(context,other)
1464
1521
  return ans if ans
1465
1522
 
1523
+ return context.exception(InvalidOperation, 'Exact next_toward') if context.exact?
1524
+
1466
1525
  comparison = self <=> other
1467
1526
  return self.copy_sign(other) if comparison == 0
1468
1527
 
@@ -1549,7 +1608,7 @@ class Decimal
1549
1608
  # (x/y).truncate, x - y*(x/y).truncate
1550
1609
  def divrem(other, context=nil)
1551
1610
  context = Decimal.define_context(context)
1552
- other = Decimal._convert(other)
1611
+ other = _convert(other)
1553
1612
 
1554
1613
  ans = _check_nans(context,other)
1555
1614
  return [ans,ans] if ans
@@ -1582,7 +1641,7 @@ class Decimal
1582
1641
  # Ruby-style integer division and modulo: (x/y).floor, x - y*(x/y).floor
1583
1642
  def divmod(other, context=nil)
1584
1643
  context = Decimal.define_context(context)
1585
- other = Decimal._convert(other)
1644
+ other = _convert(other)
1586
1645
 
1587
1646
  ans = _check_nans(context,other)
1588
1647
  return [ans,ans] if ans
@@ -1616,7 +1675,7 @@ class Decimal
1616
1675
  # General Decimal Arithmetic Specification integer division: (x/y).truncate
1617
1676
  def divide_int(other, context=nil)
1618
1677
  context = Decimal.define_context(context)
1619
- other = Decimal._convert(other)
1678
+ other = _convert(other)
1620
1679
 
1621
1680
  ans = _check_nans(context,other)
1622
1681
  return ans if ans
@@ -1641,7 +1700,7 @@ class Decimal
1641
1700
  # Ruby-style integer division: (x/y).floor
1642
1701
  def div(other, context=nil)
1643
1702
  context = Decimal.define_context(context)
1644
- other = Decimal._convert(other)
1703
+ other = _convert(other)
1645
1704
 
1646
1705
  ans = _check_nans(context,other)
1647
1706
  return [ans,ans] if ans
@@ -1667,7 +1726,7 @@ class Decimal
1667
1726
  # Ruby-style modulo: x - y*div(x,y)
1668
1727
  def modulo(other, context=nil)
1669
1728
  context = Decimal.define_context(context)
1670
- other = Decimal._convert(other)
1729
+ other = _convert(other)
1671
1730
 
1672
1731
  ans = _check_nans(context,other)
1673
1732
  return ans if ans
@@ -1690,7 +1749,7 @@ class Decimal
1690
1749
  # General Decimal Arithmetic Specification remainder: x - y*divide_int(x,y)
1691
1750
  def remainder(other, context=nil)
1692
1751
  context = Decimal.define_context(context)
1693
- other = Decimal._convert(other)
1752
+ other = _convert(other)
1694
1753
 
1695
1754
  ans = _check_nans(context,other)
1696
1755
  return ans if ans
@@ -1714,7 +1773,7 @@ class Decimal
1714
1773
  # x - y*round_half_even(x/y)
1715
1774
  def remainder_near(other, context=nil)
1716
1775
  context = Decimal.define_context(context)
1717
- other = Decimal._convert(other)
1776
+ other = _convert(other)
1718
1777
 
1719
1778
  ans = _check_nans(context,other)
1720
1779
  return ans if ans
@@ -1819,7 +1878,7 @@ class Decimal
1819
1878
  def scaleb(other, context=nil)
1820
1879
 
1821
1880
  context = Decimal.define_context(context)
1822
- other = Decimal._convert(other)
1881
+ other = _convert(other)
1823
1882
  ans = _check_nans(context, other)
1824
1883
  return ans if ans
1825
1884
  return context.exception(InvalidOperation) if other.infinite? || other.integral_exponent != 0
@@ -1843,7 +1902,11 @@ class Decimal
1843
1902
  # Ruby-style to integer conversion.
1844
1903
  def to_i
1845
1904
  if special?
1846
- return nil if nan?
1905
+ if nan?
1906
+ #return Decimal.context.exception(InvalidContext)
1907
+ Decimal.context.exception InvalidContext
1908
+ return nil
1909
+ end
1847
1910
  raise Error, "Cannot convert infinity to Integer"
1848
1911
  end
1849
1912
  if @exp >= 0
@@ -2011,7 +2074,7 @@ class Decimal
2011
2074
  # Compares like <=> but returns a Decimal value.
2012
2075
  def compare(other, context=nil)
2013
2076
 
2014
- other = Decimal._convert(other)
2077
+ other = _convert(other)
2015
2078
 
2016
2079
  if self.special? || other.special?
2017
2080
  ans = _check_nans(context, other)
@@ -2052,14 +2115,15 @@ class Decimal
2052
2115
  @coeff.to_s.size
2053
2116
  end
2054
2117
 
2055
- # Significand as an integer
2118
+ # Significand as an integer, unsigned
2056
2119
  def integral_significand
2057
2120
  @coeff
2058
2121
  end
2059
2122
 
2060
2123
  # Exponent of the significand as an integer
2061
2124
  def integral_exponent
2062
- fractional_exponent - number_of_digits
2125
+ # fractional_exponent - number_of_digits
2126
+ @exp
2063
2127
  end
2064
2128
 
2065
2129
  # Sign of the number: +1 for plus / -1 for minus.
@@ -2076,262 +2140,635 @@ class Decimal
2076
2140
  end
2077
2141
  end
2078
2142
 
2079
- # Returns copy with sign inverted
2080
- def _neg(context=nil)
2081
- if special?
2082
- ans = _check_nans(context)
2083
- return ans if ans
2084
- end
2085
- if zero?
2086
- ans = copy_abs
2087
- else
2088
- ans = copy_negate
2089
- end
2090
- context = Decimal.define_context(context)
2091
- ans._fix(context)
2143
+ # Returns a copy of with the sign set to +
2144
+ def copy_abs
2145
+ Decimal.new([+1,@coeff,@exp])
2092
2146
  end
2093
2147
 
2094
- # Returns a copy with precision adjusted
2095
- def _pos(context=nil)
2096
- if special?
2097
- ans = _check_nans(context)
2098
- return ans if ans
2099
- end
2100
- if zero?
2101
- ans = copy_abs
2102
- else
2103
- ans = Decimal.new(self)
2104
- end
2105
- context = Decimal.define_context(context)
2106
- ans._fix(context)
2148
+ # Returns a copy of with the sign inverted
2149
+ def copy_negate
2150
+ Decimal.new([-@sign,@coeff,@exp])
2107
2151
  end
2108
2152
 
2109
- # Returns a copy with positive sign
2110
- def _abs(round=true, context=nil)
2111
- return copy_abs if not round
2112
-
2113
- if special?
2114
- ans = _check_nans(context)
2115
- return ans if ans
2116
- end
2117
- if sign>0
2118
- ans = _neg(context)
2119
- else
2120
- ans = _pos(context)
2121
- end
2122
- ans
2153
+ # Returns a copy of with the sign of other
2154
+ def copy_sign(other)
2155
+ Decimal.new([other.sign, @coeff, @exp])
2123
2156
  end
2124
2157
 
2125
- # Round if it is necessary to keep within precision.
2126
- def _fix(context)
2127
- return self if context.exact?
2128
-
2129
- if special?
2130
- if nan?
2131
- return _fix_nan(context)
2158
+ # Returns true if the value is an integer
2159
+ def integral?
2160
+ if finite?
2161
+ if @exp>=0 || @coeff==0
2162
+ true
2132
2163
  else
2133
- return Decimal.new(self)
2164
+ if @exp <= -number_of_digits
2165
+ false
2166
+ else
2167
+ m = Decimal.int_radix_power(-@exp)
2168
+ (@coeff % m) == 0
2169
+ end
2134
2170
  end
2171
+ else
2172
+ false
2135
2173
  end
2174
+ end
2136
2175
 
2137
- etiny = context.etiny
2138
- etop = context.etop
2139
- if zero?
2140
- exp_max = context.clamp? ? etop : context.emax
2141
- new_exp = [[@exp, etiny].max, exp_max].min
2142
- if new_exp!=@exp
2143
- context.exception Clamped
2144
- return Decimal.new([sign,0,new_exp])
2176
+ # returns true if is an even integer
2177
+ def even?
2178
+ # integral? && ((to_i%2)==0)
2179
+ if finite?
2180
+ if @exp>0 || @coeff==0
2181
+ true
2145
2182
  else
2146
- return Decimal.new(self)
2183
+ if @exp <= -number_of_digits
2184
+ false
2185
+ else
2186
+ m = Decimal.int_radix_power(-@exp)
2187
+ if (@coeff % m) == 0
2188
+ # ((@coeff / m) % 2) == 0
2189
+ ((@coeff / m) & 1) == 0
2190
+ else
2191
+ false
2192
+ end
2193
+ end
2147
2194
  end
2195
+ else
2196
+ false
2148
2197
  end
2198
+ end
2149
2199
 
2150
- nd = number_of_digits
2151
- exp_min = nd + @exp - context.precision
2152
- if exp_min > etop
2153
- context.exception Inexact
2154
- context.exception Rounded
2155
- return context.exception(Overflow, 'above Emax', sign)
2156
- end
2157
-
2158
- self_is_subnormal = exp_min < etiny
2159
-
2160
- if self_is_subnormal
2161
- context.exception Subnormal
2162
- exp_min = etiny
2163
- end
2164
-
2165
- if @exp < exp_min
2166
- #puts "_fix(#{self}) rounded; e=#{@exp} em=#{exp_min}"
2167
- context.exception Rounded
2168
- # dig is the digits number from 0 (MS) to number_of_digits-1 (LS)
2169
- # dg = numberof_digits-dig is from 1 (LS) to number_of_digits (MS)
2170
- dg = exp_min - @exp # dig = number_of_digits + exp - exp_min
2171
- if dg > number_of_digits # dig<0
2172
- d = Decimal.new([sign,1,exp_min-1])
2173
- dg = number_of_digits # dig = 0
2200
+ # returns true if is an odd integer
2201
+ def odd?
2202
+ # integral? && ((to_i%2)==1)
2203
+ # integral? && !even?
2204
+ if finite?
2205
+ if @exp>0 || @coeff==0
2206
+ false
2174
2207
  else
2175
- d = Decimal.new(self)
2176
- end
2177
- changed = d._round(context.rounding, dg)
2178
- coeff = Decimal.int_div_radix_power(d.integral_significand, dg)
2179
- coeff += 1 if changed==1
2180
- ans = Decimal.new([sign, coeff, exp_min])
2181
- if changed!=0
2182
- context.exception Inexact
2183
- if self_is_subnormal
2184
- context.exception Underflow
2185
- if ans.zero?
2186
- context.exception Clamped
2187
- end
2188
- elsif ans.number_of_digits == context.precision+1
2189
- if ans.integral_exponent< etop
2190
- ans = Decimal.new([ans.sign, Decimal.int_div_radix_power(ans.integral_significand,1), ans.integral_exponent+1])
2208
+ if @exp <= -number_of_digits
2209
+ false
2210
+ else
2211
+ m = Decimal.int_radix_power(-@exp)
2212
+ if (@coeff % m) == 0
2213
+ # ((@coeff / m) % 2) == 1
2214
+ ((@coeff / m) & 1) == 1
2191
2215
  else
2192
- ans = context.exception(Overflow, 'above Emax', d.sign)
2216
+ false
2193
2217
  end
2194
2218
  end
2195
2219
  end
2196
- return ans
2220
+ else
2221
+ false
2197
2222
  end
2223
+ end
2198
2224
 
2199
- if context.clamp? && @exp>etop
2200
- context.exception Clamped
2201
- self_padded = Decimal.int_mult_radix_power(@coeff, @exp-etop)
2202
- return Decimal.new([sign,self_padded,etop])
2225
+ # Rescale so that the exponent is exp, either by padding with zeros
2226
+ # or by truncating digits.
2227
+ def rescale(exp, context=nil, watch_exp=true)
2228
+ context = Decimal.define_context(context)
2229
+ exp = _convert(exp)
2230
+ if self.special? || exp.special?
2231
+ ans = _check_nans(context, exp)
2232
+ return ans if ans
2233
+ if exp.infinite? || self.infinite?
2234
+ return Decimal.new(self) if exp.infinite? && self.infinite?
2235
+ return context.exception(InvalidOperation, 'rescale with one INF')
2236
+ end
2203
2237
  end
2204
-
2205
- return Decimal.new(self)
2206
-
2238
+ return context.exception(InvalidOperation,"exponent of rescale is not integral") unless exp.integral?
2239
+ exp = exp.to_i
2240
+ _watched_rescale(exp, context, watch_exp)
2207
2241
  end
2208
2242
 
2243
+ # Quantize so its exponent is the same as that of y.
2244
+ def quantize(exp, context=nil, watch_exp=true)
2245
+ exp = _convert(exp)
2246
+ context = Decimal.define_context(context)
2247
+ if self.special? || exp.special?
2248
+ ans = _check_nans(context, exp)
2249
+ return ans if ans
2250
+ if exp.infinite? || self.infinite?
2251
+ return Decimal.new(self) if exp.infinite? && self.infinite?
2252
+ return context.exception(InvalidOperation, 'quantize with one INF')
2253
+ end
2254
+ end
2255
+ exp = exp.integral_exponent
2256
+ _watched_rescale(exp, context, watch_exp)
2257
+ end
2209
2258
 
2210
- ROUND_ARITHMETIC = true
2211
-
2212
- # Round to i digits using the specified method
2213
- def _round(rounding, i)
2214
- send("_round_#{rounding}", i)
2259
+ # Return true if has the same exponent as other.
2260
+ #
2261
+ # If either operand is a special value, the following rules are used:
2262
+ # * return true if both operands are infinities
2263
+ # * return true if both operands are NaNs
2264
+ # * otherwise, return false.
2265
+ def same_quantum?(other)
2266
+ other = _convert(other)
2267
+ if self.special? || other.special?
2268
+ return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
2269
+ end
2270
+ return self.integral_exponent == other.integral_exponent
2215
2271
  end
2216
2272
 
2217
- # Round down (toward 0, truncate) to i digits
2218
- def _round_down(i)
2219
- if ROUND_ARITHMETIC
2220
- (@coeff % Decimal.int_radix_power(i))==0 ? 0 : -1
2221
- else
2222
- d = @coeff.to_s
2223
- p = d.size - i
2224
- d[p..-1].match(/\A0+\Z/) ? 0 : -1
2273
+ # Rounds to a nearby integer. May raise Inexact or Rounded.
2274
+ def to_integral_exact(context=nil)
2275
+ context = Decimal.define_context(context)
2276
+ if special?
2277
+ ans = _check_nans(context)
2278
+ return ans if ans
2279
+ return Decimal.new(self)
2225
2280
  end
2281
+ return Decimal.new(self) if @exp >= 0
2282
+ return Decimal.new([@sign, 0, 0]) if zero?
2283
+ context.exception Rounded
2284
+ ans = _rescale(0, context.rounding)
2285
+ context.exception Inexact if ans != self
2286
+ return ans
2226
2287
  end
2227
2288
 
2228
- # Round up (away from 0) to i digits
2229
- def _round_up(i)
2230
- -_round_down(i)
2289
+ # Rounds to a nearby integer. Doesn't raise Inexact or Rounded.
2290
+ def to_integral_value(context=nil)
2291
+ context = Decimal.define_context(context)
2292
+ if special?
2293
+ ans = _check_nans(context)
2294
+ return ans if ans
2295
+ return Decimal.new(self)
2296
+ end
2297
+ return Decimal.new(self) if @exp >= 0
2298
+ return _rescale(0, context.rounding)
2231
2299
  end
2232
2300
 
2233
- # Round to closest i-digit number with ties down (rounds 5 toward 0)
2234
- def _round_half_down(i)
2235
- if ROUND_ARITHMETIC
2236
- m = Decimal.int_radix_power(i)
2237
- if (m>1) && ((@coeff%m) == m/2)
2238
- -1
2239
- else
2240
- _round_half_up(i)
2241
- end
2301
+ # General rounding.
2302
+ #
2303
+ # With an integer argument this acts like Float#round: the parameter specifies the number
2304
+ # of fractional digits (or digits to the left of the decimal point if negative).
2305
+ #
2306
+ # Options can be passed as a Hash instead; valid options are:
2307
+ # * :rounding method for rounding (see Context#new())
2308
+ # The precision can be specified as:
2309
+ # * :places number of fractional digits as above.
2310
+ # * :exponent specifies the exponent corresponding to the
2311
+ # digit to be rounded (exponent == -places)
2312
+ # * :precision or :significan_digits is the number of digits
2313
+ # * :power 10^exponent, value of the digit to be rounded,
2314
+ # should be passed as a type convertible to Decimal.
2315
+ # * :index 0-based index of the digit to be rounded
2316
+ # * :rindex right 0-based index of the digit to be rounded
2317
+ #
2318
+ # The default is :places=>0 (round to integer).
2319
+ #
2320
+ # Example: ways of specifiying the rounding position
2321
+ # number: 1 2 3 4 . 5 6 7 8
2322
+ # :places -3 -2 -1 0 1 2 3 4
2323
+ # :exponent 3 2 1 0 -1 -2 -3 -4
2324
+ # :precision 1 2 3 4 5 6 7 8
2325
+ # :power 1E3 1E2 10 1 0.1 1E-2 1E-3 1E-4
2326
+ # :index 0 1 2 3 4 5 6 7
2327
+ # :index 7 6 5 4 3 2 1 0
2328
+ def round(opt={})
2329
+ opt = { :places=>opt } if opt.kind_of?(Integer)
2330
+ r = opt[:rounding] || :half_up
2331
+ as_int = false
2332
+ if v=(opt[:precision] || opt[:significant_digits])
2333
+ prec = v
2334
+ elsif v=(opt[:places])
2335
+ prec = adjusted_exponent + 1 + v
2336
+ elsif v=(opt[:exponent])
2337
+ prec = adjusted_exponent + 1 - v
2338
+ elsif v=(opt[:power])
2339
+ prec = adjusted_exponent + 1 - Decimal(v).adjusted_exponent
2340
+ elsif v=(opt[:index])
2341
+ prec = i+1
2342
+ elsif v=(opt[:rindex])
2343
+ prec = number_of_digits - v
2242
2344
  else
2243
- d = @coeff.to_s
2244
- p = d.size - i
2245
- d[p..-1].match(/^5d*$/) ? -1 : _round_half_up(i)
2345
+ prec = adjusted_exponent + 1
2346
+ as_int = true
2246
2347
  end
2348
+ result = plus(:rounding=>r, :precision=>prec)
2349
+ return as_int ? result.to_i : result
2350
+ end
2247
2351
 
2352
+ # General ceiling operation (as for Float) with same options for precision
2353
+ # as Decimal#round()
2354
+ def ceil(opt={})
2355
+ opt[:rounding] = :ceiling
2356
+ round opt
2248
2357
  end
2249
2358
 
2250
- # Round to closest i-digit number with ties up (rounds 5 away from 0)
2251
- def _round_half_up(i)
2252
- if ROUND_ARITHMETIC
2253
- m = Decimal.int_radix_power(i)
2254
- if (m>1) && ((@coeff%m) >= m/2)
2255
- 1
2256
- else
2257
- (@coeff % m)==0 ? 0 : -1
2359
+ # General floor operation (as for Float) with same options for precision
2360
+ # as Decimal#round()
2361
+ def floor(opt={})
2362
+ opt[:rounding] = :floor
2363
+ round opt
2364
+ end
2365
+
2366
+ # General truncate operation (as for Float) with same options for precision
2367
+ # as Decimal#round()
2368
+ def truncate(opt={})
2369
+ opt[:rounding] = :down
2370
+ round opt
2371
+ end
2372
+
2373
+ # Fused multiply-add.
2374
+ #
2375
+ # Computes (self*other+third) with no rounding of the intermediate product self*other.
2376
+ def fma(other, third, context=nil)
2377
+ context = Decimal.define_context(context)
2378
+ other = _convert(other)
2379
+ third = _convert(third)
2380
+ if self.special? || other.special?
2381
+ return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
2382
+ return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
2383
+ if self.nan?
2384
+ product = self
2385
+ elsif other.nan?
2386
+ product = other
2387
+ elsif self.infinite?
2388
+ return context.exception(InvalidOperation, 'INF * 0 in fma') if other.zero?
2389
+ product = Decimal.infinity(self.sign*other.sign)
2390
+ elsif other.infinite?
2391
+ return context.exception(InvalidOperation, '0 * INF in fma') if self.zero?
2392
+ product = Decimal.infinity(self.sign*other.sign)
2258
2393
  end
2259
2394
  else
2260
- d = @coeff.to_s
2261
- p = d.size - i
2262
- if '56789'.include?(d[p,1])
2263
- 1
2395
+ product = Decimal.new([self.sign*other.sign,self.integral_significand*other.integral_significand, self.integral_exponent+other.integral_exponent])
2396
+ end
2397
+ return product.add(third, context)
2398
+ end
2399
+
2400
+ # Raises to the power of x, to modulo if given.
2401
+ #
2402
+ # With two arguments, compute self**other. If self is negative then other
2403
+ # must be integral. The result will be inexact unless other is
2404
+ # integral and the result is finite and can be expressed exactly
2405
+ # in 'precision' digits.
2406
+ #
2407
+ # With three arguments, compute (self**other) % modulo. For the
2408
+ # three argument form, the following restrictions on the
2409
+ # arguments hold:
2410
+ #
2411
+ # - all three arguments must be integral
2412
+ # - other must be nonnegative
2413
+ # - at least one of self or other must be nonzero
2414
+ # - modulo must be nonzero and have at most 'precision' digits
2415
+ #
2416
+ # The result of a.power(b, modulo) is identical to the result
2417
+ # that would be obtained by computing (a**b) % modulo with
2418
+ # unbounded precision, but is computed more efficiently. It is
2419
+ # always exact.
2420
+ def power(other, modulo=nil, context=nil)
2421
+
2422
+ if context.nil? && (modulo.is_a?(Context) || modulo.is_a?(Hash))
2423
+ context = modulo
2424
+ modulo = nil
2425
+ end
2426
+
2427
+ return self.power_modulo(other, modulo, context) if modulo
2428
+
2429
+ context = Decimal.define_context(context)
2430
+ other = _convert(other)
2431
+
2432
+ ans = _check_nans(context, other)
2433
+ return ans if ans
2434
+
2435
+ # 0**0 = NaN (!), x**0 = 1 for nonzero x (including +/-Infinity)
2436
+ if other.zero?
2437
+ if self.zero?
2438
+ return context.exception(InvalidOperation, '0 ** 0')
2264
2439
  else
2265
- d[p..-1].match(/^0+$/) ? 0 : -1
2440
+ return Decimal(1)
2266
2441
  end
2267
2442
  end
2268
2443
 
2269
- end
2444
+ # result has sign -1 iff self.sign is -1 and other is an odd integer
2445
+ result_sign = +1
2446
+ _self = self
2447
+ if _self.sign == -1
2448
+ if other.integral?
2449
+ result_sign = -1 if !other.even?
2450
+ else
2451
+ # -ve**noninteger = NaN
2452
+ # (-0)**noninteger = 0**noninteger
2453
+ unless self.zero?
2454
+ return context.exception(InvalidOperation, 'x ** y with x negative and y not an integer')
2455
+ end
2456
+ end
2457
+ # negate self, without doing any unwanted rounding
2458
+ _self = self.copy_negate
2459
+ end
2460
+
2461
+ # 0**(+ve or Inf)= 0; 0**(-ve or -Inf) = Infinity
2462
+ if _self.zero?
2463
+ return (other.sign == +1) ? Decimal(result_sign, 0, 0) : Decimal.infinity(result_sign)
2464
+ end
2465
+
2466
+ # Inf**(+ve or Inf) = Inf; Inf**(-ve or -Inf) = 0
2467
+ if _self.infinite?
2468
+ return (other.sign == +1) ? Decimal.infinity(result_sign) : Decimal(result_sign, 0, 0)
2469
+ end
2470
+
2471
+ # 1**other = 1, but the choice of exponent and the flags
2472
+ # depend on the exponent of self, and on whether other is a
2473
+ # positive integer, a negative integer, or neither
2474
+ if _self == Decimal(1)
2475
+ return _self if context.exact?
2476
+ if other.integral?
2477
+ # exp = max(self._exp*max(int(other), 0),
2478
+ # 1-context.prec) but evaluating int(other) directly
2479
+ # is dangerous until we know other is small (other
2480
+ # could be 1e999999999)
2481
+ if other.sign == -1
2482
+ multiplier = 0
2483
+ elsif other > context.precision
2484
+ multiplier = context.precision
2485
+ else
2486
+ multiplier = other.to_i
2487
+ end
2270
2488
 
2271
- # Round to closest i-digit number with ties (5) to an even digit
2272
- def _round_half_even(i)
2273
- if ROUND_ARITHMETIC
2274
- m = Decimal.int_radix_power(i)
2275
- if (m>1) && ((@coeff%m) == m/2 && ((@coeff/m)%2)==0)
2276
- -1
2489
+ exp = _self.integral_exponent * multiplier
2490
+ if exp < 1-context.precision
2491
+ exp = 1-context.precision
2492
+ context.exception Rounded
2493
+ end
2277
2494
  else
2278
- _round_half_up(i)
2495
+ context.exception Rounded
2496
+ context.exception Inexact
2497
+ exp = 1-context.precision
2498
+ end
2499
+
2500
+ return Decimal(result_sign, Decimal.int_radix_power(-exp), exp)
2501
+ end
2502
+
2503
+ # compute adjusted exponent of self
2504
+ self_adj = _self.adjusted_exponent
2505
+
2506
+ # self ** infinity is infinity if self > 1, 0 if self < 1
2507
+ # self ** -infinity is infinity if self < 1, 0 if self > 1
2508
+ if other.infinite?
2509
+ if (other.sign == +1) == (self_adj < 0)
2510
+ return Decimal(result_sign, 0, 0)
2511
+ else
2512
+ return Decimal.infinity(result_sign)
2513
+ end
2514
+ end
2515
+
2516
+ # from here on, the result always goes through the call
2517
+ # to _fix at the end of this function.
2518
+ ans = nil
2519
+
2520
+ # crude test to catch cases of extreme overflow/underflow. If
2521
+ # log10(self)*other >= 10**bound and bound >= len(str(Emax))
2522
+ # then 10**bound >= 10**len(str(Emax)) >= Emax+1 and hence
2523
+ # self**other >= 10**(Emax+1), so overflow occurs. The test
2524
+ # for underflow is similar.
2525
+ bound = _self._log10_exp_bound + other.adjusted_exponent
2526
+ if (self_adj >= 0) == (other.sign == +1)
2527
+ # self > 1 and other +ve, or self < 1 and other -ve
2528
+ # possibility of overflow
2529
+ if bound >= context.emax.to_s.length
2530
+ ans = Decimal(result_sign, 1, context.emax+1)
2279
2531
  end
2280
2532
  else
2281
- d = @coeff.to_s
2282
- p = d.size - i
2533
+ # self > 1 and other -ve, or self < 1 and other +ve
2534
+ # possibility of underflow to 0
2535
+ etiny = context.etiny
2536
+ if bound >= (-etiny).to_s.length
2537
+ ans = Decimal(result_sign, 1, etiny-1)
2538
+ end
2539
+ end
2283
2540
 
2284
- if d[p..-1].match(/\A#{radix/2}0*\Z/) && (p==0 || ((d[p-1,1].to_i%2)==0))
2285
- -1
2541
+ # try for an exact result with precision +1
2542
+ if ans.nil?
2543
+ if context.exact?
2544
+ if other.adjusted_exponent < 100
2545
+ test_precision = _self.number_of_digits*other.to_i+1
2546
+ else
2547
+ test_precision = _self.number_of_digits+1
2548
+ end
2286
2549
  else
2287
- _round_half_up(i)
2550
+ test_precision = context.precision + 1
2288
2551
  end
2552
+ ans = _self._power_exact(other, test_precision)
2553
+ if !ans.nil? && (result_sign == -1)
2554
+ ans = Decimal(-1, ans.integral_significand, ans.integral_exponent)
2555
+ end
2556
+ end
2289
2557
 
2558
+ # usual case: inexact result, x**y computed directly as exp(y*log(x))
2559
+ if !ans.nil?
2560
+ return ans if context.exact?
2561
+ else
2562
+ return context.exception(Inexact, "Inexact power") if context.exact?
2563
+
2564
+ p = context.precision
2565
+ xc = _self.integral_significand
2566
+ xe = _self.integral_exponent
2567
+ yc = other.integral_significand
2568
+ ye = other.integral_exponent
2569
+ yc = -yc if other.sign == -1
2570
+
2571
+ # compute correctly rounded result: start with precision +3,
2572
+ # then increase precision until result is unambiguously roundable
2573
+ extra = 3
2574
+ coeff, exp = nil, nil
2575
+ loop do
2576
+ coeff, exp = _dpower(xc, xe, yc, ye, p+extra)
2577
+ #break if (coeff % Decimal.int_mult_radix_power(5,coeff.to_s.length-p-1)) != 0
2578
+ break if (coeff % (5*10**(coeff.to_s.length-p-1))) != 0
2579
+ extra += 3
2580
+ end
2581
+ ans = Decimal(result_sign, coeff, exp)
2290
2582
  end
2291
- end
2292
2583
 
2293
- # Round up (not away from 0 if negative) to i digits
2294
- def _round_ceiling(i)
2295
- sign<0 ? _round_down(i) : -_round_down(i)
2584
+ # the specification says that for non-integer other we need to
2585
+ # raise Inexact, even when the result is actually exact. In
2586
+ # the same way, we need to raise Underflow here if the result
2587
+ # is subnormal. (The call to _fix will take care of raising
2588
+ # Rounded and Subnormal, as usual.)
2589
+ if !other.integral?
2590
+ context.exception Inexact
2591
+ # pad with zeros up to length context.precision+1 if necessary
2592
+ if ans.number_of_digits <= context.precision
2593
+ 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)
2595
+ end
2596
+ context.exception Underflow if ans.adjusted_exponent < context.emin
2597
+ end
2598
+ # unlike exp, ln and log10, the power function respects the
2599
+ # rounding mode; no need to use ROUND_HALF_EVEN here
2600
+ ans._fix(context)
2296
2601
  end
2297
2602
 
2298
- # Round down (not toward 0 if negative) to i digits
2299
- def _round_floor(i)
2300
- sign>0 ? _round_down(i) : -_round_down(i)
2301
- end
2603
+ # Returns the base 10 logarithm
2604
+ def log10(context=nil)
2605
+ context = Decimal.define_context(context)
2302
2606
 
2303
- # Round down unless digit i-1 is 0 or 5
2304
- def _round_up05(i)
2305
- if ROUND_ARITHMETIC
2306
- dg = (@coeff%Decimal.int_radix_power(i+1))/Decimal.int_radix_power(i)
2607
+ # log10(NaN) = NaN
2608
+ ans = _check_nans(context)
2609
+ return ans if ans
2610
+
2611
+ # log10(0.0) == -Infinity
2612
+ return Decimal.infinity(-1) if self.zero?
2613
+
2614
+ # log10(Infinity) = Infinity
2615
+ return Decimal.infinity if self.infinite? && self.sign == +1
2616
+
2617
+ # log10(negative or -Infinity) raises InvalidOperation
2618
+ return context.exception(InvalidOperation, 'log10 of a negative value') if self.sign == -1
2619
+
2620
+ digits = self.digits
2621
+ # log10(10**n) = n
2622
+ if digits.first == 1 && digits[1..-1].all?{|d| d==0}
2623
+ # answer may need rounding
2624
+ ans = Decimal(self.integral_exponent + digits.size - 1)
2625
+ return ans if context.exact?
2307
2626
  else
2308
- d = @coeff.to_s
2309
- p = d.size - i
2310
- dg = (p>0) ? d[p-1,1].to_i : 0
2627
+ # result is irrational, so necessarily inexact
2628
+ return context.exception(Inexact, "Inexact power") if context.exact?
2629
+ c = self.integral_significand
2630
+ e = self.integral_exponent
2631
+ p = context.precision
2632
+
2633
+ # correctly rounded result: repeatedly increase precision
2634
+ # until result is unambiguously roundable
2635
+ places = p-self._log10_exp_bound+2
2636
+ coeff = nil
2637
+ loop do
2638
+ coeff = _dlog10(c, e, places)
2639
+ # assert coeff.abs.to_s.length-p >= 1
2640
+ break if (coeff % (5*10**(coeff.abs.to_s.length-p-1)))!=0
2641
+ places += 3
2642
+ end
2643
+ ans = Decimal(coeff<0 ? -1 : +1, coeff.abs, -places)
2311
2644
  end
2312
- if [0,Decimal.radix/2].include?(dg)
2313
- -_round_down(i)
2314
- else
2315
- _round_down(i)
2645
+
2646
+ Decimal.context(context, :rounding=>:half_even) do |local_context|
2647
+ ans = ans._fix(local_context)
2648
+ context.flags = local_context.flags
2316
2649
  end
2650
+ return ans
2317
2651
  end
2318
2652
 
2319
- # adjust payload of a NaN to the context
2320
- def _fix_nan(context)
2321
- if !context.exact?
2322
- payload = @coeff
2323
- payload = nil if payload==0
2653
+ # Exponential function
2654
+ def exp(context=nil)
2655
+ context = Decimal.define_context(context)
2324
2656
 
2325
- max_payload_len = context.maximum_nan_diagnostic_digits
2657
+ # exp(NaN) = NaN
2658
+ ans = _check_nans(context)
2659
+ return ans if ans
2326
2660
 
2327
- if number_of_digits > max_payload_len
2328
- payload = payload.to_s[-max_payload_len..-1].to_i
2329
- return Decimal([@sign, payload, @exp])
2661
+ # exp(-Infinity) = 0
2662
+ return Decimal.zero if self.infinite? && (self.sign == -1)
2663
+
2664
+ # exp(0) = 1
2665
+ return Decimal(1) if self.zero?
2666
+
2667
+ # exp(Infinity) = Infinity
2668
+ return Decimal(self) if self.infinite?
2669
+
2670
+ # the result is now guaranteed to be inexact (the true
2671
+ # mathematical result is transcendental). There's no need to
2672
+ # raise Rounded and Inexact here---they'll always be raised as
2673
+ # a result of the call to _fix.
2674
+ return context.exception(Inexact, 'Inexact exp') if context.exact?
2675
+ p = context.precision
2676
+ adj = self.adjusted_exponent
2677
+
2678
+ # we only need to do any computation for quite a small range
2679
+ # of adjusted exponents---for example, -29 <= adj <= 10 for
2680
+ # the default context. For smaller exponent the result is
2681
+ # indistinguishable from 1 at the given precision, while for
2682
+ # larger exponent the result either overflows or underflows.
2683
+ if self.sign == +1 and adj > ((context.emax+1)*3).to_s.length
2684
+ # overflow
2685
+ ans = Decimal(+1, 1, context.emax+1)
2686
+ elsif self.sign == -1 and adj > ((-context.etiny+1)*3).to_s.length
2687
+ # underflow to 0
2688
+ ans = Decimal(+1, 1, context.etiny-1)
2689
+ elsif self.sign == +1 and adj < -p
2690
+ # p+1 digits; final round will raise correct flags
2691
+ ans = Decimal(+1, Decimal.int_radix_power(p)+1, -p)
2692
+ elsif self.sign == -1 and adj < -p-1
2693
+ # p+1 digits; final round will raise correct flags
2694
+ ans = Decimal(+1, Decimal.int_radix_power(p+1)-1, -p-1)
2695
+ else
2696
+ # general case
2697
+ c = self.integral_significand
2698
+ e = self.integral_exponent
2699
+ c = -c if self.sign == -1
2700
+
2701
+ # compute correctly rounded result: increase precision by
2702
+ # 3 digits at a time until we get an unambiguously
2703
+ # roundable result
2704
+ extra = 3
2705
+ coeff = exp = nil
2706
+ loop do
2707
+ coeff, exp = _dexp(c, e, p+extra)
2708
+ break if (coeff % (5*10**(coeff.to_s.length-p-1)))!=0
2709
+ extra += 3
2330
2710
  end
2711
+ ans = Decimal(+1, coeff, exp)
2331
2712
  end
2332
- Decimal(self)
2713
+
2714
+ # at this stage, ans should round correctly with *any*
2715
+ # rounding mode, not just with ROUND_HALF_EVEN
2716
+ Decimal.context(context, :rounding=>:half_even) do |local_context|
2717
+ ans = ans._fix(local_context)
2718
+ context.flags = local_context.flags
2719
+ end
2720
+
2721
+ return ans
2722
+ end
2723
+
2724
+ # Returns the natural (base e) logarithm
2725
+ def ln(context=nil)
2726
+ context = Decimal.define_context(context)
2727
+
2728
+ # ln(NaN) = NaN
2729
+ ans = _check_nans(context)
2730
+ return ans if ans
2731
+
2732
+ # ln(0.0) == -Infinity
2733
+ return Decimal.infinity(-1) if self.zero?
2734
+
2735
+ # ln(Infinity) = Infinity
2736
+ return Decimal.infinity if self.infinite? && self.sign == +1
2737
+
2738
+ # ln(1.0) == 0.0
2739
+ return Decimal.zero if self == Decimal(1)
2740
+
2741
+ # ln(negative) raises InvalidOperation
2742
+ return context.exception(InvalidOperation, 'ln of a negative value') if self.sign==-1
2743
+
2744
+ # result is irrational, so necessarily inexact
2745
+ return context.exception(Inexact, 'Inexact exp') if context.exact?
2746
+
2747
+ c = self.integral_significand
2748
+ e = self.integral_exponent
2749
+ p = context.precision
2750
+
2751
+ # correctly rounded result: repeatedly increase precision by 3
2752
+ # until we get an unambiguously roundable result
2753
+ places = p - self._ln_exp_bound + 2 # at least p+3 places
2754
+ coeff = nil
2755
+ loop do
2756
+ coeff = _dlog(c, e, places)
2757
+ # assert coeff.to_s.length-p >= 1
2758
+ break if (coeff % (5*10**(coeff.abs.to_s.length-p-1))) != 0
2759
+ places += 3
2760
+ end
2761
+ ans = Decimal((coeff<0) ? -1 : +1, coeff.abs, -places)
2762
+
2763
+ Decimal.context(context, :rounding=>:half_even) do |local_context|
2764
+ ans = ans._fix(local_context)
2765
+ context.flags = local_context.flags
2766
+ end
2767
+ return ans
2333
2768
  end
2334
2769
 
2770
+ # Auxiliar Methods
2771
+
2335
2772
  # Check if the number or other is NaN, signal if sNaN or return NaN;
2336
2773
  # return nil if none is NaN.
2337
2774
  def _check_nans(context=nil, other=nil)
@@ -2377,113 +2814,23 @@ class Decimal
2377
2814
 
2378
2815
  end
2379
2816
 
2380
- # Normalizes op1, op2 to have the same exp and length of coefficient. Used for addition.
2381
- def Decimal._normalize(op1, op2, prec=0)
2382
- #puts "N: #{op1.inspect} #{op2.inspect} p=#{prec}"
2383
- if op1.integral_exponent < op2.integral_exponent
2384
- swap = true
2385
- tmp,other = op2,op1
2386
- else
2387
- swap = false
2388
- tmp,other = op1,op2
2817
+ def _watched_rescale(exp, context, watch_exp)
2818
+ if !watch_exp
2819
+ ans = _rescale(exp, context.rounding)
2820
+ context.exception(Rounded) if ans.integral_exponent > self.integral_exponent
2821
+ context.exception(Inexact) if ans != self
2822
+ return ans
2389
2823
  end
2390
- tmp_len = tmp.number_of_digits
2391
- other_len = other.number_of_digits
2392
- exp = tmp.integral_exponent + [-1, tmp_len - prec - 2].min
2393
- #puts "exp=#{exp}"
2394
- if (other_len+other.integral_exponent-1 < exp) && prec>0
2395
- other = Decimal.new([other.sign, 1, exp])
2396
- #puts "other = #{other.inspect}"
2824
+
2825
+ if exp < context.etiny || exp > context.emax
2826
+ return context.exception(InvalidOperation, "target operation out of bounds in quantize/rescale")
2397
2827
  end
2398
- tmp = Decimal.new([tmp.sign, int_mult_radix_power(tmp.integral_significand, tmp.integral_exponent-other.integral_exponent), other.integral_exponent])
2399
- #puts "tmp=#{tmp.inspect}"
2400
- return swap ? [other, tmp] : [tmp, other]
2401
- end
2402
2828
 
2403
- # Returns a copy of with the sign set to +
2404
- def copy_abs
2405
- Decimal.new([+1,@coeff,@exp])
2406
- end
2829
+ return Decimal.new([@sign, 0, exp])._fix(context) if zero?
2407
2830
 
2408
- # Returns a copy of with the sign inverted
2409
- def copy_negate
2410
- Decimal.new([-@sign,@coeff,@exp])
2411
- end
2412
-
2413
- # Returns a copy of with the sign of other
2414
- def copy_sign(other)
2415
- Decimal.new([other.sign, @coeff, @exp])
2416
- end
2417
-
2418
- # Returns true if the value is an integer
2419
- def integral?
2420
- if finite?
2421
- if @exp>=0 || @coeff==0
2422
- true
2423
- else
2424
- if @exp <= -number_of_digits
2425
- false
2426
- else
2427
- m = Decimal.int_radix_power(-@exp)
2428
- (@coeff % m) == 0
2429
- end
2430
- end
2431
- else
2432
- false
2433
- end
2434
- end
2435
-
2436
- # Rescale so that the exponent is exp, either by padding with zeros
2437
- # or by truncating digits.
2438
- def rescale(exp, context=nil, watch_exp=true)
2439
- context = Decimal.define_context(context)
2440
- exp = Decimal._convert(exp)
2441
- if self.special? || exp.special?
2442
- ans = _check_nans(context, exp)
2443
- return ans if ans
2444
- if exp.infinite? || self.infinite?
2445
- return Decimal.new(self) if exp.infinite? && self.infinite?
2446
- return context.exception(InvalidOperation, 'rescale with one INF')
2447
- end
2448
- end
2449
- return context.exception(InvalidOperation,"exponent of rescale is not integral") unless exp.integral?
2450
- exp = exp.to_i
2451
- _watched_rescale(exp, context, watch_exp)
2452
- end
2453
-
2454
- # Quantize so its exponent is the same as that of y.
2455
- def quantize(exp, context=nil, watch_exp=true)
2456
- exp = Decimal._convert(exp)
2457
- context = Decimal.define_context(context)
2458
- if self.special? || exp.special?
2459
- ans = _check_nans(context, exp)
2460
- return ans if ans
2461
- if exp.infinite? || self.infinite?
2462
- return Decimal.new(self) if exp.infinite? && self.infinite?
2463
- return context.exception(InvalidOperation, 'quantize with one INF')
2464
- end
2465
- end
2466
- exp = exp.integral_exponent
2467
- _watched_rescale(exp, context, watch_exp)
2468
- end
2469
-
2470
- def _watched_rescale(exp, context, watch_exp)
2471
- if !watch_exp
2472
- ans = _rescale(exp, context.rounding)
2473
- context.exception(Rounded) if ans.integral_exponent > self.integral_exponent
2474
- context.exception(Inexact) if ans != self
2475
- return ans
2476
- end
2477
-
2478
- if exp < context.etiny || exp > context.emax
2479
- return context.exception(InvalidOperation, "target operation out of bounds in quantize/rescale")
2480
- end
2481
-
2482
- return Decimal.new([@sign, 0, exp])._fix(context) if zero?
2483
-
2484
- self_adjusted = adjusted_exponent
2485
- return context.exception(InvalidOperation,"exponent of quantize/rescale result too large for current context") if self_adjusted > context.emax
2486
- return context.exception(InvalidOperation,"quantize/rescale has too many digits for current context") if (self_adjusted - exp + 1 > context.precision) && !context.exact?
2831
+ self_adjusted = adjusted_exponent
2832
+ return context.exception(InvalidOperation,"exponent of quantize/rescale result too large for current context") if self_adjusted > context.emax
2833
+ return context.exception(InvalidOperation,"quantize/rescale has too many digits for current context") if (self_adjusted - exp + 1 > context.precision) && !context.exact?
2487
2834
 
2488
2835
  ans = _rescale(exp, context.rounding)
2489
2836
  return context.exception(InvalidOperation,"exponent of rescale result too large for current context") if ans.adjusted_exponent > context.emax
@@ -2496,147 +2843,153 @@ class Decimal
2496
2843
  return ans._fix(context)
2497
2844
  end
2498
2845
 
2499
- # Return true if has the same exponent as other.
2500
- #
2501
- # If either operand is a special value, the following rules are used:
2502
- # * return true if both operands are infinities
2503
- # * return true if both operands are NaNs
2504
- # * otherwise, return false.
2505
- def same_quantum?(other)
2506
- other = Decimal._convert(other)
2507
- if self.special? || other.special?
2508
- return (self.nan? && other.nan?) || (self.infinite? && other.infinite?)
2846
+ # Returns copy with sign inverted
2847
+ def _neg(context=nil)
2848
+ if special?
2849
+ ans = _check_nans(context)
2850
+ return ans if ans
2509
2851
  end
2510
- return self.integral_exponent == other.integral_exponent
2852
+ if zero?
2853
+ ans = copy_abs
2854
+ else
2855
+ ans = copy_negate
2856
+ end
2857
+ context = Decimal.define_context(context)
2858
+ ans._fix(context)
2511
2859
  end
2512
2860
 
2513
- # Rounds to a nearby integer. May raise Inexact or Rounded.
2514
- def to_integral_exact(context=nil)
2515
- context = Decimal.define_context(context)
2861
+ # Returns a copy with precision adjusted
2862
+ def _pos(context=nil)
2516
2863
  if special?
2517
2864
  ans = _check_nans(context)
2518
2865
  return ans if ans
2519
- return Decimal.new(self)
2520
2866
  end
2521
- return Decimal.new(self) if @exp >= 0
2522
- return Decimal.new([@sign, 0, 0]) if zero?
2523
- context.exception Rounded
2524
- ans = _rescale(0, context.rounding)
2525
- context.exception Inexact if ans != self
2526
- return ans
2867
+ if zero?
2868
+ ans = copy_abs
2869
+ else
2870
+ ans = Decimal.new(self)
2871
+ end
2872
+ context = Decimal.define_context(context)
2873
+ ans._fix(context)
2527
2874
  end
2528
2875
 
2529
- # Rounds to a nearby integer. Doesn't raise Inexact or Rounded.
2530
- def to_integral_value(context=nil)
2531
- context = Decimal.define_context(context)
2876
+ # Returns a copy with positive sign
2877
+ def _abs(round=true, context=nil)
2878
+ return copy_abs if not round
2879
+
2532
2880
  if special?
2533
2881
  ans = _check_nans(context)
2534
2882
  return ans if ans
2535
- return Decimal.new(self)
2536
2883
  end
2537
- return Decimal.new(self) if @exp >= 0
2538
- return _rescale(0, context.rounding)
2539
- end
2540
-
2541
- # General rounding.
2542
- #
2543
- # With an integer argument this acts like Float#round: the parameter specifies the number
2544
- # of fractional digits (or digits to the left of the decimal point if negative).
2545
- #
2546
- # Options can be passed as a Hash instead; valid options are:
2547
- # * :rounding method for rounding (see Context#new())
2548
- # The precision can be specified as:
2549
- # * :places number of fractional digits as above.
2550
- # * :exponent specifies the exponent corresponding to the
2551
- # digit to be rounded (exponent == -places)
2552
- # * :precision or :significan_digits is the number of digits
2553
- # * :power 10^exponent, value of the digit to be rounded,
2554
- # should be passed as a type convertible to Decimal.
2555
- # * :index 0-based index of the digit to be rounded
2556
- # * :rindex right 0-based index of the digit to be rounded
2557
- #
2558
- # The default is :places=>0 (round to integer).
2559
- #
2560
- # Example: ways of specifiying the rounding position
2561
- # number: 1 2 3 4 . 5 6 7 8
2562
- # :places -3 -2 -1 0 1 2 3 4
2563
- # :exponent 3 2 1 0 -1 -2 -3 -4
2564
- # :precision 1 2 3 4 5 6 7 8
2565
- # :power 1E3 1E2 10 1 0.1 1E-2 1E-3 1E-4
2566
- # :index 0 1 2 3 4 5 6 7
2567
- # :index 7 6 5 4 3 2 1 0
2568
- def round(opt={})
2569
- opt = { :places=>opt } if opt.kind_of?(Integer)
2570
- r = opt[:rounding] || :half_up
2571
- as_int = false
2572
- if v=(opt[:precision] || opt[:significant_digits])
2573
- prec = v
2574
- elsif v=(opt[:places])
2575
- prec = adjusted_exponent + 1 + v
2576
- elsif v=(opt[:exponent])
2577
- prec = adjusted_exponent + 1 - v
2578
- elsif v=(opt[:power])
2579
- prec = adjusted_exponent + 1 - Decimal(v).adjusted_exponent
2580
- elsif v=(opt[:index])
2581
- prec = i+1
2582
- elsif v=(opt[:rindex])
2583
- prec = number_of_digits - v
2884
+ if sign>0
2885
+ ans = _neg(context)
2584
2886
  else
2585
- prec = adjusted_exponent + 1
2586
- as_int = true
2887
+ ans = _pos(context)
2587
2888
  end
2588
- result = plus(:rounding=>r, :precision=>prec)
2589
- return as_int ? result.to_i : result
2889
+ ans
2590
2890
  end
2591
2891
 
2592
- # General ceiling operation (as for Float) with same options for precision
2593
- # as Decimal#round()
2594
- def ceil(opt={})
2595
- opt[:rounding] = :ceiling
2596
- round opt
2597
- end
2892
+ # Round if it is necessary to keep within precision.
2893
+ def _fix(context)
2894
+ return self if context.exact?
2598
2895
 
2599
- # General floor operation (as for Float) with same options for precision
2600
- # as Decimal#round()
2601
- def floor(opt={})
2602
- opt[:rounding] = :floor
2603
- round opt
2604
- end
2896
+ if special?
2897
+ if nan?
2898
+ return _fix_nan(context)
2899
+ else
2900
+ return Decimal.new(self)
2901
+ end
2902
+ end
2903
+
2904
+ etiny = context.etiny
2905
+ etop = context.etop
2906
+ if zero?
2907
+ exp_max = context.clamp? ? etop : context.emax
2908
+ new_exp = [[@exp, etiny].max, exp_max].min
2909
+ if new_exp!=@exp
2910
+ context.exception Clamped
2911
+ return Decimal.new([sign,0,new_exp])
2912
+ else
2913
+ return Decimal.new(self)
2914
+ end
2915
+ end
2916
+
2917
+ nd = number_of_digits
2918
+ exp_min = nd + @exp - context.precision
2919
+ if exp_min > etop
2920
+ context.exception Inexact
2921
+ context.exception Rounded
2922
+ return context.exception(Overflow, 'above Emax', sign)
2923
+ end
2924
+
2925
+ self_is_subnormal = exp_min < etiny
2926
+
2927
+ if self_is_subnormal
2928
+ context.exception Subnormal
2929
+ exp_min = etiny
2930
+ end
2931
+
2932
+ if @exp < exp_min
2933
+ context.exception Rounded
2934
+ # dig is the digits number from 0 (MS) to number_of_digits-1 (LS)
2935
+ # dg = numberof_digits-dig is from 1 (LS) to number_of_digits (MS)
2936
+ dg = exp_min - @exp # dig = number_of_digits + exp - exp_min
2937
+ if dg > number_of_digits # dig<0
2938
+ d = Decimal.new([sign,1,exp_min-1])
2939
+ dg = number_of_digits # dig = 0
2940
+ else
2941
+ d = Decimal.new(self)
2942
+ end
2943
+ changed = d._round(context.rounding, dg)
2944
+ coeff = Decimal.int_div_radix_power(d.integral_significand, dg)
2945
+ coeff += 1 if changed==1
2946
+ ans = Decimal.new([sign, coeff, exp_min])
2947
+ if changed!=0
2948
+ context.exception Inexact
2949
+ if self_is_subnormal
2950
+ context.exception Underflow
2951
+ if ans.zero?
2952
+ context.exception Clamped
2953
+ end
2954
+ 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])
2957
+ else
2958
+ ans = context.exception(Overflow, 'above Emax', d.sign)
2959
+ end
2960
+ end
2961
+ end
2962
+ return ans
2963
+ end
2964
+
2965
+ if context.clamp? && @exp>etop
2966
+ context.exception Clamped
2967
+ self_padded = Decimal.int_mult_radix_power(@coeff, @exp-etop)
2968
+ return Decimal.new([sign,self_padded,etop])
2969
+ end
2970
+
2971
+ return Decimal.new(self)
2605
2972
 
2606
- # General truncate operation (as for Float) with same options for precision
2607
- # as Decimal#round()
2608
- def truncate(opt={})
2609
- opt[:rounding] = :down
2610
- round opt
2611
2973
  end
2612
2974
 
2613
- # Fused multiply-add.
2614
- #
2615
- # Computes (self*other+third) with no rounding of the intermediate product self*other.
2616
- def fma(other, third, context=nil)
2617
- context = Decimal.define_context(context)
2618
- other = Decimal._convert(other)
2619
- third = Decimal._convert(third)
2620
- if self.special? || other.special?
2621
- return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
2622
- return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
2623
- if self.nan?
2624
- product = self
2625
- elsif other.nan?
2626
- product = other
2627
- elsif self.infinite?
2628
- return context.exception(InvalidOperation, 'INF * 0 in fma') if other.zero?
2629
- product = Decimal.infinity(self.sign*other.sign)
2630
- elsif other.infinite?
2631
- return context.exception(InvalidOperation, '0 * INF in fma') if self.zero?
2632
- product = Decimal.infinity(self.sign*other.sign)
2975
+ # adjust payload of a NaN to the context
2976
+ def _fix_nan(context)
2977
+ if !context.exact?
2978
+ payload = @coeff
2979
+ payload = nil if payload==0
2980
+
2981
+ max_payload_len = context.maximum_nan_diagnostic_digits
2982
+
2983
+ if number_of_digits > max_payload_len
2984
+ payload = payload.to_s[-max_payload_len..-1].to_i
2985
+ return Decimal([@sign, payload, @exp])
2633
2986
  end
2634
- else
2635
- product = Decimal.new([self.sign*other.sign,self.integral_significand*other.integral_significand, self.integral_exponent+other.integral_exponent])
2636
2987
  end
2637
- return product.add(third, context)
2988
+ Decimal(self)
2638
2989
  end
2639
2990
 
2991
+ protected
2992
+
2640
2993
  def _divide_truncate(other, context)
2641
2994
  context = Decimal.define_context(context)
2642
2995
  sign = self.sign * other.sign
@@ -2715,28 +3068,869 @@ class Decimal
2715
3068
 
2716
3069
  end
2717
3070
 
2718
- # Convert a numeric value to decimal (internal use)
2719
- def Decimal._convert(x, error=true)
2720
- case x
2721
- when Decimal
2722
- x
2723
- when *Decimal.context.coercible_types
2724
- Decimal.new(x)
3071
+ # Power-modulo: self._power_modulo(other, modulo) == (self**other) % modulo
3072
+ # This is equivalent to Python's 3-argument version of pow()
3073
+ def _power_modulo(other, modulo, context=nil)
3074
+
3075
+ context = Decimal.define_context(context)
3076
+ other = _convert(other)
3077
+ modulo = _convert(third)
3078
+
3079
+ if self.nan? || other.nan? || modulo.nan?
3080
+ return context.exception(InvalidOperation, 'sNaN', self) if self.snan?
3081
+ return context.exception(InvalidOperation, 'sNaN', other) if other.snan?
3082
+ return context.exception(InvalidOperation, 'sNaN', modulo) if other.modulo?
3083
+ return self._fix_nan(context) if self.nan?
3084
+ return other._fix_nan(context) if other.nan?
3085
+ return modulo._fix_nan(context) # if modulo.nan?
3086
+ end
3087
+
3088
+ if !(self.integral? && other.integral? && modulo.integral?)
3089
+ return context.exception(InvalidOperation, '3-argument power not allowed unless all arguments are integers.')
3090
+ end
3091
+
3092
+ if other < 0
3093
+ return context.exception(InvalidOperation, '3-argument power cannot have a negative 2nd argument.')
3094
+ end
3095
+
3096
+ if modulo.zero?
3097
+ return context.exception(InvalidOperation, '3-argument power cannot have a 0 3rd argument.')
3098
+ end
3099
+
3100
+ if modulo.adjusted_exponent >= context.precision
3101
+ return context.exception(InvalidOperation, 'insufficient precision: power 3rd argument must not have more than precision digits')
3102
+ end
3103
+
3104
+ if other.zero? && self.zero?
3105
+ return context.exception(InvalidOperation, "0**0 not defined")
3106
+ end
3107
+
3108
+ sign = other.even? ? +1 : -1
3109
+ modulo = modulo.to_i.abs
3110
+
3111
+ base = (self.integral_significand % modulo * (Decimal.int_radix_power(self.integral_exponent) % modulo)) % modulo
3112
+
3113
+ other.integral_exponent.times do
3114
+ base = (base**Decimal.radix) % modulo
3115
+ end
3116
+ base = (base**other.integral_significand) % modulo
3117
+
3118
+ Decimal(sign, base, 0)
3119
+ end
3120
+
3121
+ # Attempt to compute self**other exactly
3122
+ # Given Decimals self and other and an integer p, attempt to
3123
+ # compute an exact result for the power self**other, with p
3124
+ # digits of precision. Return nil if self**other is not
3125
+ # exactly representable in p digits.
3126
+ #
3127
+ # Assumes that elimination of special cases has already been
3128
+ # performed: self and other must both be nonspecial; self must
3129
+ # 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.
3132
+ def _power_exact(other, p)
3133
+
3134
+ # In the comments below, we write x for the value of self and
3135
+ # y for the value of other. Write x = xc*10**xe and y =
3136
+ # yc*10**ye.
3137
+
3138
+ # The main purpose of this method is to identify the *failure*
3139
+ # of x**y to be exactly representable with as little effort as
3140
+ # possible. So we look for cheap and easy tests that
3141
+ # eliminate the possibility of x**y being exact. Only if all
3142
+ # these tests are passed do we go on to actually compute x**y.
3143
+
3144
+ # Here's the main idea. First normalize both x and y. We
3145
+ # express y as a rational m/n, with m and n relatively prime
3146
+ # and n>0. Then for x**y to be exactly representable (at
3147
+ # *any* precision), xc must be the nth power of a positive
3148
+ # integer and xe must be divisible by n. If m is negative
3149
+ # then additionally xc must be a power of either 2 or 5, hence
3150
+ # a power of 2**n or 5**n.
3151
+ #
3152
+ # There's a limit to how small |y| can be: if y=m/n as above
3153
+ # then:
3154
+ #
3155
+ # (1) if xc != 1 then for the result to be representable we
3156
+ # need xc**(1/n) >= 2, and hence also xc**|y| >= 2. So
3157
+ # if |y| <= 1/nbits(xc) then xc < 2**nbits(xc) <=
3158
+ # 2**(1/|y|), hence xc**|y| < 2 and the result is not
3159
+ # representable.
3160
+ #
3161
+ # (2) if xe != 0, |xe|*(1/n) >= 1, so |xe|*|y| >= 1. Hence if
3162
+ # |y| < 1/|xe| then the result is not representable.
3163
+ #
3164
+ # Note that since x is not equal to 1, at least one of (1) and
3165
+ # (2) must apply. Now |y| < 1/nbits(xc) iff |yc|*nbits(xc) <
3166
+ # 10**-ye iff len(str(|yc|*nbits(xc)) <= -ye.
3167
+ #
3168
+ # There's also a limit to how large y can be, at least if it's
3169
+ # positive: the normalized result will have coefficient xc**y,
3170
+ # so if it's representable then xc**y < 10**p, and y <
3171
+ # p/log10(xc). Hence if y*log10(xc) >= p then the result is
3172
+ # not exactly representable.
3173
+
3174
+ # if len(str(abs(yc*xe)) <= -ye then abs(yc*xe) < 10**-ye,
3175
+ # so |y| < 1/xe and the result is not representable.
3176
+ # Similarly, len(str(abs(yc)*xc_bits)) <= -ye implies |y|
3177
+ # < 1/nbits(xc).
3178
+
3179
+ xc = self.integral_significand
3180
+ xe = self.integral_exponent
3181
+ while (xc % Decimal.radix) == 0
3182
+ xc /= Decimal.radix
3183
+ xe += 1
3184
+ end
3185
+
3186
+ yc = other.integral_significand
3187
+ ye = other.integral_exponent
3188
+ while (yc % Decimal.radix) == 0
3189
+ yc /= Decimal.radix
3190
+ ye += 1
3191
+ end
3192
+
3193
+ # case where xc == 1: result is 10**(xe*y), with xe*y
3194
+ # required to be an integer
3195
+ if xc == 1
3196
+ if ye >= 0
3197
+ exponent = xe*yc*Decimal.int_radix_power(ye)
3198
+ else
3199
+ exponent, remainder = (xe*yc).divmod(Decimal.int_radix_power(-ye))
3200
+ return nil if remainder!=0
3201
+ end
3202
+ exponent = -exponent if other.sign == -1
3203
+ # if other is a nonnegative integer, use ideal exponent
3204
+ if other.integral? and (other.sign == +1)
3205
+ ideal_exponent = self.integral_exponent*other.to_i
3206
+ zeros = [exponent-ideal_exponent, p-1].min
3207
+ else
3208
+ zeros = 0
3209
+ end
3210
+ return Decimal(+1, Decimal.int_radix_power(zeros), exponent-zeros)
3211
+ end
3212
+
3213
+ # case where y is negative: xc must be either a power
3214
+ # of 2 or a power of 5.
3215
+ if other.sign == -1
3216
+ last_digit = (xc % 10)
3217
+ if [2,4,6,8].include?(last_digit)
3218
+ # quick test for power of 2
3219
+ return nil if xc & -xc != xc
3220
+ # now xc is a power of 2; e is its exponent
3221
+ e = _nbits(xc)-1
3222
+ # find e*y and xe*y; both must be integers
3223
+ if ye >= 0
3224
+ y_as_int = yc*Decimal.int_radix_power(ye)
3225
+ e = e*y_as_int
3226
+ xe = xe*y_as_int
3227
+ else
3228
+ ten_pow = Decimal.int_radix_power(-ye)
3229
+ e, remainder = (e*yc).divmod(ten_pow)
3230
+ return nil if remainder!=0
3231
+ xe, remainder = (xe*yc).divmod(ten_pow)
3232
+ return nil if remainder!=0
3233
+ end
3234
+
3235
+ return nil if e*65 >= p*93 # 93/65 > log(10)/log(5)
3236
+ xc = 5**e
3237
+ elsif last_digit == 5
3238
+ # e >= log_5(xc) if xc is a power of 5; we have
3239
+ # equality all the way up to xc=5**2658
3240
+ e = _nbits(xc)*28/65
3241
+ xc, remainder = (5**e).divmod(xc)
3242
+ return nil if remainder!=0
3243
+ while (xc % 5) == 0
3244
+ xc /= 5
3245
+ e -= 1
3246
+ end
3247
+ if ye >= 0
3248
+ y_as_integer = Decimal.int_mult_radix_power(yc,ye)
3249
+ e = e*y_as_integer
3250
+ xe = xe*y_as_integer
3251
+ else
3252
+ ten_pow = Decimal.int_radix_power(-ye)
3253
+ e, remainder = (e*yc).divmod(ten_pow)
3254
+ return nil if remainder
3255
+ xe, remainder = (xe*yc).divmod(ten_pow)
3256
+ return nil if remainder
3257
+ end
3258
+ return nil if e*3 >= p*10 # 10/3 > log(10)/log(2)
3259
+ xc = 2**e
3260
+ else
3261
+ return nil
3262
+ end
3263
+
3264
+ return nil if xc >= Decimal.int_radix_power(p)
3265
+ xe = -e-xe
3266
+ return Decimal(+1, xc, xe)
3267
+
3268
+ end
3269
+
3270
+ # now y is positive; find m and n such that y = m/n
3271
+ if ye >= 0
3272
+ m, n = yc*10**ye, 1
2725
3273
  else
2726
- raise TypeError, "Unable to convert #{x.class} to Decimal" if error
2727
- nil
3274
+ return nil if (xe != 0) and ((yc*xe).abs.to_s.length <= -ye)
3275
+ xc_bits = _nbits(xc)
3276
+ return nil if (xc != 1) and ((yc.abs*xc_bits).to_s.length <= -ye)
3277
+ m, n = yc, Decimal.int_radix_power(-ye)
3278
+ while ((m % 2) == 0) && ((n % 2) == 0)
3279
+ m /= 2
3280
+ n /= 2
3281
+ end
3282
+ while ((m % 5) == 0) && ((n % 5) == 0)
3283
+ m /= 5
3284
+ n /= 5
3285
+ end
3286
+ end
3287
+
3288
+ # compute nth root of xc*10**xe
3289
+ if n > 1
3290
+ # if 1 < xc < 2**n then xc isn't an nth power
3291
+ return nil if xc != 1 and xc_bits <= n
3292
+
3293
+ xe, rem = xe.divmod(n)
3294
+ return nil if rem != 0
3295
+
3296
+ # compute nth root of xc using Newton's method
3297
+ a = 1 << -(-_nbits(xc)/n) # initial estimate
3298
+ q = r = nil
3299
+ loop do
3300
+ q, r = xc.divmod(a**(n-1))
3301
+ break if a <= q
3302
+ a = (a*(n-1) + q)/n
3303
+ end
3304
+ return nil if !((a == q) and (r == 0))
3305
+ xc = a
3306
+ end
3307
+
3308
+ # now xc*10**xe is the nth root of the original xc*10**xe
3309
+ # compute mth power of xc*10**xe
3310
+
3311
+ # if m > p*100/_log10_lb(xc) then m > p/log10(xc), hence xc**m >
3312
+ # 10**p and the result is not representable.
3313
+ return nil if (xc > 1) and (m > p*100/_log10_lb(xc))
3314
+ xc = xc**m
3315
+ xe *= m
3316
+ return nil if xc > 10**p
3317
+
3318
+ # by this point the result *is* exactly representable
3319
+ # adjust the exponent to get as close as possible to the ideal
3320
+ # exponent, if necessary
3321
+ str_xc = xc.to_s
3322
+ if other.integral? && other.sign == +1
3323
+ ideal_exponent = self.integral_exponent*other.to_i
3324
+ zeros = [xe-ideal_exponent, p-str_xc.length].min
3325
+ else
3326
+ zeros = 0
3327
+ end
3328
+ return Decimal(+1, Decimal.int_mult_radix_power(xc, zeros), xe-zeros)
3329
+ end
3330
+
3331
+ ROUND_ARITHMETIC = true
3332
+
3333
+ # Round to i digits using the specified method
3334
+ def _round(rounding, i)
3335
+ send("_round_#{rounding}", i)
3336
+ end
3337
+
3338
+ # Round down (toward 0, truncate) to i digits
3339
+ def _round_down(i)
3340
+ if ROUND_ARITHMETIC
3341
+ (@coeff % Decimal.int_radix_power(i))==0 ? 0 : -1
3342
+ else
3343
+ d = @coeff.to_s
3344
+ p = d.size - i
3345
+ d[p..-1].match(/\A0+\Z/) ? 0 : -1
3346
+ end
3347
+ end
3348
+
3349
+ # Round up (away from 0) to i digits
3350
+ def _round_up(i)
3351
+ -_round_down(i)
3352
+ end
3353
+
3354
+ # Round to closest i-digit number with ties down (rounds 5 toward 0)
3355
+ def _round_half_down(i)
3356
+ if ROUND_ARITHMETIC
3357
+ m = Decimal.int_radix_power(i)
3358
+ if (m>1) && ((@coeff%m) == m/2)
3359
+ -1
3360
+ else
3361
+ _round_half_up(i)
3362
+ end
3363
+ else
3364
+ d = @coeff.to_s
3365
+ p = d.size - i
3366
+ d[p..-1].match(/^5d*$/) ? -1 : _round_half_up(i)
3367
+ end
3368
+
3369
+ end
3370
+
3371
+ # Round to closest i-digit number with ties up (rounds 5 away from 0)
3372
+ def _round_half_up(i)
3373
+ if ROUND_ARITHMETIC
3374
+ m = Decimal.int_radix_power(i)
3375
+ if (m>1) && ((@coeff % m) >= m/2)
3376
+ 1
3377
+ else
3378
+ (@coeff % m)==0 ? 0 : -1
3379
+ end
3380
+ else
3381
+ d = @coeff.to_s
3382
+ p = d.size - i
3383
+ if '56789'.include?(d[p,1])
3384
+ 1
3385
+ else
3386
+ d[p..-1].match(/^0+$/) ? 0 : -1
3387
+ end
3388
+ end
3389
+
3390
+ end
3391
+
3392
+ # Round to closest i-digit number with ties (5) to an even digit
3393
+ def _round_half_even(i)
3394
+ if ROUND_ARITHMETIC
3395
+ m = Decimal.int_radix_power(i)
3396
+ if (m>1) && ((@coeff%m) == m/2 && ((@coeff/m)%2)==0)
3397
+ -1
3398
+ else
3399
+ _round_half_up(i)
3400
+ end
3401
+ else
3402
+ d = @coeff.to_s
3403
+ p = d.size - i
3404
+
3405
+ if d[p..-1].match(/\A#{Decimal.radix/2}0*\Z/) && (p==0 || ((d[p-1,1].to_i%2)==0))
3406
+ -1
3407
+ else
3408
+ _round_half_up(i)
3409
+ end
3410
+
2728
3411
  end
2729
3412
  end
2730
3413
 
2731
- # Parse numeric text literals (internal use)
2732
- def _parser(txt)
2733
- md = /^\s*([-+])?(?:(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([-+]?\d+))?|Inf(?:inity)?|(s)?NaN(\d*))\s*$/i.match(txt)
2734
- if md
2735
- OpenStruct.new :sign=>md[1], :int=>md[2], :frac=>md[3], :onlyfrac=>md[4], :exp=>md[5],
2736
- :signal=>md[6], :diag=>md[7]
3414
+ # Round up (not away from 0 if negative) to i digits
3415
+ def _round_ceiling(i)
3416
+ sign<0 ? _round_down(i) : -_round_down(i)
3417
+ end
3418
+
3419
+ # Round down (not toward 0 if negative) to i digits
3420
+ def _round_floor(i)
3421
+ sign>0 ? _round_down(i) : -_round_down(i)
3422
+ end
3423
+
3424
+ # Round down unless digit i-1 is 0 or 5
3425
+ def _round_up05(i)
3426
+ if ROUND_ARITHMETIC
3427
+ dg = (@coeff%Decimal.int_radix_power(i+1))/Decimal.int_radix_power(i)
3428
+ else
3429
+ d = @coeff.to_s
3430
+ p = d.size - i
3431
+ dg = (p>0) ? d[p-1,1].to_i : 0
3432
+ end
3433
+ if [0,Decimal.radix/2].include?(dg)
3434
+ -_round_down(i)
3435
+ else
3436
+ _round_down(i)
2737
3437
  end
2738
3438
  end
2739
3439
 
3440
+
3441
+ # Compute a lower bound for the adjusted exponent of self.log10()
3442
+ # In other words, find r such that self.log10() >= 10**r.
3443
+ # Assumes that self is finite and positive and that self != 1.
3444
+ def _log10_exp_bound
3445
+ # For x >= 10 or x < 0.1 we only need a bound on the integer
3446
+ # part of log10(self), and this comes directly from the
3447
+ # exponent of x. For 0.1 <= x <= 10 we use the inequalities
3448
+ # 1-1/x <= log(x) <= x-1. If x > 1 we have |log10(x)| >
3449
+ # (1-1/x)/2.31 > 0. If x < 1 then |log10(x)| > (1-x)/2.31 > 0
3450
+
3451
+ adj = self.integral_exponent + number_of_digits - 1
3452
+ return adj.to_s.length - 1 if adj >= 1 # self >= 10
3453
+ return (-1-adj).to_s.length-1 if adj <= -2 # self < 0.1
3454
+
3455
+ c = self.integral_significand
3456
+ e = self.integral_exponent
3457
+ if adj == 0
3458
+ # 1 < self < 10
3459
+ num = (c - Decimal.int_radix_power(-e)).to_s
3460
+ den = (231*c).to_s
3461
+ return num.length - den.length - ((num < den) ? 1 : 0) + 2
3462
+ end
3463
+ # adj == -1, 0.1 <= self < 1
3464
+ num = (Decimal.int_radix_power(-e)-c).to_s
3465
+ return num.length + e - ((num < "231") ? 1 : 0) - 1
3466
+ end
3467
+
3468
+ # Compute a lower bound for the adjusted exponent of self.ln().
3469
+ # In other words, compute r such that self.ln() >= 10**r. Assumes
3470
+ # that self is finite and positive and that self != 1.
3471
+ def _ln_exp_bound
3472
+ # 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
3474
+ if adj >= 1
3475
+ # argument >= 10; we use 23/10 = 2.3 as a lower bound for ln(10)
3476
+ return (adj*23/10).to_s.length - 1
3477
+ end
3478
+ if adj <= -2
3479
+ # argument <= 0.1
3480
+ return ((-1-adj)*23/10).to_s.length - 1
3481
+ end
3482
+ c = self.integral_significand
3483
+ e = self.integral_exponent
3484
+ if adj == 0
3485
+ # 1 < self < 10
3486
+ num = (c-(10**-e)).to_s
3487
+ den = c.to_s
3488
+ return num.length - den.length - ((num < den) ? 1 : 0)
3489
+ end
3490
+ # adj == -1, 0.1 <= self < 1
3491
+ return e + (10**-e - c).to_s.length - 1
3492
+ end
3493
+
3494
+ module AuxiliarFunctions #:nodoc:
3495
+
3496
+ module_function
3497
+
3498
+ # Convert a numeric value to decimal (internal use)
3499
+ def _convert(x, error=true)
3500
+ case x
3501
+ when Decimal
3502
+ x
3503
+ when *Decimal.context.coercible_types
3504
+ Decimal.new(x)
3505
+ else
3506
+ raise TypeError, "Unable to convert #{x.class} to Decimal" if error
3507
+ nil
3508
+ end
3509
+ end
3510
+
3511
+ # Parse numeric text literals (internal use)
3512
+ def _parser(txt)
3513
+ md = /^\s*([-+])?(?:(?:(\d+)(?:\.(\d*))?|\.(\d+))(?:[eE]([-+]?\d+))?|Inf(?:inity)?|(s)?NaN(\d*))\s*$/i.match(txt)
3514
+ if md
3515
+ OpenStruct.new :sign=>md[1], :int=>md[2], :frac=>md[3], :onlyfrac=>md[4], :exp=>md[5],
3516
+ :signal=>md[6], :diag=>md[7]
3517
+ end
3518
+ end
3519
+
3520
+ # Normalizes op1, op2 to have the same exp and length of coefficient. Used for addition.
3521
+ def _normalize(op1, op2, prec=0)
3522
+ if op1.integral_exponent < op2.integral_exponent
3523
+ swap = true
3524
+ tmp,other = op2,op1
3525
+ else
3526
+ swap = false
3527
+ tmp,other = op1,op2
3528
+ end
3529
+ tmp_len = tmp.number_of_digits
3530
+ 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
3533
+ other = Decimal.new([other.sign, 1, exp])
3534
+ end
3535
+ tmp = Decimal.new(tmp.sign,
3536
+ Decimal.int_mult_radix_power(tmp.integral_significand, tmp.integral_exponent-other.integral_exponent),
3537
+ other.integral_exponent)
3538
+ return swap ? [other, tmp] : [tmp, other]
3539
+ end
3540
+
3541
+ # Number of bits in binary representation of the positive integer n, or 0 if n == 0.
3542
+ #--
3543
+ # This function from Tim Peters was taken from here:
3544
+ # http://mail.python.org/pipermail/python-list/1999-July/007758.html
3545
+ # The correction being in the function definition is for speed, and
3546
+ # the whole function is not resolved with math.log because of avoiding
3547
+ # the use of floats.
3548
+ #++
3549
+ def _nbits(n, correction = { #:nodoc:
3550
+ '0'=> 4, '1'=> 3, '2'=> 2, '3'=> 2,
3551
+ '4'=> 1, '5'=> 1, '6'=> 1, '7'=> 1,
3552
+ '8'=> 0, '9'=> 0, 'a'=> 0, 'b'=> 0,
3553
+ 'c'=> 0, 'd'=> 0, 'e'=> 0, 'f'=> 0})
3554
+ raise TypeError, "The argument to _nbits should be nonnegative." if n < 0
3555
+ hex_n = "%x" % n
3556
+ 4*hex_n.length - correction[hex_n[0,1]]
3557
+ end
3558
+
3559
+ # Given integers xc, xe, yc and ye representing Decimals x = xc*10**xe and
3560
+ # y = yc*10**ye, compute x**y. Returns a pair of integers (c, e) such that:
3561
+ #
3562
+ # 10**(p-1) <= c <= 10**p, and
3563
+ # (c-1)*10**e < x**y < (c+1)*10**e
3564
+ #
3565
+ # in other words, c*10**e is an approximation to x**y with p digits
3566
+ # of precision, and with an error in c of at most 1. (This is
3567
+ # almost, but not quite, the same as the error being < 1ulp: when c
3568
+ # == 10**(p-1) we can only guarantee error < 10ulp.)
3569
+ #
3570
+ # We assume that: x is positive and not equal to 1, and y is nonzero.
3571
+ def _dpower(xc, xe, yc, ye, p)
3572
+ # Find b such that 10**(b-1) <= |y| <= 10**b
3573
+ b = yc.abs.to_s.length + ye
3574
+
3575
+ # log(x) = lxc*10**(-p-b-1), to p+b+1 places after the decimal point
3576
+ lxc = _dlog(xc, xe, p+b+1)
3577
+
3578
+ # compute product y*log(x) = yc*lxc*10**(-p-b-1+ye) = pc*10**(-p-1)
3579
+ shift = ye-b
3580
+ if shift >= 0
3581
+ pc = lxc*yc*10**shift
3582
+ else
3583
+ pc = _div_nearest(lxc*yc, 10**-shift)
3584
+ end
3585
+
3586
+ if pc == 0
3587
+ # we prefer a result that isn't exactly 1; this makes it
3588
+ # easier to compute a correctly rounded result in __pow__
3589
+ if (xc.to_s.length + xe >= 1) == (yc > 0) # if x**y > 1:
3590
+ coeff, exp = 10**(p-1)+1, 1-p
3591
+ else
3592
+ coeff, exp = 10**p-1, -p
3593
+ end
3594
+ else
3595
+ coeff, exp = _dexp(pc, -(p+1), p+1)
3596
+ coeff = _div_nearest(coeff, 10)
3597
+ exp += 1
3598
+ end
3599
+
3600
+ return coeff, exp
3601
+ end
3602
+
3603
+ # Compute an approximation to exp(c*10**e), with p decimal places of precision.
3604
+ # Returns integers d, f such that:
3605
+ #
3606
+ # 10**(p-1) <= d <= 10**p, and
3607
+ # (d-1)*10**f < exp(c*10**e) < (d+1)*10**f
3608
+ #
3609
+ # In other words, d*10**f is an approximation to exp(c*10**e) with p
3610
+ # digits of precision, and with an error in d of at most 1. This is
3611
+ # almost, but not quite, the same as the error being < 1ulp: when d
3612
+ # = 10**(p-1) the error could be up to 10 ulp.
3613
+ def _dexp(c, e, p)
3614
+ # we'll call iexp with M = 10**(p+2), giving p+3 digits of precision
3615
+ p += 2
3616
+
3617
+ # compute log(10) with extra precision = adjusted exponent of c*10**e
3618
+ extra = [0, e + c.to_s.length - 1].max
3619
+ q = p + extra
3620
+
3621
+ # compute quotient c*10**e/(log(10)) = c*10**(e+q)/(log(10)*10**q),
3622
+ # rounding down
3623
+ shift = e+q
3624
+ if shift >= 0
3625
+ cshift = c*10**shift
3626
+ else
3627
+ cshift = c/10**-shift
3628
+ end
3629
+ quot, rem = cshift.divmod(_log10_digits(q))
3630
+
3631
+ # reduce remainder back to original precision
3632
+ rem = _div_nearest(rem, 10**extra)
3633
+
3634
+ # error in result of _iexp < 120; error after division < 0.62
3635
+ return _div_nearest(_iexp(rem, 10**p), 1000), quot - p + 3
3636
+ end
3637
+
3638
+ # Closest integer to a/b, a and b positive integers; rounds to even
3639
+ # in the case of a tie.
3640
+ def _div_nearest(a, b)
3641
+ q, r = a.divmod(b)
3642
+ q + (((2*r + (q&1)) > b) ? 1 : 0)
3643
+ end
3644
+
3645
+ # Closest integer to the square root of the positive integer n. a is
3646
+ # an initial approximation to the square root. Any positive integer
3647
+ # will do for a, but the closer a is to the square root of n the
3648
+ # faster convergence will be.
3649
+ def _sqrt_nearest(n, a)
3650
+
3651
+ if n <= 0 or a <= 0
3652
+ raise ArgumentError, "Both arguments to _sqrt_nearest should be positive."
3653
+ end
3654
+
3655
+ b=0
3656
+ while a != b
3657
+ b, a = a, a--n/a>>1 # ??
3658
+ end
3659
+ return a
3660
+ end
3661
+
3662
+ # Given an integer x and a nonnegative integer shift, return closest
3663
+ # integer to x / 2**shift; use round-to-even in case of a tie.
3664
+ def _rshift_nearest(x, shift)
3665
+ b, q = (1 << shift), (x >> shift)
3666
+ return q + (((2*(x & (b-1)) + (q&1)) > b) ? 1 : 0)
3667
+ #return q + (2*(x & (b-1)) + (((q&1) > b) ? 1 : 0))
3668
+ end
3669
+
3670
+ # Integer approximation to M*log(x/M), with absolute error boundable
3671
+ # in terms only of x/M.
3672
+ #
3673
+ # Given positive integers x and M, return an integer approximation to
3674
+ # M * log(x/M). For L = 8 and 0.1 <= x/M <= 10 the difference
3675
+ # between the approximation and the exact result is at most 22. For
3676
+ # L = 8 and 1.0 <= x/M <= 10.0 the difference is at most 15. In
3677
+ # both cases these are upper bounds on the error; it will usually be
3678
+ # much smaller.
3679
+ def _ilog(x, m, l = 8)
3680
+ # The basic algorithm is the following: let log1p be the function
3681
+ # log1p(x) = log(1+x). Then log(x/M) = log1p((x-M)/M). We use
3682
+ # the reduction
3683
+ #
3684
+ # log1p(y) = 2*log1p(y/(1+sqrt(1+y)))
3685
+ #
3686
+ # repeatedly until the argument to log1p is small (< 2**-L in
3687
+ # absolute value). For small y we can use the Taylor series
3688
+ # expansion
3689
+ #
3690
+ # log1p(y) ~ y - y**2/2 + y**3/3 - ... - (-y)**T/T
3691
+ #
3692
+ # truncating at T such that y**T is small enough. The whole
3693
+ # computation is carried out in a form of fixed-point arithmetic,
3694
+ # with a real number z being represented by an integer
3695
+ # approximation to z*M. To avoid loss of precision, the y below
3696
+ # is actually an integer approximation to 2**R*y*M, where R is the
3697
+ # number of reductions performed so far.
3698
+
3699
+ y = x-m
3700
+ # argument reduction; R = number of reductions performed
3701
+ r = 0
3702
+ # while (r <= l && y.abs << l-r >= m ||
3703
+ # r > l and y.abs>> r-l >= m)
3704
+ while (((r <= l) && ((y.abs << (l-r)) >= m)) ||
3705
+ ((r > l) && ((y.abs>>(r-l)) >= m)))
3706
+ y = _div_nearest((m*y) << 1,
3707
+ m + _sqrt_nearest(m*(m+_rshift_nearest(y, r)), m))
3708
+ r += 1
3709
+ end
3710
+
3711
+ # Taylor series with T terms
3712
+ t = -(-10*m.to_s.length/(3*l)).to_i
3713
+ yshift = _rshift_nearest(y, r)
3714
+ w = _div_nearest(m, t)
3715
+ # (1...t).reverse_each do |k| # Ruby 1.9
3716
+ (1...t).to_a.reverse.each do |k|
3717
+ w = _div_nearest(m, k) - _div_nearest(yshift*w, m)
3718
+ end
3719
+
3720
+ return _div_nearest(w*y, m)
3721
+ end
3722
+
3723
+ # Given integers c, e and p with c > 0, p >= 0, compute an integer
3724
+ # approximation to 10**p * log10(c*10**e), with an absolute error of
3725
+ # at most 1. Assumes that c*10**e is not exactly 1.
3726
+ def _dlog10(c, e, p)
3727
+ # increase precision by 2; compensate for this by dividing
3728
+ # final result by 100
3729
+ p += 2
3730
+
3731
+ # write c*10**e as d*10**f with either:
3732
+ # f >= 0 and 1 <= d <= 10, or
3733
+ # f <= 0 and 0.1 <= d <= 1.
3734
+ # Thus for c*10**e close to 1, f = 0
3735
+ l = c.to_s.length
3736
+ f = e+l - ((e+l >= 1) ? 1 : 0)
3737
+
3738
+ if p > 0
3739
+ m = 10**p
3740
+ k = e+p-f
3741
+ if k >= 0
3742
+ c *= 10**k
3743
+ else
3744
+ c = _div_nearest(c, 10**-k)
3745
+ end
3746
+ log_d = _ilog(c, m) # error < 5 + 22 = 27
3747
+ log_10 = _log10_digits(p) # error < 1
3748
+ log_d = _div_nearest(log_d*m, log_10)
3749
+ log_tenpower = f*m # exact
3750
+ else
3751
+ log_d = 0 # error < 2.31
3752
+ log_tenpower = _div_nearest(f, 10**-p) # error < 0.5
3753
+ end
3754
+
3755
+ return _div_nearest(log_tenpower+log_d, 100)
3756
+ end
3757
+
3758
+ # Compute a lower bound for 100*log10(c) for a positive integer c.
3759
+ def _log10_lb(c, correction = {
3760
+ '1'=> 100, '2'=> 70, '3'=> 53, '4'=> 40, '5'=> 31,
3761
+ '6'=> 23, '7'=> 16, '8'=> 10, '9'=> 5})
3762
+ raise ArgumentError, "The argument to _log10_lb should be nonnegative." if c <= 0
3763
+ str_c = c.to_s
3764
+ return 100*str_c.length - correction[str_c[0,1]]
3765
+ end
3766
+
3767
+ # Given integers c, e and p with c > 0, compute an integer
3768
+ # approximation to 10**p * log(c*10**e), with an absolute error of
3769
+ # at most 1. Assumes that c*10**e is not exactly 1.
3770
+ def _dlog(c, e, p)
3771
+
3772
+ # Increase precision by 2. The precision increase is compensated
3773
+ # for at the end with a division by 100.
3774
+ p += 2
3775
+
3776
+ # rewrite c*10**e as d*10**f with either f >= 0 and 1 <= d <= 10,
3777
+ # or f <= 0 and 0.1 <= d <= 1. Then we can compute 10**p * log(c*10**e)
3778
+ # as 10**p * log(d) + 10**p*f * log(10).
3779
+ l = c.to_s.length
3780
+ f = e+l - ((e+l >= 1) ? 1 : 0)
3781
+
3782
+ # compute approximation to 10**p*log(d), with error < 27
3783
+ if p > 0
3784
+ k = e+p-f
3785
+ if k >= 0
3786
+ c *= 10**k
3787
+ else
3788
+ c = _div_nearest(c, 10**-k) # error of <= 0.5 in c
3789
+ end
3790
+
3791
+ # _ilog magnifies existing error in c by a factor of at most 10
3792
+ log_d = _ilog(c, 10**p) # error < 5 + 22 = 27
3793
+ else
3794
+ # p <= 0: just approximate the whole thing by 0; error < 2.31
3795
+ log_d = 0
3796
+ end
3797
+
3798
+ # compute approximation to f*10**p*log(10), with error < 11.
3799
+ if f
3800
+ extra = f.abs.to_s.length - 1
3801
+ if p + extra >= 0
3802
+ # error in f * _log10_digits(p+extra) < |f| * 1 = |f|
3803
+ # after division, error < |f|/10**extra + 0.5 < 10 + 0.5 < 11
3804
+ f_log_ten = _div_nearest(f*_log10_digits(p+extra), 10**extra)
3805
+ else
3806
+ f_log_ten = 0
3807
+ end
3808
+ else
3809
+ f_log_ten = 0
3810
+ end
3811
+
3812
+ # error in sum < 11+27 = 38; error after division < 0.38 + 0.5 < 1
3813
+ return _div_nearest(f_log_ten + log_d, 100)
3814
+ end
3815
+
3816
+ # Given integers x and M, M > 0, such that x/M is small in absolute
3817
+ # value, compute an integer approximation to M*exp(x/M). For 0 <=
3818
+ # x/M <= 2.4, the absolute error in the result is bounded by 60 (and
3819
+ # is usually much smaller).
3820
+ def _iexp(x, m, l=8)
3821
+
3822
+ # Algorithm: to compute exp(z) for a real number z, first divide z
3823
+ # by a suitable power R of 2 so that |z/2**R| < 2**-L. Then
3824
+ # compute expm1(z/2**R) = exp(z/2**R) - 1 using the usual Taylor
3825
+ # series
3826
+ #
3827
+ # expm1(x) = x + x**2/2! + x**3/3! + ...
3828
+ #
3829
+ # Now use the identity
3830
+ #
3831
+ # expm1(2x) = expm1(x)*(expm1(x)+2)
3832
+ #
3833
+ # R times to compute the sequence expm1(z/2**R),
3834
+ # expm1(z/2**(R-1)), ... , exp(z/2), exp(z).
3835
+
3836
+ # Find R such that x/2**R/M <= 2**-L
3837
+ r = _nbits((x<<l)/m)
3838
+
3839
+ # Taylor series. (2**L)**T > M
3840
+ t = -(-10*m.to_s.length/(3*l)).to_i
3841
+ y = _div_nearest(x, t)
3842
+ mshift = m<<r
3843
+ (1...t).to_a.reverse.each do |i|
3844
+ y = _div_nearest(x*(mshift + y), mshift * i)
3845
+ end
3846
+
3847
+ # Expansion
3848
+ (0...r).to_a.reverse.each do |k|
3849
+ mshift = m<<(k+2)
3850
+ y = _div_nearest(y*(y+mshift), mshift)
3851
+ end
3852
+
3853
+ return m+y
3854
+ end
3855
+
3856
+ # We'll memoize the digits of log(10):
3857
+ @log10_digits = "23025850929940456840179914546843642076011014886"
3858
+ class <<self
3859
+ attr_accessor :log10_digits
3860
+ end
3861
+
3862
+ # Given an integer p >= 0, return floor(10**p)*log(10).
3863
+ def _log10_digits(p)
3864
+ # digits are stored as a string, for quick conversion to
3865
+ # integer in the case that we've already computed enough
3866
+ # digits; the stored digits should always be correct
3867
+ # (truncated, not rounded to nearest).
3868
+ raise ArgumentError, "p should be nonnegative" if p<0
3869
+ if p >= AuxiliarFunctions.log10_digits.length
3870
+ digits = nil
3871
+ # compute p+3, p+6, p+9, ... digits; continue until at
3872
+ # least one of the extra digits is nonzero
3873
+ extra = 3
3874
+ loop do
3875
+ # compute p+extra digits, correct to within 1ulp
3876
+ m = 10**(p+extra+2)
3877
+ digits = _div_nearest(_ilog(10*m, m), 100).to_s
3878
+ break if digits[-extra..-1] != '0'*extra
3879
+ extra += 3
3880
+ end
3881
+ # keep all reliable digits so far; remove trailing zeros
3882
+ # and next nonzero digit
3883
+ AuxiliarFunctions.log10_digits = digits.sub(/0*$/,'')[0...-1]
3884
+ end
3885
+ return (AuxiliarFunctions.log10_digits[0...p+1]).to_i
3886
+ end
3887
+
3888
+ # Compute an approximation to exp(c*10**e), with p decimal places of
3889
+ # precision.
3890
+ #
3891
+ # Returns integers d, f such that:
3892
+ #
3893
+ # 10**(p-1) <= d <= 10**p, and
3894
+ # (d-1)*10**f < exp(c*10**e) < (d+1)*10**f
3895
+ #
3896
+ # In other words, d*10**f is an approximation to exp(c*10**e) with p
3897
+ # digits of precision, and with an error in d of at most 1. This is
3898
+ # almost, but not quite, the same as the error being < 1ulp: when d
3899
+ # = 10**(p-1) the error could be up to 10 ulp.
3900
+ def dexp(c, e, p)
3901
+ # we'll call iexp with M = 10**(p+2), giving p+3 digits of precision
3902
+ p += 2
3903
+
3904
+ # compute log(10) with extra precision = adjusted exponent of c*10**e
3905
+ extra = [0, e + c.to_s.length - 1].max
3906
+ q = p + extra
3907
+
3908
+ # compute quotient c*10**e/(log(10)) = c*10**(e+q)/(log(10)*10**q),
3909
+ # rounding down
3910
+ shift = e+q
3911
+ if shift >= 0
3912
+ cshift = c*10**shift
3913
+ else
3914
+ cshift = c/10**-shift
3915
+ end
3916
+ quot, rem = cshift.divmod(_log10_digits(q))
3917
+
3918
+ # reduce remainder back to original precision
3919
+ rem = _div_nearest(rem, 10**extra)
3920
+
3921
+ # error in result of _iexp < 120; error after division < 0.62
3922
+ return _div_nearest(_iexp(rem, 10**p), 1000), quot - p + 3
3923
+ end
3924
+
3925
+ end # AuxiliarFunctions
3926
+
3927
+ # This is for using auxiliar functions from Decimal instance method
3928
+ # without the "AuxiliarFunctions." prefix
3929
+ include AuxiliarFunctions
3930
+ # If we need to use them from Decimal class methods, we can avoid
3931
+ # the use of the prefix with:
3932
+ # extend AuxiliarFunctions
3933
+
2740
3934
  end
2741
3935
 
2742
3936
  # Decimal constructor. See Decimal#new for the parameters.