long-decimal 0.02.01 → 1.00.01

Sign up to get free protection for your applications and to get access to all the features.
@@ -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