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.
- data/README +7 -16
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/install.rb +1 -1
- data/lib/long-decimal-extra.rb +623 -72
- data/lib/long-decimal.rb +716 -223
- data/make_doc.rb +1 -1
- data/test/testlongdecimal-extra.rb +1101 -9
- data/test/testlongdecimal-performance.rb +357 -0
- data/test/testlongdecimal.rb +509 -76
- data/test/testlongdeclib.rb +94 -43
- data/test/testrandlib.rb +1 -1
- data/test/testrandom-extra.rb +5 -3
- data/test/testrandom.rb +5 -3
- data/test/testrandpower.rb +5 -3
- data/version.rb +4 -2
- metadata +28 -18
data/lib/long-decimal.rb
CHANGED
@@ -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.
|
11
|
-
# CVS-Label: $Name:
|
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
|
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
|
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
|
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
|
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
|
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.
|
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.
|
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(
|
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*
|
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(
|
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*
|
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*
|
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(
|
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
|
557
|
-
@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
|
-
|
576
|
-
raise TypeError, "
|
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 *
|
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 =
|
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
|
-
|
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 =
|
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
|
-
|
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 =
|
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) /
|
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 (
|
876
|
-
|
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 (
|
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
|
885
|
-
|
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
|
-
|
889
|
-
|
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
|
-
|
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
|
-
|
908
|
-
#
|
909
|
-
#
|
910
|
-
return
|
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
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
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
|
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
|
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
|
-
|
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 =
|
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
|
-
|
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(
|
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
|
-
|
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 *
|
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(
|
1528
|
-
|
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 %
|
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)
|
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.
|
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
|
-
|
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
|
-
|
1949
|
-
|
1950
|
-
|
1951
|
-
|
1952
|
-
|
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
|
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
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
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
|
-
|
2372
|
-
raise
|
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
|
2915
|
+
# y**2 <= x < (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
|
-
|
2440
|
-
|
2923
|
+
# calculate an integer s >= 0 and a remainder r >= 0 such that
|
2924
|
+
# x = s**2 + r and s**2 <= x < (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
|
2964
|
+
# y**2 <= x < (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
|
-
|
2973
|
+
# x = s**2 + r and s**2 <= x < (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
|
3039
|
+
# y**3 <= x < (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
|
-
|
2564
|
-
|
3047
|
+
# calculate an integer s >= 0 and a remainder r >= 0 such that
|
3048
|
+
# x = s**3 + r and s**3 <= x < (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
|
-
|
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
|