long-decimal 0.02.01 → 1.00.01

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.
@@ -7,8 +7,8 @@
7
7
  # additional functionality, mostly transcendental functions,
8
8
  # may be found in long-decimal-extra.rb
9
9
  #
10
- # CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $
11
- # CVS-Label: $Name: BETA_02_01 $
10
+ # CVS-ID: $Header: /var/cvs/long-decimal/long-decimal/lib/long-decimal.rb,v 1.86 2011/01/23 20:55:32 bk1 Exp $
11
+ # CVS-Label: $Name: RELEASE_1_00_01 $
12
12
  # Author: $Author: bk1 $ (Karl Brodowsky)
13
13
  #
14
14
 
@@ -22,7 +22,7 @@ BYTE_SIZE_OF_ONE = 1.size
22
22
 
23
23
  #
24
24
  # define rounding modes to be used for LongDecimal
25
- # this serves the purpose of an "enum" in C/C++
25
+ # this serves the purpose of an "enum" in C/C++/Java
26
26
  #
27
27
  module LongDecimalRoundingMode
28
28
 
@@ -83,6 +83,7 @@ module LongDecimalRoundingMode
83
83
  ROUND_HALF_EVEN = RoundingModeClass.new(:ROUND_HALF_EVEN, 8)
84
84
  ROUND_UNNECESSARY = RoundingModeClass.new(:ROUND_UNNECESSARY, 9)
85
85
 
86
+ # which mode is to be used instead when we do an multiplicative inversion?
86
87
  MUL_INVERSE_MODE = {
87
88
  ROUND_UP => ROUND_DOWN,
88
89
  ROUND_DOWN => ROUND_UP,
@@ -96,6 +97,7 @@ module LongDecimalRoundingMode
96
97
  ROUND_UNNECESSARY => ROUND_UNNECESSARY
97
98
  }
98
99
 
100
+ # which mode is to be used instead when we do an additive inversion?
99
101
  ADD_INVERSE_MODE = {
100
102
  ROUND_UP => ROUND_UP,
101
103
  ROUND_DOWN => ROUND_DOWN,
@@ -159,6 +161,7 @@ if (RUBY_PLATFORM == 'java')
159
161
 
160
162
  alias :mul :*
161
163
 
164
+ # fix multiplication
162
165
  def *(y)
163
166
  if (self == 0 || y == 0)
164
167
  return self.mul(y)
@@ -262,17 +265,17 @@ class Integer
262
265
  upper = self + (r_upper - r_self)
263
266
 
264
267
  unless (lower < self && self < upper)
265
- raise Error, "self=#{self} not in (#{lower}, #{upper})"
268
+ raise ArgumentError, "self=#{self} not in (#{lower}, #{upper})"
266
269
  end
267
270
  if (rounding_mode == LongDecimalRoundingMode::ROUND_UNNECESSARY) then
268
271
  raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, self=#{self.to_s} is in open interval (#{lower}, #{upper})"
269
272
  end
270
273
 
271
- # if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then
272
- # return lower
273
- # elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
274
- # return upper
275
- # end
274
+ # if (rounding_mode == LongDecimalRoundingMode::ROUND_FLOOR) then
275
+ # return lower
276
+ # elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
277
+ # return upper
278
+ # end
276
279
 
277
280
  sign_self = self.sign
278
281
  if (sign_self == 0) then
@@ -292,14 +295,14 @@ class Integer
292
295
  elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_CLOSEST_PREFER_MINUS) then
293
296
  return lower
294
297
  else
295
- raise Error, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
298
+ raise ArgumentError, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
296
299
  end
297
300
  elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_PLUS) then
298
301
  return upper
299
302
  elsif (zero_rounding_mode == LongDecimalRoundingMode::ZERO_ROUND_TO_MINUS) then
300
303
  return lower
301
304
  else
302
- raise Error, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
305
+ raise ArgumentError, "this case can never happen: zero_rounding_mode=#{zero_rounding_mode}"
303
306
  end
304
307
  end
305
308
  end
@@ -332,7 +335,7 @@ class Integer
332
335
  elsif (rounding_mode == LongDecimalRoundingMode::ROUND_HALF_CEILING) then
333
336
  rounding_mode = LongDecimalRoundingMode::ROUND_CEILING
334
337
  else
335
- raise Error, "this case can never happen: rounding_mode=#{rounding_mode}"
338
+ raise ArgumentError, "this case can never happen: rounding_mode=#{rounding_mode}"
336
339
  end
337
340
  end
338
341
 
@@ -341,7 +344,7 @@ class Integer
341
344
  elsif (rounding_mode == LongDecimalRoundingMode::ROUND_CEILING) then
342
345
  return upper
343
346
  else
344
- raise Error, "this case can never happen: rounding_mode=#{rounding_mode}"
347
+ raise ArgumentError, "this case can never happen: rounding_mode=#{rounding_mode}"
345
348
  end
346
349
  end
347
350
  end
@@ -350,7 +353,10 @@ end
350
353
  # common base class for LongDecimal and LongDecimalQuot
351
354
  #
352
355
  class LongDecimalBase < Numeric
353
- @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
356
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.86 2011/01/23 20:55:32 bk1 Exp $-'
357
+
358
+ # allow easy check if running with version 1.9
359
+ RUNNING_19 = RUBY_VERSION.match /^1\.9/
354
360
 
355
361
  include LongDecimalRoundingMode
356
362
 
@@ -457,6 +463,118 @@ class LongDecimalBase < Numeric
457
463
  scale_ufo(other).zero?
458
464
  end
459
465
 
