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.
- 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
|