466
+ private
467
+
468
+ #
469
+ # helper method for round_to_scale
470
+ #
471
+ def round_to_scale_helper(dividend, divisor, new_scale, mode)
472
+
473
+ sign_quot = dividend <=> 0
474
+ if sign_quot == 0 then
475
+ # finish zero without long calculations at once
476
+ return LongDecimal(0, new_scale)
477
+ end
478
+
479
+ divisor = divisor
480
+ quot, rem = dividend.divmod(divisor)
481
+ sign_rem = rem <=> 0
482
+ if (sign_rem == 0)
483
+ # if self can be expressed without loss as LongDecimal with
484
+ # new_scale digits after the decimal point, just do it.
485
+ return LongDecimal(quot, new_scale)
486
+ end
487
+
488
+ # we do not expect negative signs of remainder. To make sure that
489
+ # this does not cause problems in further code, we just throw an
490
+ # exception. This should never happen (and did not happen during
491
+ # testing).
492
+ raise ArgumentError, "signs do not match self=#{self.to_s} f=#{factor} dividend=#{dividend} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem <= 0
493
+
494
+ if (sign_quot < 0) then
495
+ # handle negative sign of self
496
+ rem -= divisor
497
+ quot += 1
498
+ sign_rem = rem <=> 0
499
+ raise ArgumentError, "signs do not match self=#{self.to_s} f=#{factor} dividend=#{dividend} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem >= 0
500
+ end
501
+
502
+ if mode == ROUND_UNNECESSARY then
503
+ # this mode means that rounding should not be necessary. But
504
+ # the case that no rounding is needed, has already been covered
505
+ # above, so it is an error, if this mode is required and the
506
+ # result could not be returned above.
507
+ raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
508
+ end
509
+
510
+ if (mode == ROUND_CEILING)
511
+ # ROUND_CEILING goes to the closest allowed number >= self, even
512
+ # for negative numbers. Since sign is handled separately, it is
513
+ # more conveniant to use ROUND_UP or ROUND_DOWN depending on the
514
+ # sign.
515
+ mode = (sign_quot > 0) ? ROUND_UP : ROUND_DOWN
516
+
517
+ elsif (mode == ROUND_FLOOR)
518
+ # ROUND_FLOOR goes to the closest allowed number <= self, even
519
+ # for negative numbers. Since sign is handled separately, it is
520
+ # more conveniant to use ROUND_UP or ROUND_DOWN depending on the
521
+ # sign.
522
+ mode = (sign_quot < 0) ? ROUND_UP : ROUND_DOWN
523
+
524
+ else
525
+
526
+ if (mode == ROUND_HALF_CEILING)
527
+ # ROUND_HALF_CEILING goes to the closest allowed number >= self, even
528
+ # for negative numbers. Since sign is handled separately, it is
529
+ # more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
530
+ # sign.
531
+ mode = (sign_quot > 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
532
+
533
+ elsif (mode == ROUND_HALF_FLOOR)
534
+ # ROUND_HALF_FLOOR goes to the closest allowed number <= self, even
535
+ # for negative numbers. Since sign is handled separately, it is
536
+ # more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
537
+ # sign.
538
+ mode = (sign_quot < 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
539
+
540
+ end
541
+
542
+ # handle the ROUND_HALF_... stuff and find the adequate ROUND_UP
543
+ # or ROUND_DOWN to use
544
+ abs_rem = rem.abs
545
+ half = (abs_rem << 1) <=> divisor
546
+ if (mode == ROUND_HALF_UP || mode == ROUND_HALF_DOWN || mode == ROUND_HALF_EVEN) then
547
+ if (half < 0) then
548
+ mode = ROUND_DOWN
549
+ elsif half > 0 then
550
+ mode = ROUND_UP
551
+ else
552
+ # half == 0
553
+ if (mode == ROUND_HALF_UP) then
554
+ mode = ROUND_UP
555
+ elsif (mode == ROUND_HALF_DOWN) then
556
+ mode = ROUND_DOWN
557
+ else
558
+ # mode == ROUND_HALF_EVEN
559
+ mode = (quot[0] == 1 ? ROUND_UP : ROUND_DOWN)
560
+ end
561
+ end
562
+ end
563
+ end
564
+
565
+ if mode == ROUND_UP
566
+ # since the case where we can express the result exactly without
567
+ # loss has already been handled above, ROUND_UP can be handled
568
+ # correctly by adding one unit.
569
+ quot += sign_quot
570
+ end
571
+
572
+ # put together result
573
+ new_int_val = quot
574
+ LongDecimal(new_int_val, new_scale)
575
+
576
+ end
577
+
460
578
  end # class LongDecimalBase
461
579
 
462
580
  #
@@ -465,7 +583,7 @@ end # class LongDecimalBase
465
583
  # digits and the other one the position of the decimal point.
466
584
  #
467
585
  class LongDecimal < LongDecimalBase
468
- @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
586
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.86 2011/01/23 20:55:32 bk1 Exp $-'
469
587
 
470
588
  # MINUS_ONE = LongDecimal(-1)
471
589
  # ZERO = LongDecimal(0)
@@ -499,7 +617,7 @@ class LongDecimal < LongDecimalBase
499
617
  # digits after the decimal point (scale=s)
500
618
  #
501
619
  def LongDecimal.one!(s = 0)
502
- new(10**s, s)
620
+ new(LongMath.npower10(s), s)
503
621
  end
504
622
 
505
623
 
@@ -508,7 +626,7 @@ class LongDecimal < LongDecimalBase
508
626
  # digits after the decimal point (scale=s)
509
627
  #
510
628
  def LongDecimal.two!(s = 0)
511
- new(2*10**s, s)
629
+ new(2*LongMath.npower10(s), s)
512
630
  end
513
631
 
514
632
 
@@ -517,7 +635,7 @@ class LongDecimal < LongDecimalBase
517
635
  # digits after the decimal point (scale=s)
518
636
  #
519
637
  def LongDecimal.ten!(s = 0)
520
- new(10**(s+1), s)
638
+ new(LongMath.npower10(s+1), s)
521
639
  end
522
640
 
523
641
  #
@@ -525,7 +643,7 @@ class LongDecimal < LongDecimalBase
525
643
  # digits after the decimal point (scale=s)
526
644
  #
527
645
  def LongDecimal.half!(s = 1)
528
- new(5*10**(s-1), s)
646
+ new(5 * LongMath.npower10(s-1), s)
529
647
  end
530
648
 
531
649
 
@@ -534,7 +652,7 @@ class LongDecimal < LongDecimalBase
534
652
  # digits after the decimal point (scale=s)
535
653
  #
536
654
  def LongDecimal.minus_one!(s = 0)
537
- new(-1*10**s, s)
655
+ new(-1*LongMath.npower10(s), s)
538
656
  end
539
657
 
540
658
 
@@ -546,15 +664,15 @@ class LongDecimal < LongDecimalBase
546
664
  def LongDecimal.power_of_ten!(e, s = 0)
547
665
  LongMath.check_is_int(e, "e")
548
666
  raise TypeError, "negative 1st arg \"#{e.inspect}\"" if e < 0
549
- new(10**(s+e), s)
667
+ new(LongMath.npower10(s+e), s)
550
668
  end
551
669
 
552
670
  #
553
671
  # needed for clone()
554
672
  #
555
673
  def initialize_copy(x)
556
- @int_val = x.int_val
557
- @scale = x.scale
674
+ @int_val = x.int_val
675
+ @scale = x.scale
558
676
  end
559
677
 
560
678
  #
@@ -572,8 +690,9 @@ class LongDecimal < LongDecimalBase
572
690
  raise TypeError, "complex numbers not supported \"#{x.inspect}\"" if x.kind_of? Complex
573
691
 
574
692
  # handle some obvious errors with optional second parameter, if present
575
- raise TypeError, "non integer 2nd arg \"#{s.inspect}\"" if ! s.kind_of? Integer
576
- raise TypeError, "negative 2nd arg \"#{s.inspect}\"" if s < 0
693
+ LongMath.check_is_prec(s, "scale", :raise_error)
694
+ # raise TypeError, "non integer 2nd arg \"#{s.inspect}\"" if ! s.kind_of? Integer
695
+ # raise TypeError, "negative 2nd arg \"#{s.inspect}\"" if s < 0
577
696
 
578
697
  # scale is the second parameter or 0 if it is missing
579
698
  scale = s
@@ -597,7 +716,7 @@ class LongDecimal < LongDecimalBase
597
716
  denom /= 5 ** mul_5
598
717
  iscale2 = Math.log10(denom).ceil
599
718
  scale += iscale2
600
- int_val = (x * 10 ** (iscale2+iscale)).to_i
719
+ int_val = (x * LongMath.npower10(iscale2+iscale)).to_i
601
720
 
602
721
  else
603
722
  # we assume a string or a floating point number
@@ -686,7 +805,7 @@ class LongDecimal < LongDecimalBase
686
805
  # multiply int_val by a power of 10 in order to compensate for
687
806
  # the change of scale and to keep number in the same order of magnitude.
688
807
  d = s - @scale
689
- f = 10 ** (d.abs)
808
+ f = LongMath.npower10(d.abs)
690
809
  if (d >= 0) then
691
810
  @int_val = (@int_val * f).to_i
692
811
  else
@@ -724,28 +843,20 @@ class LongDecimal < LongDecimalBase
724
843
  #
725
844
  def round_to_scale(new_scale, mode = ROUND_UNNECESSARY)
726
845
 
727
- raise TypeError, "new_scale #{new_scale.inspect} must be integer" unless new_scale.kind_of? Integer
728
- raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
846
+ new_scale = LongMath.check_is_prec(new_scale)
729
847
  raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
730
848
  if @scale == new_scale then
731
849
  self
732
850
  else
733
851
  diff = new_scale - scale
734
- factor = 10 ** (diff.abs)
852
+ factor = LongMath.npower10(diff.abs)
735
853
  if (diff > 0) then
736
854
  # we become more precise, no rounding issues
737
855
  new_int_val = int_val * factor
856
+ return LongDecimal(new_int_val, new_scale)
738
857
  else
739
- quot, rem = int_val.divmod(factor)
740
- if (rem == 0) then
741
- new_int_val = quot
742
- elsif (mode == ROUND_UNNECESSARY) then
743
- raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
744
- else
745
- return LongDecimalQuot(self, LongDecimal(1)).round_to_scale(new_scale, mode)
746
- end
858
+ return round_to_scale_helper(int_val, factor, new_scale, mode)
747
859
  end
748
- LongDecimal(new_int_val, new_scale)
749
860
  end
750
861
  end
751
862
 
@@ -789,7 +900,7 @@ class LongDecimal < LongDecimalBase
789
900
  expanded = self.round_to_scale(new_scale, rounding_mode)
790
901
  return expanded.round_to_allowed_remainders(new_scale, remainders, modulus, rounding_mode, zero_rounding_mode)
791
902
  elsif @scale > new_scale
792
- factor = 10**(@scale - new_scale)
903
+ factor = LongMath.npower10(@scale - new_scale)
793
904
  remainders = remainders.collect do |r|
794
905
  r * factor
795
906
  end
@@ -828,7 +939,7 @@ class LongDecimal < LongDecimalBase
828
939
  unless (base.kind_of? Integer) && 2 <= base && base <= 36 then
829
940
  raise TypeError, "base must be integer between 2 and 36"
830
941
  end
831
- quot = (self.move_point_right(scale) * base ** shown_scale) / 10 ** scale
942
+ quot = (self.move_point_right(scale) * base ** shown_scale) / LongMath.npower10(scale)
832
943
  rounded = quot.round_to_scale(0, mode)
833
944
  rounded.to_s_internal(base, shown_scale)
834
945
  end
@@ -870,54 +981,164 @@ class LongDecimal < LongDecimalBase
870
981
  # within the ranges expressable as Floats. Goes via string
871
982
  # representation otherwise.
872
983
  #
984
+ # to_f has to consider the following cases:
985
+ # if 10**scale or int_val > MAX_FLOATABLE, divide by an adequate power of 10 to reach the ranges, where the conversion below works.
986
+ # if 10**scale and int_val both < MAX_FLOATABLE, use lookup for float-representation 1/10**scale -> int_val.to_f * (1/10**scale)
987
+ # special care has to be taken for the "border cases".
988
+ #
873
989
  def to_f
990
+
991
+ # result 0.0 if int_val == 0
992
+ if (int_val == 0)
993
+ # t1
994
+ # puts "t1 #{self.to_s}=#{self.inspect} -> 0.0"
995
+ return 0.0
996
+ end
997
+
998
+ if (scale == 0)
999
+ if (int_val.abs <= LongMath::MAX_FLOATABLE)
1000
+ y = int_val.to_f
1001
+ # t2
1002
+ # puts "t2 #{self.to_s}=#{self.inspect} -> #{y}"
1003
+ return y
1004
+ elsif int_val < 0
1005
+ # t13
1006
+ # puts "t13 #{self.to_s}=#{self.inspect} -> -Infinity"
1007
+ return -1.0/0.0
1008
+ elsif int_val > 0
1009
+ # t14
1010
+ # puts "t13 #{self.to_s}=#{self.inspect} -> Infinity"
1011
+ return 1.0/0.0
1012
+ end
1013
+ end
1014
+
1015
+ # negative: can be handled by doing to_f of the absolute value and negating the result.
1016
+ if (self < 0) then
1017
+ y = -(-self).to_f
1018
+ # t3
1019
+ # puts "t3 #{self.to_s}=#{self.inspect} -> #{y}"
1020
+ return y
1021
+ end
1022
+
1023
+ # handle the usual case first, avoiding expensive calculations
1024
+ if (int_val <= LongMath::MAX_FLOATABLE && scale <= Float::MAX_10_EXP)
1025
+ y = to_f_simple(int_val, scale)
1026
+ # t4
1027
+ # puts "t4 #{self.to_s}=#{self.inspect} -> #{y}"
1028
+ return y
1029
+ end
1030
+
1031
+ divisor = denominator
1032
+
1033
+ # result NaN if int_val > MAX_FLOATABLE * 10**scale
874
1034
  # handle overflow: raise exception
875
- if (self.abs > LongMath::MAX_FLOATABLE) then
876
- raise ArgumentError, "self=#{self.inspect} cannot be expressed as Float"
1035
+ if (int_val > divisor * LongMath::MAX_FLOATABLE) then
1036
+ # t5
1037
+ # puts "t5 #{self.to_s}=#{self.inspect} -> Infinity"
1038
+ return 1/0.0 # Infinity
877
1039
  end
878
1040
 
1041
+ # result 0.0 if int_val * MAX_FLOATABLE < 10**scale
879
1042
  # handle underflow: return 0.0
880
- if (self.abs < LongMath::MIN_FLOATABLE) then
1043
+ if (int_val * LongMath::INV_MIN_FLOATABLE * 20 < divisor) then
1044
+ # t6
1045
+ # puts "t6 #{self.to_s}=#{self.inspect} -> 0.0"
1046
+ p = int_val * LongMath::INV_MIN_FLOATABLE * 20
1047
+ d = divisor
1048
+ n = int_val
881
1049
  return 0.0
882
1050
  end
883
1051
 
884
- if (self < 0) then
885
- return -(-self).to_f
1052
+ if int_val <= LongMath::MAX_FLOATABLE then
1053
+ # the case divisor <= LongMath::MAX_FLOATABLE has been dealt with above already.
1054
+ # ==> denominator > LongMath::MAX_FLOATABLE is true
1055
+ # the case self < LongMath::MIN_FLOATABLE has been handed above
1056
+ # int_val beeing < LongMath::MAX_FLOATABLE we know that qe < 2 * Float::MAX_10_EXP
1057
+ y = int_val.to_f
1058
+ s = scale
1059
+ while (s > 0)
1060
+ qe = [ s, Float::MAX_10_EXP ].min
1061
+ q = LongMath.neg_float_npower10(qe)
1062
+ y *= q
1063
+ if (y == 0.0)
1064
+ # t7
1065
+ # puts "t7 #{self.to_s}=#{self.inspect} -> #{y}"
1066
+ return y
1067
+ end
1068
+ s -= qe
1069
+ end
1070
+ # t8
1071
+ # puts "t8 #{self.to_s}=#{self.inspect} -> #{y}"
1072
+ return y
1073
+ end
1074
+
1075
+ # we can now assume that int_val > LongMath::MAX_FLOATABLE, but not self > LongMath::MAX_FLOATABLE
1076
+ # so rounding should help.
1077
+ # we need to retain some 16 digits to be safely when going via integer
1078
+ if int_val >= LongMath::FLOATABLE_WITHOUT_FRACTION * divisor
1079
+ $stdout.flush
1080
+ rounded_ld = round_to_scale(0, ROUND_HALF_UP)
1081
+ # scale = 0, 0 < int_val <= MAX_FLOATABLE
1082
+ y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
1083
+ # t9
1084
+ # puts "t9 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} -> #{y}"
1085
+ return y
886
1086
  end
887
1087
 
888
- dividend = numerator
889
- divisor = denominator
1088
+ # we need to retain some digits after the decimal point
1089
+ # it can be assumed that self < LongMath::FLOATABLE_WITHOUT_FRACTION, so retaining some digits is necessary
890
1090
 
891
- if (divisor == 1) then
892
- return dividend.to_f
893
- elsif dividend.abs <= LongMath::MAX_FLOATABLE then
894
- if (divisor.abs > LongMath::MAX_FLOATABLE) then
895
- q = 10**(scale - Float::MAX_10_EXP)
896
- f = (dividend / q).to_f
897
- d = LongMath::MAX_FLOATABLE10
898
- # d = divisor / q
899
- return f / d
900
- else
901
- f = dividend.to_f
902
- return f / divisor
903
- end
904
- elsif dividend.abs < divisor
905
- # self is between -1 and 1
1091
+ cmp = int_val <=> divisor
906
1092
 
907
- # factor = dividend.abs.div(LongMath::MAX_FLOATABLE)
908
- # digits = factor.to_ld.int_digits10
909
- # return LongDecimal(dividend.div(10**digits), scale -digits).to_f
910
- return self.to_s.to_f
1093
+ if (cmp == 0)
1094
+ # t10
1095
+ # puts "t10 #{self.to_s}=#{self.inspect} -> 1.0"
1096
+ return 1.0
1097
+ elsif (cmp > 0)
1098
+ # self > 1, retain MAX_SIGNIFICANT_FLOATABLE_DIGITS
1099
+ rounded_ld = round_to_scale(LongMath::MAX_SIGNIFICANT_FLOATABLE_DIGITS, ROUND_HALF_UP)
1100
+ # self >= LongMath::FLOATABLE_WITHOUT_FRACTION > self > 1, scale = 16,
1101
+ y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
1102
+ # t11
1103
+ # puts "t11 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} -> #{y}"
1104
+ return y
911
1105
  else
912
- q = dividend.abs / divisor
913
- if (q.abs > 1000000000000000000000)
914
- return q.to_f
915
- else
916
- return self.to_s.to_f
917
- end
1106
+ # self < 1
1107
+ # sd <= 0, since self <= 0
1108
+ sd = sint_digits10
1109
+ # add some reserve, to keep room for to_f's rounding
1110
+ reserve = 5
1111
+ # significant_digits = sd + scale
1112
+ # reduction = significant_digits - MAX_SIGNIFICANT_FLOATABLE_DIGITS
1113
+ # new_scale = scale - reduction + reserve
1114
+ # simplifies to the following expression
1115
+ new_scale = LongMath::MAX_SIGNIFICANT_FLOATABLE_DIGITS - sd + reserve
1116
+ rounded_ld = round_to_scale(new_scale, ROUND_HALF_UP)
1117
+ y = to_f_simple(rounded_ld.int_val, rounded_ld.scale)
1118
+ # t12
1119
+ # puts "t12 #{self.to_s}=#{self.inspect} #{rounded_ld.to_s}=#{rounded_ld.inspect} sd=#{sd} #{self <=> 1} -> #{y}"
1120
+ return y
918
1121
  end
919
1122
  end
920
1123
 
1124
+ private
1125
+
1126
+ # private helper method for to_f
1127
+ def to_f_simple(int_val, scale)
1128
+ if (scale > Float::MAX_10_EXP - 10)
1129
+ ds1 = scale >> 1
1130
+ ds2 = scale - ds1
1131
+ f1 = int_val.to_f
1132
+ f2 = LongMath.neg_float_npower10(ds1)
1133
+ f3 = LongMath.neg_float_npower10(ds2)
1134
+ f1 * f2 * f3
1135
+ else
1136
+ int_val.to_f * LongMath.neg_float_npower10(scale)
1137
+ end
1138
+ end
1139
+
1140
+ public
1141
+
921
1142
  #
922
1143
  # convert self into Integer
923
1144
  # This may loose information. In most cases it is preferred to
@@ -942,7 +1163,7 @@ class LongDecimal < LongDecimalBase
942
1163
  end
943
1164
 
944
1165
  #
945
- # convert selt into BigDecimal
1166
+ # convert self into BigDecimal
946
1167
  #
947
1168
  def to_bd
948
1169
  # this operation is probably not used so heavily, so we can live with a
@@ -953,13 +1174,13 @@ class LongDecimal < LongDecimalBase
953
1174
  #
954
1175
  # LongDecimals can be seen as a fraction with a power of 10 as
955
1176
  # denominator for compatibility with other numeric classes this
956
- # method is included, returning 10**scale.
1177
+ # method is included, returning LongMath.npower10(scale).
957
1178
  # Please observe that there may be common factors of numerator and
958
1179
  # denominator in case of LongDecimal, which does not occur in case
959
1180
  # of Rational
960
1181
  #
961
1182
  def denominator
962
- 10**scale
1183
+ LongMath.npower10(scale)
963
1184
  end
964
1185
 
965
1186
  #
@@ -1061,7 +1282,7 @@ class LongDecimal < LongDecimalBase
1061
1282
  o, s = coerce(other)
1062
1283
  if (s.kind_of? LongDecimal) then
1063
1284
  exponent = [s.scale, o.scale].max
1064
- factor = 10**exponent
1285
+ factor = LongMath.npower10(exponent)
1065
1286
  s *= factor
1066
1287
  o *= factor
1067
1288
  s = s.round_to_scale(0)
@@ -1177,7 +1398,15 @@ class LongDecimal < LongDecimalBase
1177
1398
  def *(other)
1178
1399
  o, s = coerce(other)
1179
1400
  if s.kind_of? LongDecimal then
1180
- LongDecimal(s.int_val * o.int_val, s.scale + o.scale)
1401
+ new_scale = s.scale + o.scale
1402
+ prod = s.int_val * o.int_val
1403
+ if (new_scale > LongMath.prec_limit)
1404
+ reduced_scale = LongMath.check_is_prec(new_scale)
1405
+ reduction = new_scale - reduced_scale
1406
+ LongDecimal(prod / LongMath.npower10(reduction), reduced_scale)
1407
+ else
1408
+ LongDecimal(prod, new_scale)
1409
+ end
1181
1410
  else
1182
1411
  s * o
1183
1412
  end
@@ -1267,7 +1496,7 @@ class LongDecimal < LongDecimalBase
1267
1496
  else
1268
1497
  abs_other = -other
1269
1498
  new_scale = abs_other * scale
1270
- LongDecimalQuot(Rational(10 ** new_scale, int_val ** abs_other), new_scale)
1499
+ LongDecimalQuot(Rational(LongMath.npower10(new_scale), int_val ** abs_other), new_scale)
1271
1500
  end
1272
1501
  else
1273
1502
  if (other.kind_of? LongDecimalBase) then
@@ -1336,7 +1565,7 @@ class LongDecimal < LongDecimalBase
1336
1565
  # bitwise inversion
1337
1566
  #
1338
1567
  def ~
1339
- LongDecimal(~int_val, scale)
1568
+ LongDecimal(~int_val, scale)
1340
1569
  end
1341
1570
 
1342
1571
  #
@@ -1413,7 +1642,7 @@ class LongDecimal < LongDecimalBase
1413
1642
  def move_point_right_int(n)
1414
1643
  raise TypeError, "only implemented for Fixnum >= 0" unless n >= 0
1415
1644
  if (n > scale) then
1416
- LongDecimal(int_val * 10**(n-scale), 0)
1645
+ LongDecimal(int_val * LongMath.npower10(n-scale), 0)
1417
1646
  else
1418
1647
  LongDecimal(int_val, scale-n)
1419
1648
  end
@@ -1524,8 +1753,18 @@ class LongDecimal < LongDecimalBase
1524
1753
  # Complex. It need to be observed that this will fail if self
1525
1754
  # has too many digits before the decimal point to be expressed
1526
1755
  # as Float.
1527
- s, o = other.coerce(Complex(self.to_f, 0))
1528
- return o, s
1756
+ # s, o = other.coerce(self.to_f)
1757
+ if (RUNNING_19)
1758
+ s, o = other.coerce(self)
1759
+ # puts "complex coerce 19: #{self}, #{other} -> #{s}, #{o}"
1760
+ return o, s
1761
+ else
1762
+ s, o = other.coerce(Complex(self, 0))
1763
+ # puts "complex coerce 18/J: #{self}, #{other} -> #{s}, #{o}"
1764
+ return o, s
1765
+ end
1766
+ # s, o = other.coerce(Complex(self.to_f, 0))
1767
+ # return o, s
1529
1768
 
1530
1769
  elsif other.kind_of? Numeric then
1531
1770
  # all other go by expressing self as Float and seeing how it
@@ -1543,7 +1782,7 @@ class LongDecimal < LongDecimalBase
1543
1782
  # is self expressable as an integer without loss of digits?
1544
1783
  #
1545
1784
  def is_int?
1546
- scale == 0 || int_val % 10**scale == 0
1785
+ scale == 0 || int_val % LongMath.npower10(scale) == 0
1547
1786
  end
1548
1787
 
1549
1788
  #
@@ -1564,9 +1803,32 @@ class LongDecimal < LongDecimalBase
1564
1803
  # takes into account the values expressed by self and other and the
1565
1804
  # equality of the number of digits.
1566
1805
  #
1806
+ def eql?(other)
1807
+ (other.kind_of? LongDecimal) && (self <=> other) == 0 && self.scale == other.scale
1808
+ end
1809
+
1810
+ #
1811
+ # comparison of self with other for equality
1812
+ # takes into account the values expressed by self
1813
+ #
1567
1814
  def ==(other)
1568
1815
  # (other.kind_of? LongDecimal) && (self <=> other) == 0 && self.scale == other.scale
1569
- (other.kind_of? LongDecimal) && self.int_val == other.int_val && self.scale == other.scale
1816
+ if (other.kind_of? LongDecimal)
1817
+ scale_diff = self.scale - other.scale
1818
+ if (scale_diff == 0)
1819
+ return self.int_val == other.int_val
1820
+ elsif (scale_diff < 0)
1821
+ return self.int_val * LongMath.npower10(-scale_diff) == other.int_val
1822
+ else
1823
+ return self.int_val == other.int_val * LongMath.npower10(scale_diff)
1824
+ end
1825
+ elsif other.kind_of? Integer
1826
+ return self.int_val == other * LongMath.npower10(scale)
1827
+ elsif other.kind_of? Numeric
1828
+ return (self <=> other).zero?
1829
+ else
1830
+ return false
1831
+ end
1570
1832
  end
1571
1833
 
1572
1834
  #
@@ -1618,7 +1880,7 @@ end # LongDecimal
1618
1880
  #
1619
1881
  class LongDecimalQuot < LongDecimalBase
1620
1882
 
1621
- @@RCS_ID='-$Id: long-decimal.rb,v 1.60 2009/04/21 04:27:39 bk1 Exp $-'
1883
+ @@RCS_ID='-$Id: long-decimal.rb,v 1.86 2011/01/23 20:55:32 bk1 Exp $-'
1622
1884
 
1623
1885
  #
1624
1886
  # constructor
@@ -1647,7 +1909,8 @@ class LongDecimalQuot < LongDecimalBase
1647
1909
  #
1648
1910
  def initialize(first, second)
1649
1911
  @digits10 = nil
1650
- if ((first.kind_of? Rational) || (first.kind_of? Integer)) && (second.kind_of? Integer) then
1912
+ if ((first.kind_of? Rational) || (first.kind_of? LongDecimalQuot) || (first.kind_of? Integer)) && (second.kind_of? Integer) then
1913
+ LongMath.check_is_prec(second)
1651
1914
  @rat = Rational(first.numerator, first.denominator)
1652
1915
  @scale = second
1653
1916
 
@@ -1669,6 +1932,9 @@ class LongDecimalQuot < LongDecimalBase
1669
1932
  new_scale = [ 0, 2 * dy + sx + sy - [ dx + sx, dy + sy ].max - 3].max
1670
1933
 
1671
1934
  first, second = first.anti_equalize_scale(second)
1935
+ if (second.zero?)
1936
+ raise ZeroDivisionError, "second=#{second.inspect} must not be zero. (first=#{first.inspect})"
1937
+ end
1672
1938
  @rat = Rational(first.to_i, second.to_i)
1673
1939
  @scale = new_scale
1674
1940
  else
@@ -1723,8 +1989,8 @@ class LongDecimalQuot < LongDecimalBase
1723
1989
  #
1724
1990
  # conversion to BigDecimal
1725
1991
  #
1726
- def to_bd
1727
- to_ld.to_bd
1992
+ def to_bd(prec = scale, mode = LongMath.standard_mode)
1993
+ to_ld(prec, mode).to_bd
1728
1994
  end
1729
1995
 
1730
1996
  #
@@ -1830,6 +2096,7 @@ class LongDecimalQuot < LongDecimalBase
1830
2096
  if (s.kind_of? LongDecimalQuot) then
1831
2097
  LongDecimalQuot(s.rat - o.rat, [s.scale, o.scale].max)
1832
2098
  else
2099
+ # puts "ldq-coerce: s=#{s} o=#{o} self=#{self} other=#{other}"
1833
2100
  s - o
1834
2101
  end
1835
2102
  end
@@ -1937,110 +2204,13 @@ class LongDecimalQuot < LongDecimalBase
1937
2204
  raise TypeError, "new_scale #{new_scale.inspect} must be >= 0" unless new_scale >= 0
1938
2205
  raise TypeError, "mode #{mode.inspect} must be legal rounding mode" unless mode.kind_of? RoundingModeClass
1939
2206
 
1940
- sign_quot = numerator <=> 0
1941
- if sign_quot == 0 then
1942
- # finish zero without long calculations at once
1943
- return LongDecimal(0, new_scale)
1944
- end
1945
-
1946
- factor = 10**new_scale
2207
+ factor = LongMath.npower10(new_scale)
1947
2208
  prod = numerator * factor
1948
- divisor = denominator
1949
- quot, rem = prod.divmod(divisor)
1950
- sign_rem = rem <=> 0
1951
- if (sign_rem == 0)
1952
- # if self can be expressed without loss as LongDecimal with
1953
- # new_scale digits after the decimal point, just do it.
1954
- return LongDecimal(quot, new_scale)
1955
- end
1956
-
1957
- # we do not expect negative signs of remainder. To make sure that
1958
- # this does not cause problems in further code, we just throw an
1959
- # exception. This should never happen (and did not happen during
1960
- # testing).
1961
- raise Error, "signs do not match self=#{self.to_s} f=#{factor} prod=#{prod} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem <= 0
1962
-
1963
- if (sign_quot < 0) then
1964
- # handle negative sign of self
1965
- rem -= divisor
1966
- quot += 1
1967
- sign_rem = rem <=> 0
1968
- raise Error, "signs do not match self=#{self.to_s} f=#{factor} prod=#{prod} divisor=#{divisor} quot=#{quot} rem=#{rem}" if sign_rem >= 0
1969
- end
1970
-
1971
- if mode == ROUND_UNNECESSARY then
1972
- # this mode means that rounding should not be necessary. But
1973
- # the case that no rounding is needed, has already been covered
1974
- # above, so it is an error, if this mode is required and the
1975
- # result could not be returned above.
1976
- raise ArgumentError, "mode ROUND_UNNECESSARY not applicable, remainder #{rem.to_s} is not zero"
1977
- end
1978
-
1979
- if (mode == ROUND_CEILING)
1980
- # ROUND_CEILING goes to the closest allowed number >= self, even
1981
- # for negative numbers. Since sign is handled separately, it is
1982
- # more conveniant to use ROUND_UP or ROUND_DOWN depending on the
1983
- # sign.
1984
- mode = (sign_quot > 0) ? ROUND_UP : ROUND_DOWN
1985
-
1986
- elsif (mode == ROUND_FLOOR)
1987
- # ROUND_FLOOR goes to the closest allowed number <= self, even
1988
- # for negative numbers. Since sign is handled separately, it is
1989
- # more conveniant to use ROUND_UP or ROUND_DOWN depending on the
1990
- # sign.
1991
- mode = (sign_quot < 0) ? ROUND_UP : ROUND_DOWN
1992
-
1993
- else
1994
-
1995
- if (mode == ROUND_HALF_CEILING)
1996
- # ROUND_HALF_CEILING goes to the closest allowed number >= self, even
1997
- # for negative numbers. Since sign is handled separately, it is
1998
- # more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
1999
- # sign.
2000
- mode = (sign_quot > 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
2001
-
2002
- elsif (mode == ROUND_HALF_FLOOR)
2003
- # ROUND_HALF_FLOOR goes to the closest allowed number <= self, even
2004
- # for negative numbers. Since sign is handled separately, it is
2005
- # more conveniant to use ROUND_HALF_UP or ROUND_HALF_DOWN depending on the
2006
- # sign.
2007
- mode = (sign_quot < 0) ? ROUND_HALF_UP : ROUND_HALF_DOWN
2008
-
2009
- end
2010
-
2011
- # handle the ROUND_HALF_... stuff and find the adequate ROUND_UP
2012
- # or ROUND_DOWN to use
2013
- abs_rem = rem.abs
2014
- half = (abs_rem << 1) <=> denominator
2015
- if (mode == ROUND_HALF_UP || mode == ROUND_HALF_DOWN || mode == ROUND_HALF_EVEN) then
2016
- if (half < 0) then
2017
- mode = ROUND_DOWN
2018
- elsif half > 0 then
2019
- mode = ROUND_UP
2020
- else
2021
- # half == 0
2022
- if (mode == ROUND_HALF_UP) then
2023
- mode = ROUND_UP
2024
- elsif (mode == ROUND_HALF_DOWN) then
2025
- mode = ROUND_DOWN
2026
- else
2027
- # mode == ROUND_HALF_EVEN
2028
- mode = (quot[0] == 1 ? ROUND_UP : ROUND_DOWN)
2029
- end
2030
- end
2031
- end
2032
- end
2033
-
2034
- if mode == ROUND_UP
2035
- # since the case where we can express the result exactly without
2036
- # loss has already been handled above, ROUND_UP can be handled
2037
- # correctly by adding one unit.
2038
- quot += sign_quot
2039
- end
2040
-
2041
- # put together result
2042
- new_int_val = quot
2043
- LongDecimal(new_int_val, new_scale)
2209
+ raise TypeError, "numerator=#{numerator} must be integer" unless numerator.kind_of? Integer
2210
+ raise TypeError, "denominator=#{denominator}=#{denominator.inspect} must be integer" unless denominator.kind_of? Integer
2211
+ raise TypeError, "factor=#{factor} (new_scale=#{new_scale}) must be integer" unless factor.kind_of? Integer
2212
+ raise TypeError, "prod=#{prod} must be integer" unless prod.kind_of? Integer
2213
+ return round_to_scale_helper(prod, denominator, new_scale, mode)
2044
2214
 
2045
2215
  end # round_to_scale
2046
2216
 
@@ -2075,7 +2245,8 @@ class LongDecimalQuot < LongDecimalBase
2075
2245
 
2076
2246
  elsif other.kind_of? BigDecimal then
2077
2247
  # for BigDecimal, convert self to BigDecimal as well
2078
- s, o = other.coerce(self.to_bd)
2248
+ s, o = other.coerce(self.to_bd(scale + 10))
2249
+ return o, s
2079
2250
 
2080
2251
  elsif other.kind_of? Numeric then
2081
2252
  # for all other numeric types convert self to Float. This may
@@ -2101,10 +2272,27 @@ class LongDecimalQuot < LongDecimalBase
2101
2272
  # explicit number of digits after the decimal point is given. But
2102
2273
  # scale needs to match for equality.
2103
2274
  #
2104
- def ==(other)
2275
+ def eql?(other)
2105
2276
  (other.kind_of? LongDecimalQuot) && (self <=> other) == 0 && self.scale == other.scale
2106
2277
  end
2107
2278
 
2279
+
2280
+ #
2281
+ # compare two numbers for equality.
2282
+ # The LongDecimalQuot self is considered == to other if and only if
2283
+ # it expresses the same value
2284
+ # It needs to be observed that scale does not influence the value expressed
2285
+ # by the number, but only how rouding is performed by default if no
2286
+ # explicit number of digits after the decimal point is given.
2287
+ #
2288
+ def ==(other)
2289
+ if other.kind_of? Numeric
2290
+ (self <=> other) == 0
2291
+ else
2292
+ false
2293
+ end
2294
+ end
2295
+
2108
2296
  #
2109
2297
  # check if the number expressed by self is 0 (zero)
2110
2298
  # with any number of 0s after the decimal point.
@@ -2200,6 +2388,77 @@ class Numeric
2200
2388
 
2201
2389
  end # Numeric
2202
2390
 
2391
+ class Complex
2392
+
2393
+ alias :cdiv :/
2394
+
2395
+ # fix problems with complex division depending on Ruby version
2396
+ if (RUBY_VERSION.match /^1\.8/)
2397
+ #
2398
+ # Division by real or complex number for Ruby 1.8
2399
+ #
2400
+ def / (other)
2401
+ if other.kind_of?(Complex)
2402
+ p = self*other.conjugate
2403
+ d = other.abs2
2404
+ r = p.real/d
2405
+ i = p.image/d
2406
+ Complex(r, i)
2407
+ elsif Complex.generic?(other)
2408
+ Complex(@real/other, @image/other)
2409
+ elsif other.kind_of? BigDecimal
2410
+ Complex(@real/other, @image/other)
2411
+ else
2412
+ x, y = other.coerce(self)
2413
+ x/y
2414
+ end
2415
+ end
2416
+ else
2417
+ #
2418
+ # Division by real or complex number for Ruby 1.9
2419
+ #
2420
+ def / (other)
2421
+ if other.kind_of?(Complex)
2422
+ p = self*other.conjugate
2423
+ d = other.abs2
2424
+ r = nil
2425
+ i = nil
2426
+ if (d.kind_of? Integer) && (p.real.kind_of? Integer)
2427
+ r = Rational(p.real, d)
2428
+ else
2429
+ r = p.real/d
2430
+ end
2431
+ if (d.kind_of? Integer) && (p.image.kind_of? Integer)
2432
+ i = Rational(p.image, d)
2433
+ else
2434
+ i = p.image/d
2435
+ end
2436
+ Complex(r, i)
2437
+ elsif Complex.generic?(other)
2438
+ r = nil
2439
+ i = nil
2440
+ if (other.kind_of? Integer) && (real.kind_of? Integer)
2441
+ r = Rational(real, other)
2442
+ else
2443
+ r = real/other
2444
+ end
2445
+ if (other.kind_of? Integer) && (image.kind_of? Integer)
2446
+ i = Rational(image, other)
2447
+ else
2448
+ i = image/other
2449
+ end
2450
+ Complex(r, i)
2451
+ elsif other.kind_of? BigDecimal
2452
+ Complex(real/other, image/other)
2453
+ else
2454
+ x, y = other.coerce(self)
2455
+ x/y
2456
+ end
2457
+ end
2458
+ end
2459
+ end
2460
+
2461
+
2203
2462
  class Rational
2204
2463
 
2205
2464
  #
@@ -2218,6 +2477,54 @@ class Rational
2218
2477
  end
2219
2478
  end
2220
2479
 
2480
+ # retain original to_f under different name
2481
+ alias :to_f_orig :to_f
2482
+
2483
+ FLOAT_MAX_I = Float::MAX.to_i
2484
+ FLOAT_SIGNIFICANT_I = 2**56
2485
+
2486
+ unless (RUBY_VERSION.match /^1\.9/)
2487
+
2488
+ # fix eql? for Ruby 1.8
2489
+ def eql?(other)
2490
+ (other.kind_of? Rational) && self.numerator == other.numerator && self.denominator == other.denominator
2491
+ end
2492
+
2493
+ # improved to_f, works better where numerator and denominator are integers beyond the range of float, but their Quotient is still expressable as Float
2494
+ def to_f
2495
+ num = @numerator
2496
+ den = @denominator
2497
+ sign = num <=> 0
2498
+ if (sign.zero?)
2499
+ return 0.0
2500
+ elsif sign < 0
2501
+ num = -num
2502
+ end
2503
+ num_big = nil
2504
+ den_big = nil
2505
+ while num >= FLOAT_SIGNIFICANT_I && den >= FLOAT_SIGNIFICANT_I && (num >= FLOAT_MAX_I || den >= FLOAT_MAX_I)
2506
+ num += 0x80
2507
+ num >>= 8
2508
+ den += 0x80
2509
+ den >>= 8
2510
+ end
2511
+
2512
+ if num >= FLOAT_MAX_I
2513
+ num = (num + den/2) / den
2514
+ return (sign * num).to_f
2515
+ elsif den >= FLOAT_MAX_I
2516
+ den = (den + num/2) / num
2517
+ if (den >= FLOAT_MAX_I)
2518
+ return 0.0
2519
+ else
2520
+ return sign/den.to_f
2521
+ end
2522
+ else
2523
+ return sign * (num.to_f / den.to_f)
2524
+ end
2525
+ end
2526
+ end
2527
+
2221
2528
  end # Rational
2222
2529
 
2223
2530
  #
@@ -2233,12 +2540,61 @@ module LongMath
2233
2540
 
2234
2541
  MAX_FLOATABLE = Float::MAX.to_i
2235
2542
  MAX_FLOATABLE2 = MAX_FLOATABLE / 2
2236
- MAX_FLOATABLE10 = 10.0 ** Float::MAX_10_EXP
2237
- MAX_EXP_ABLE = 709
2238
- MIN_FLOATABLE = Float::MIN.to_ld(340, LongMath::ROUND_UP)
2239
- LOG2 = Math.log(2.0)
2240
- LOG10 = Math.log(10.0)
2543
+ # moved to bottom because of dependencies
2544
+ # MAX_FLOATABLE10 = 10.0 ** Float::MAX_10_EXP
2545
+ MAX_EXP_ABLE = 709
2546
+ # moved to the bottom because of dependencies
2547
+ # MIN_FLOATABLE = Float::MIN.to_ld(340, LongMath::ROUND_UP)
2548
+
2549
+ # some arbritrary limit, so we do not exhaust too much memory.
2550
+ MAX_PREC = 2097161 # largest integral number n such that 10**n can be calculated in Ruby.
2551
+ DEFAULT_MAX_PREC = MAX_PREC / 10
2552
+
2553
+ # maximum exponent of 0.1 yielding a non-zero result 0.1**n
2554
+ MAX_NEG_10_EXP = Float::MAX_10_EXP + 16
2555
+ LOG2 = Math.log(2.0)
2556
+ LOG10 = Math.log(10.0)
2557
+
2558
+ #
2559
+ # constants and module variables for LongMath.npower10
2560
+ #
2561
+ POWERS_SMALL_EXP_PARAM = 8
2562
+ POWERS_SMALL_EXP_LIMIT = 1 << POWERS_SMALL_EXP_PARAM # 256
2563
+ POWERS_SMALL_EXP_MASK = POWERS_SMALL_EXP_LIMIT - 1 # 255
2564
+ POWERS_MED_EXP_PARAM = 16
2565
+ POWERS_MED_EXP_LIMIT = 1 << POWERS_MED_EXP_PARAM # 65536
2566
+ POWERS_MED_EXP_MASK = POWERS_MED_EXP_LIMIT - 1 # 65535
2567
+ POWERS_BIG_EXP_LIMIT = MAX_PREC
2568
+
2569
+ private
2241
2570
 
2571
+ # POWERS_BIG_BASE = 10**POWERS_MED_EXP_LIMIT: calculate on demand
2572
+ def LongMath.powers_big_base
2573
+ npower10_cached(POWERS_MED_EXP_LIMIT)
2574
+ end
2575
+
2576
+ # powers of powers_big_base
2577
+ def LongMath.npower_of_big_base(n1)
2578
+ power = @@powers_of_big_base[n1]
2579
+ if (power.nil?)
2580
+ power = powers_big_base ** n1
2581
+ @@powers_of_big_base[n1] = power
2582
+ puts "npower_of_big_base(n1=#{n1}) c->#{power.size}"
2583
+ else
2584
+ puts "npower_of_big_base(n1=#{n1}) c<-#{power.size}"
2585
+ end
2586
+ power
2587
+ end
2588
+
2589
+ # stores power 10**i at position i (memoize pattern)
2590
+ @@small_powers_of_10 = []
2591
+ # stores power (POWERS_BIG_BASE)**i at position i (memoize pattern)
2592
+ @@powers_of_big_base = []
2593
+
2594
+ # stores power 10.0**(-i) at position i (memoize pattern)
2595
+ @@negative_powers_of_10_f = []
2596
+
2597
+ # keep certain common calculations in memory (memoize-pattern)
2242
2598
  @@cache = {}
2243
2599
 
2244
2600
  CacheKey = Struct.new(:fname, :arg, :mode)
@@ -2278,6 +2634,48 @@ module LongMath
2278
2634
 
2279
2635
  end
2280
2636
 
2637
+ #
2638
+ # lookup the upper limit for scale of LongDecimal
2639
+ #
2640
+ def LongMath.prec_limit
2641
+ @@prec_limit ||= LongMath::DEFAULT_MAX_PREC
2642
+ end
2643
+
2644
+ #
2645
+ # lookup the rule for handling errors with overflow of LongDecimal scale
2646
+ #
2647
+ def LongMath.prec_overflow_handling
2648
+ @@prec_overflow_handling ||= :raise_error
2649
+ end
2650
+
2651
+ #
2652
+ # set the rule for handling errors with overflow of LongDecimal scale
2653
+ # possible values are:
2654
+ # :raise_error : immediately raise an error
2655
+ # :use_max : tacitely reduce scale to the maximum allowed value
2656
+ # :warn_use_max : print a warning and reduce scale to the max allowed
2657
+ #
2658
+ def LongMath.prec_overflow_handling=(poh)
2659
+ unless (poh == :raise_error || poh == :use_max || poh == :warn_use_max)
2660
+ raise ArgumentError, "poh=#{poh} no accepted value"
2661
+ end
2662
+ @@prec_overflow_handling = poh
2663
+ end
2664
+
2665
+ #
2666
+ # get the rule for handling errors with overflow of LongDecimal scale
2667
+ # possible values are:
2668
+ # :raise_error : immediately raise an error
2669
+ # :use_max : tacitely reduce scale to the maximum allowed value
2670
+ # :warn_use_max : print a warning and reduce scale to the max allowed
2671
+ #
2672
+ def LongMath.prec_limit=(l = LongMath::DEFAULT_MAX_PREC)
2673
+ LongMath.check_is_int(l)
2674
+ raise ArgumentError, "#{l} must be >= #{Float::MAX_10_EXP}" unless l >= Float::MAX_10_EXP
2675
+ raise ArgumentError, "#{l} must be <= #{LongMath::MAX_PREC}" unless l <= LongMath::MAX_PREC
2676
+ @@prec_limit = l
2677
+ end
2678
+
2281
2679
  private
2282
2680
 
2283
2681
  #
@@ -2340,6 +2738,78 @@ module LongMath
2340
2738
 
2341
2739
  public
2342
2740
 
2741
+ #
2742
+ # optimize calculation of power of 10 by non-negative integer,
2743
+ # because it is essential to LongDecimal to us it very often.
2744
+ # n is the exponent (must be >= 0 and Integer)
2745
+ #
2746
+ def LongMath.npower10(n)
2747
+ check_is_prec(n, "n", :raise_error, MAX_PREC)
2748
+ n0 = n & POWERS_MED_EXP_MASK
2749
+ n1 = n >> POWERS_MED_EXP_PARAM
2750
+ p = npower10_cached(n0)
2751
+ if (n1 > 0) then
2752
+ puts "n0=#{n0} n1=#{n1}"
2753
+ p1 = npower_of_big_base(n1)
2754
+ puts "n0=#{n0} n1=#{n1} p1"
2755
+ p *= p1
2756
+ puts "n0=#{n0} n1=#{n1} p"
2757
+ end
2758
+ return p
2759
+ end
2760
+
2761
+ private
2762
+
2763
+ #
2764
+ # helper method for npower10
2765
+ # only for internal use
2766
+ #
2767
+ def LongMath.npower10_cached(n)
2768
+ p = @@small_powers_of_10[n]
2769
+ if (p.nil?)
2770
+ n0 = n & POWERS_SMALL_EXP_MASK
2771
+ n1 = n >> POWERS_SMALL_EXP_PARAM
2772
+ p = npower10_cached_small(n0)
2773
+ if (n1 > 0)
2774
+ p *= npower10_cached_small(POWERS_SMALL_EXP_LIMIT) ** n1
2775
+ end
2776
+ @@small_powers_of_10[n] = p
2777
+ end
2778
+ p
2779
+ end
2780
+
2781
+ #
2782
+ # helper method for npower10
2783
+ # only for internal use
2784
+ #
2785
+ def LongMath.npower10_cached_small(n)
2786
+ p = @@small_powers_of_10[n]
2787
+ if (p.nil?)
2788
+ p = 10 ** n
2789
+ @@small_powers_of_10[n] = p
2790
+ end
2791
+ p
2792
+ end
2793
+
2794
+ public
2795
+
2796
+ #
2797
+ # helper method for npower10
2798
+ # only for internal use
2799
+ #
2800
+ def LongMath.neg_float_npower10(n)
2801
+ if (n > MAX_NEG_10_EXP)
2802
+ return 0.0
2803
+ end
2804
+ p = @@negative_powers_of_10_f[n]
2805
+ if (p.nil?)
2806
+ #p = 0.1 ** n
2807
+ p = "1e-#{n}".to_f # 0.1 ** n
2808
+ @@negative_powers_of_10_f[n] = p
2809
+ end
2810
+ p
2811
+ end
2812
+
2343
2813
  #
2344
2814
  # helper method for internal use: checks if word_len is a reasonable
2345
2815
  # size for splitting a number into parts
@@ -2367,9 +2837,23 @@ module LongMath
2367
2837
  # helper method for internal use: checks if parameter x is a
2368
2838
  # reasonable value for the precision (scale) of a LongDecimal
2369
2839
  #
2370
- def LongMath.check_is_prec(prec, name="prec")
2371
- check_is_int(prec, "prec")
2372
- raise TypeError, "#{name}=#{prec.inspect} must be >= 0" unless prec >= 0
2840
+ def LongMath.check_is_prec(prec, name="prec", error_handling = nil, pl = prec_limit)
2841
+ raise TypeError, "#{name}=#{prec.inspect} must be Fixnum" unless prec.kind_of? Integer
2842
+ raise ArgumentError, "#{name}=#{prec.inspect} must be >= 0" unless prec >= 0
2843
+ unless (prec.kind_of? Fixnum) && prec <= pl
2844
+ poh = LongMath.prec_overflow_handling
2845
+ if poh == :raise_error || error_handling == :raise_error
2846
+ raise ArgumentError, "#{name}=#{prec.inspect} must be <= #{pl}"
2847
+ elsif poh == :warn_use_max
2848
+ warn "WARNING: #{name}=#{prec} too big => reduced to #{pl}"
2849
+ prec = pl
2850
+ elsif poh == :use_max
2851
+ prec = pl
2852
+ else
2853
+ raise ArgumentError, "unsupported value for prec_overflow_handling=#{poh} found #{name}=#{prec} > #{pl}"
2854
+ end
2855
+ end
2856
+ prec
2373
2857
  end
2374
2858
 
2375
2859
  #
@@ -2428,7 +2912,7 @@ module LongMath
2428
2912
  #
2429
2913
  # calculate the square root of an integer x using bitwise algorithm
2430
2914
  # the result is rounded to an integer y such that
2431
- # y**2�<=�x�<�(y+1)**2
2915
+ # y**2&nbsp;<=&nbsp;x&nbsp;<&nbsp;(y+1)**2
2432
2916
  #
2433
2917
  def LongMath.sqrtb(x)
2434
2918
  a = sqrtb_with_remainder(x)
@@ -2436,8 +2920,8 @@ module LongMath
2436
2920
  end
2437
2921
 
2438
2922
  #
2439
- #�calculateanintegers�>=�0andaremainderr�>=�0suchthat
2440
- #�x�=�s**2�+�rands**2�<=�x�<�(s+1)**2
2923
+ # calculate an integer s&nbsp;>=&nbsp;0 and a remainder r&nbsp;>=&nbsp;0 such that
2924
+ # x&nbsp;=&nbsp;s**2&nbsp;+&nbsp;r and s**2&nbsp;<=&nbsp;x&nbsp;<&nbsp;(s+1)**2
2441
2925
  # the bitwise algorithm is used, which works well for relatively
2442
2926
  # small values of x.
2443
2927
  #
@@ -2477,7 +2961,7 @@ module LongMath
2477
2961
  # 32 bit systems, because internally parts of the double size are
2478
2962
  # used.
2479
2963
  # the result is rounded to an integer y such that
2480
- # y**2�<=�x�<�(y+1)**2
2964
+ # y**2&nbsp;<=&nbsp;x&nbsp;<&nbsp;(y+1)**2
2481
2965
  #
2482
2966
  def LongMath.sqrtw(x, n = 16)
2483
2967
  a = sqrtw_with_remainder(x, n)
@@ -2486,7 +2970,7 @@ module LongMath
2486
2970
 
2487
2971
  #
2488
2972
  # calculate the an integer s >= 0 and a remainder r >= 0 such that
2489
- #�x�=�s**2�+�rands**2�<=�x�<�(s+1)**2
2973
+ # x&nbsp;=&nbsp;s**2&nbsp;+&nbsp;r and s**2&nbsp;<=&nbsp;x&nbsp;<&nbsp;(s+1)**2
2490
2974
  # the wordwise algorithm is used, which works well for relatively
2491
2975
  # large values of x. n defines the word size to be used for the
2492
2976
  # algorithm. It is good to use half of the machine word, but the
@@ -2552,7 +3036,7 @@ module LongMath
2552
3036
  #
2553
3037
  # calculate the cubic root of an integer x using bitwise algorithm
2554
3038
  # the result is rounded to an integer y such that
2555
- # y**3�<=�x�<�(y+1)**3
3039
+ # y**3&nbsp;<=&nbsp;x&nbsp;<&nbsp;(y+1)**3
2556
3040
  #
2557
3041
  def LongMath.cbrtb(x)
2558
3042
  a = cbrtb_with_remainder(x)
@@ -2560,8 +3044,8 @@ module LongMath
2560
3044
  end
2561
3045
 
2562
3046
  #
2563
- #�calculateanintegers�>=�0andaremainderr�>=�0suchthat
2564
- #�x�=�s**3�+�rands**3�<=�x�<�(s+1)**3
3047
+ # calculate an integer s&nbsp;>=&nbsp;0 and a remainder r&nbsp;>=&nbsp;0 such that
3048
+ # x&nbsp;=&nbsp;s**3&nbsp;+&nbsp;r and s**3&nbsp;<=&nbsp;x&nbsp;<&nbsp;(s+1)**3
2565
3049
  # for negative numbers x return negative remainder and result.
2566
3050
  # the bitwise algorithm is used, which works well for relatively
2567
3051
  # small values of x.
@@ -2733,7 +3217,7 @@ module LongMath
2733
3217
  #
2734
3218
  def LongMath.pi(prec, final_mode = LongMath.standard_mode, iprec = nil, mode = nil, cache_result = true) # DOWN?
2735
3219
 
2736
- check_is_prec(prec, "prec")
3220
+ prec = check_is_prec(prec, "prec")
2737
3221
  if (mode.nil?)
2738
3222
  mode = LongMath.standard_mode
2739
3223
  end
@@ -2744,7 +3228,7 @@ module LongMath
2744
3228
  if (iprec.nil?)
2745
3229
  iprec = 5*(prec+1)
2746
3230
  end
2747
- check_is_prec(iprec, "iprec")
3231
+ iprec = check_is_prec(iprec, "iprec")
2748
3232
  sprec = (iprec >> 1) + 1
2749
3233
  dprec = (prec+1) << 1
2750
3234
 
@@ -2792,7 +3276,7 @@ module LongMath
2792
3276
  #
2793
3277
  def LongMath.exp(x, prec, mode = LongMath.standard_mode) # down?
2794
3278
  raise TypeError, "x=#{x.inspect} must not be greater #{MAX_EXP_ABLE}" unless x <= MAX_EXP_ABLE
2795
- check_is_prec(prec, "prec")
3279
+ prec = check_is_prec(prec, "prec")
2796
3280
  check_is_mode(mode, "mode")
2797
3281
  exp_internal(x, prec, mode)
2798
3282
  end
@@ -2810,12 +3294,11 @@ module LongMath
2810
3294
  iprec_extra = (xf / LOG10).abs
2811
3295
  end
2812
3296
  iprec = ((prec+12) * 1.20 + iprec_extra * 1.10).round
2813
- if (iprec < prec) then
2814
- iprec = prec
2815
- end
3297
+ iprec = [ iprec, prec ].max
2816
3298
  if (x_was_neg)
2817
3299
  iprec += 2
2818
3300
  end
3301
+ iprec = check_is_prec(iprec, "iprec")
2819
3302
  iprec
2820
3303
  end
2821
3304
 
@@ -2837,7 +3320,7 @@ module LongMath
2837
3320
  raise ArgumentError, "precision must be supplied either as precision of x=#{x} or explicitely"
2838
3321
  end
2839
3322
  end
2840
- check_is_prec(prec, "prec")
3323
+ prec = check_is_prec(prec, "prec")
2841
3324
 
2842
3325
  if (final_mode.nil?)
2843
3326
  final_mode = LongMath.standard_mode
@@ -2881,7 +3364,7 @@ module LongMath
2881
3364
  if (iprec.nil?) then
2882
3365
  iprec = calc_iprec_for_exp(x, prec, x_was_neg)
2883
3366
  end
2884
- check_is_prec(iprec, "iprec")
3367
+ iprec = check_is_prec(iprec, "iprec")
2885
3368
 
2886
3369
  # we only cache exp(1)
2887
3370
  cache_key = get_cache_key("exp", x, mode, [1, 10, 100, MAX_EXP_ABLE.to_i])
@@ -2967,7 +3450,7 @@ module LongMath
2967
3450
  # internal helper method for calculationg sqrt and sqrt_with_remainder
2968
3451
  #
2969
3452
  def LongMath.sqrt_internal(x, prec, mode, with_rem, cache_result = true)
2970
- check_is_prec(prec, "prec")
3453
+ prec = check_is_prec(prec, "prec")
2971
3454
  check_is_mode(mode, "mode")
2972
3455
  unless (x.kind_of? LongDecimal)
2973
3456
  x = x.to_ld(2 * (prec+1), mode)
@@ -3035,7 +3518,7 @@ module LongMath
3035
3518
  # internal helper method for calculationg cbrt and cbrt_with_remainder
3036
3519
  #
3037
3520
  def LongMath.cbrt_internal(x, prec, mode, with_rem, cache_result = true)
3038
- check_is_prec(prec, "prec")
3521
+ prec = check_is_prec(prec, "prec")
3039
3522
  check_is_mode(mode, "mode")
3040
3523
  unless (x.kind_of? LongDecimal)
3041
3524
  x = x.to_ld(3 * (prec+1), mode)
@@ -3088,7 +3571,7 @@ module LongMath
3088
3571
  # LongDecimal.
3089
3572
  #
3090
3573
  def LongMath.log(x, prec, mode = LongMath.standard_mode) # down?
3091
- check_is_prec(prec, "prec")
3574
+ prec = check_is_prec(prec, "prec")
3092
3575
  check_is_mode(mode, "mode")
3093
3576
  log_internal(x, prec, mode)
3094
3577
  end
@@ -3110,7 +3593,7 @@ module LongMath
3110
3593
  raise ArgumentError, "precision must be supplied either as precision of x=#{x} or explicitely"
3111
3594
  end
3112
3595
  end
3113
- check_is_prec(prec, "prec")
3596
+ prec = check_is_prec(prec, "prec")
3114
3597
 
3115
3598
  if (final_mode.nil?)
3116
3599
  final_mode = LongMath.standard_mode
@@ -3124,7 +3607,7 @@ module LongMath
3124
3607
  if (iprec < prec) then
3125
3608
  iprec = prec
3126
3609
  end
3127
- check_is_prec(iprec, "iprec")
3610
+ iprec = check_is_prec(iprec, "iprec")
3128
3611
  unless (x.kind_of? LongDecimal)
3129
3612
  x = x.to_ld(iprec, mode)
3130
3613
  end
@@ -3218,10 +3701,12 @@ module LongMath
3218
3701
 
3219
3702
  @@standard_mode = ROUND_HALF_UP
3220
3703
 
3704
+ # default to be used as rounding mode when no explicit mode is provided
3221
3705
  def LongMath.standard_mode
3222
3706
  @@standard_mode
3223
3707
  end
3224
3708
 
3709
+ # set default to be used as rounding mode when no explicit mode is provided
3225
3710
  def LongMath.standard_mode=(x)
3226
3711
  LongMath.check_is_mode(x)
3227
3712
  @@standard_mode = x
@@ -3238,6 +3723,14 @@ module LongMath
3238
3723
  @@standard_imode = x
3239
3724
  end
3240
3725
 
3726
+ MAX_FLOATABLE10 = LongMath.npower10(Float::MAX_10_EXP)
3727
+ MIN_FLOATABLE = Float::MIN.to_ld(340, LongMath::ROUND_UP)
3728
+ INV_MIN_FLOATABLE = MIN_FLOATABLE.reciprocal.round_to_scale(0, LongMath::ROUND_HALF_UP).to_i
3729
+ # numbers >= FLOATABLE_WITHOUT_FRACTION yield the same result when converted to Float, regardless of what follows after the decimal point
3730
+ FLOATABLE_WITHOUT_FRACTION = (2 / Float::EPSILON).to_i
3731
+ MAX_SIGNIFICANT_FLOATABLE_DIGITS = Float::DIG + 1
3732
+
3733
+
3241
3734
  end # LongMath
3242
3735
 
3243
3736
  # end of file long-decimal.rb