| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Math::FractionManip; |
|
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:GENE'; |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# ABSTRACT: Manipulate fractions |
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
736
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
35
|
|
|
7
|
|
|
|
|
|
|
#use warnings; |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.5502'; |
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
4
|
use Carp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
49
|
|
|
12
|
1
|
|
|
1
|
|
953
|
use Math::BigInt; |
|
|
1
|
|
|
|
|
21305
|
|
|
|
1
|
|
|
|
|
5
|
|
|
13
|
1
|
|
|
1
|
|
21892
|
use Math::BigFloat; |
|
|
1
|
|
|
|
|
37765
|
|
|
|
1
|
|
|
|
|
5
|
|
|
14
|
|
|
|
|
|
|
use overload |
|
15
|
1
|
|
|
|
|
8
|
'+' => 'add', |
|
16
|
|
|
|
|
|
|
'-' => 'sub', |
|
17
|
|
|
|
|
|
|
'*' => 'mul', |
|
18
|
|
|
|
|
|
|
'/' => 'div', |
|
19
|
|
|
|
|
|
|
'abs' => 'abs', |
|
20
|
|
|
|
|
|
|
'**' => 'pow', |
|
21
|
|
|
|
|
|
|
'sqrt' => 'sqrt', |
|
22
|
|
|
|
|
|
|
'<=>' => 'cmp', |
|
23
|
|
|
|
|
|
|
'""' => 'string', |
|
24
|
|
|
|
|
|
|
'0+' => 'decimal', |
|
25
|
1
|
|
|
1
|
|
648
|
fallback => 1; |
|
|
1
|
|
|
|
|
2
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my %DEF = ( |
|
28
|
|
|
|
|
|
|
CURRENT => { TAGS => [qw/ NORMAL REDUCE SMALL AUTO /], DIGITS => undef, SYSTEM => 1, NAME => 'DEFAULT' }, |
|
29
|
|
|
|
|
|
|
DEFAULT => { TAGS => [qw/ NORMAL REDUCE SMALL AUTO /], DIGITS => undef, READONLY => 1, SYSTEM => 1 }, |
|
30
|
|
|
|
|
|
|
BLANK => { TAGS => ['', '', ''], DIGITS => '', READONLY => 1, SYSTEM => 1 }, |
|
31
|
|
|
|
|
|
|
); |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my ($OUTFORMAT, $REDUCE, $SIZE, $AUTO, $INTERNAL, $RED_STATE) = (0 .. 5); |
|
34
|
|
|
|
|
|
|
my $TAG_END = 3; #Last index of tags meant to be kept. |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my %TAGS = ( |
|
37
|
|
|
|
|
|
|
NORMAL => [$OUTFORMAT, 'NORMAL'], |
|
38
|
|
|
|
|
|
|
MIXED => [$OUTFORMAT, 'MIXED'], |
|
39
|
|
|
|
|
|
|
MIXED_RAW => [$OUTFORMAT, 'MIXED_RAW'], |
|
40
|
|
|
|
|
|
|
RAW => [$OUTFORMAT, 'RAW'], |
|
41
|
|
|
|
|
|
|
DEF_MIXED => [$OUTFORMAT, undef], |
|
42
|
|
|
|
|
|
|
REDUCE => [$REDUCE, 'REDUCE'], |
|
43
|
|
|
|
|
|
|
NO_REDUCE => [$REDUCE, 'NO_REDUCE'], |
|
44
|
|
|
|
|
|
|
DEF_REDUCE => [$REDUCE, undef], |
|
45
|
|
|
|
|
|
|
SMALL => [$SIZE, 'SMALL'], |
|
46
|
|
|
|
|
|
|
BIG => [$SIZE, 'BIG'], |
|
47
|
|
|
|
|
|
|
DEF_BIG => [$SIZE, undef], |
|
48
|
|
|
|
|
|
|
AUTO => [$AUTO, 'AUTO'], |
|
49
|
|
|
|
|
|
|
NO_AUTO => [$AUTO, 'NO_AUTO'], |
|
50
|
|
|
|
|
|
|
DEF_AUTO => [$AUTO, undef], |
|
51
|
|
|
|
|
|
|
CONVERTED => [$INTERNAL, 'CONVERTED'], |
|
52
|
|
|
|
|
|
|
IS_REDUCED => [$RED_STATE, 'IS_REDUCED'], |
|
53
|
|
|
|
|
|
|
); |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
my @DEF_TAG = qw(DEF_MIXED DEF_REDUCE DEF_BIG DEF_AUTO); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
my $ID = 01; |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub new { |
|
60
|
64
|
|
|
64
|
1
|
4819
|
my $proto = shift; |
|
61
|
64
|
|
33
|
|
|
220
|
my $class = ref($proto) || $proto; |
|
62
|
64
|
|
|
|
|
108
|
my ($self, @frac, @tags, $tag, $decimal, $p1, $p2, $p3); |
|
63
|
64
|
100
|
100
|
|
|
114
|
if (_is_decimal($_[0]) and _is_decimal($_[1]) and _is_decimal($_[2])) { |
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
64
|
2
|
|
|
|
|
7
|
my $sign = $_[0] / abs($_[0]); |
|
65
|
2
|
|
|
|
|
6
|
@tags = _tags(@_[3 .. $#_]); |
|
66
|
2
|
|
|
|
|
7
|
($decimal, $p1, $p2, $p3) = _fix_num(\@tags, @_[0 .. 2]); |
|
67
|
2
|
|
|
|
|
6
|
($p1, $p2, $p3) = (abs($p1), abs($p2), abs($p3)); |
|
68
|
2
|
|
|
|
|
6
|
@frac = ($p1 * $p3 + $p2, $sign * $p3); |
|
69
|
2
|
50
|
|
|
|
6
|
@frac = _de_decimal(@frac, \@tags) if $decimal; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
elsif (_is_decimal($_[0]) and _is_decimal($_[1])) { |
|
72
|
50
|
|
|
|
|
127
|
@tags = _tags(@_[2 .. $#_]); |
|
73
|
50
|
|
|
|
|
118
|
($decimal, @frac) = _fix_num(\@tags, @_[0 .. 1]); |
|
74
|
50
|
100
|
|
|
|
87
|
@frac = _de_decimal(@frac, \@tags) if $decimal; |
|
75
|
50
|
|
|
|
|
78
|
@frac = _simplify_sign(@frac); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
elsif (_is_decimal($_[0])) { |
|
78
|
|
|
|
|
|
|
{ |
|
79
|
5
|
|
|
|
|
9
|
@tags = _tags(@_[1 .. $#_]); |
|
|
5
|
|
|
|
|
15
|
|
|
80
|
5
|
|
|
|
|
15
|
($decimal, $p1) = _fix_num(\@tags, $_[0]); |
|
81
|
5
|
100
|
|
|
|
16
|
@frac = ($p1, 1), last if not $decimal; |
|
82
|
3
|
|
|
|
|
8
|
(@frac[0 .. 1], $tag) = _from_decimal($p1); |
|
83
|
3
|
|
|
|
|
7
|
@tags = _tags(@tags, $tag); |
|
84
|
3
|
|
|
|
|
8
|
($decimal, @frac) = _fix_num(\@tags, @frac); |
|
85
|
3
|
50
|
|
|
|
7
|
@frac = _de_decimal(@frac, \@tags) if $decimal; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
elsif ($_[0] =~ /\s*([\+\-]?)\s*([0-9e\.\+\-]+)\s+([0-9e\.\+\-]+)\s*\/\s*([0-9e\.\+\-]+)/) { |
|
89
|
2
|
|
|
|
|
6
|
my $sign = $1 . '1'; |
|
90
|
2
|
|
|
|
|
8
|
@tags = _tags(@_[1 .. $#_]); |
|
91
|
2
|
|
|
|
|
21
|
($decimal, $p1, $p2, $p3) = _fix_num(\@tags, $2, $3, $4); |
|
92
|
2
|
|
|
|
|
7
|
($p1, $p2, $p3) = (abs($p1), abs($p2), abs($p3)); |
|
93
|
2
|
|
|
|
|
8
|
@frac = ($p1 * $p3 + $p2, $sign * $p3); |
|
94
|
2
|
50
|
|
|
|
4
|
@frac = _de_decimal($p1 * $p3 + $p2, $sign * $p3, \@tags) if $decimal; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
elsif ($_[0] =~ /\s*([0-9e\.\+\-]+)\s*\/\s*([0-9e\.\+\-]+)/) { |
|
97
|
5
|
|
|
|
|
22
|
@tags = _tags(@_[1 .. $#_]); |
|
98
|
5
|
|
|
|
|
14
|
($decimal, @frac) = _fix_num(\@tags, $1, $2); |
|
99
|
5
|
50
|
|
|
|
12
|
@frac = _de_decimal(@frac, \@tags) if $decimal; |
|
100
|
5
|
|
|
|
|
12
|
@frac = _simplify_sign(@frac); |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
else { |
|
103
|
0
|
|
|
|
|
0
|
croak("\"$_[0]\" is of unknown format"); |
|
104
|
|
|
|
|
|
|
} |
|
105
|
64
|
50
|
|
|
|
142
|
croak("Can not have 0 as the denominator") if $frac[1] == 0; |
|
106
|
64
|
100
|
100
|
|
|
427
|
if (_tag($REDUCE, \@tags) ne 'NO_REDUCE' and _tag($RED_STATE, \@tags) ne 'IS_REDUCED') { |
|
107
|
33
|
|
|
|
|
37
|
my $not_reduced; |
|
108
|
33
|
|
|
|
|
48
|
($not_reduced, @frac) = _reduce(@frac); |
|
109
|
33
|
100
|
66
|
|
|
65
|
@frac = _fix_auto('DOWN', \@tags, @frac) if $not_reduced and _tag($AUTO, \@tags) eq 'AUTO'; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
64
|
100
|
|
|
|
111
|
@tags[$RED_STATE] = undef if _tag($RED_STATE, \@tags) eq 'IS_REDUCED'; |
|
112
|
64
|
|
|
|
|
134
|
$self->{frac} = \@frac; |
|
113
|
64
|
|
|
|
|
108
|
$self->{tags} = \@tags; |
|
114
|
64
|
|
|
|
|
97
|
bless($self, $class); |
|
115
|
64
|
|
|
|
|
240
|
return $self; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub string { |
|
119
|
40
|
|
|
40
|
1
|
10994
|
my $self = shift; |
|
120
|
40
|
|
|
|
|
60
|
my @frac; |
|
121
|
40
|
|
|
|
|
104
|
my $mixed = _tag($OUTFORMAT, [$_[0]], $self->{tags}); |
|
122
|
40
|
100
|
|
|
|
108
|
if ($mixed eq 'MIXED') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
123
|
14
|
|
|
|
|
30
|
@frac = $self->list('MIXED'); |
|
124
|
14
|
|
|
|
|
25
|
my $string = ""; |
|
125
|
14
|
100
|
|
|
|
30
|
$string .= "$frac[0]" if $frac[0] != 0; |
|
126
|
14
|
100
|
100
|
|
|
342
|
$string .= " " if $frac[0] != 0 and $frac[1] != 0; |
|
127
|
14
|
100
|
|
|
|
275
|
$string .= "$frac[1]/$frac[2]" if $frac[1] != 0; |
|
128
|
14
|
50
|
|
|
|
343
|
$string = "0" if $string eq ''; |
|
129
|
14
|
|
|
|
|
144
|
return $string; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
elsif ($mixed eq 'MIXED_RAW') { |
|
132
|
0
|
|
|
|
|
0
|
@frac = $self->list('MIXED'); |
|
133
|
0
|
|
|
|
|
0
|
return "$frac[0] $frac[1]/$frac[2]"; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
elsif ($mixed eq 'RAW') { |
|
136
|
0
|
|
|
|
|
0
|
@frac = $self->list; |
|
137
|
0
|
0
|
|
|
|
0
|
return ($frac[0] >= 0 ? '+' : '') . "$frac[0]/$frac[1]"; |
|
138
|
|
|
|
|
|
|
} |
|
139
|
|
|
|
|
|
|
else { |
|
140
|
26
|
|
|
|
|
47
|
@frac = $self->list; |
|
141
|
26
|
|
|
|
|
232
|
return "$frac[0]/$frac[1]"; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub list { |
|
146
|
40
|
|
|
40
|
1
|
59
|
my $self = shift; |
|
147
|
40
|
|
|
|
|
46
|
my @frac = @{ $self->{frac} }; |
|
|
40
|
|
|
|
|
72
|
|
|
148
|
40
|
100
|
|
|
|
72
|
if ($_[0] eq "MIXED") { |
|
149
|
14
|
|
|
|
|
27
|
my $whole = $frac[0] / $frac[1]; |
|
150
|
14
|
100
|
|
|
|
265
|
$whole = int($whole) if not ref($frac[0]); |
|
151
|
14
|
|
|
|
|
28
|
$frac[0] = abs($frac[0] - $frac[1] * $whole); |
|
152
|
14
|
|
|
|
|
281
|
@frac = ($whole, @frac); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
40
|
|
|
|
|
53
|
foreach (@frac) { s/^\+//; } |
|
|
94
|
|
|
|
|
234
|
|
|
155
|
40
|
|
|
|
|
126
|
return @frac; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub reduce { |
|
159
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
160
|
0
|
|
|
|
|
0
|
my ($undef, @frac) = _reduce(@{ $self->{frac} }); |
|
|
0
|
|
|
|
|
0
|
|
|
161
|
0
|
|
|
|
|
0
|
return Math::FractionManip->new(@frac, @{ $self->{tags} }); |
|
|
0
|
|
|
|
|
0
|
|
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub decimal { |
|
166
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
|
167
|
2
|
|
|
|
|
4
|
my @frac = @{ $self->{frac} }; |
|
|
2
|
|
|
|
|
5
|
|
|
168
|
2
|
50
|
|
|
|
9
|
return $frac[0] / $frac[1] if not ref($frac[0]); |
|
169
|
0
|
0
|
|
|
|
0
|
return Math::BigFloat->new(Math::BigFloat::bdiv($frac[0], $frac[1], $DEF{CURRENT}{DIGITS})) if ref($frac[0]); |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
sub num { |
|
173
|
1
|
|
|
1
|
1
|
954
|
my $self = shift; |
|
174
|
1
|
|
|
|
|
2
|
my @frac = @{ $self->{frac} }; |
|
|
1
|
|
|
|
|
4
|
|
|
175
|
1
|
50
|
|
|
|
16
|
return $frac[0] / $frac[1] if not ref $frac[0]; |
|
176
|
0
|
0
|
|
|
|
0
|
return Math::BigFloat->new(Math::BigFloat::bdiv($frac[0], $frac[1], $DEF{CURRENT}{DIGITS})) if ref($frac[0]); |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
## For the next three methods: |
|
180
|
|
|
|
|
|
|
# If used on the object use the tags of the object |
|
181
|
|
|
|
|
|
|
# If given a class use the dafault tags, |
|
182
|
|
|
|
|
|
|
# .... if a default set is specified then return for that set. |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub is_tag { |
|
185
|
6
|
|
|
6
|
1
|
1126
|
my $self = shift; |
|
186
|
6
|
|
|
|
|
10
|
my $tag = shift; |
|
187
|
6
|
50
|
|
|
|
15
|
my $default = 1 if $_[0] eq 'INC_DEF'; |
|
188
|
6
|
|
|
|
|
10
|
my $is_tag = 0; |
|
189
|
6
|
|
|
|
|
9
|
my @tags; |
|
190
|
|
|
|
|
|
|
{ |
|
191
|
6
|
50
|
|
|
|
6
|
$is_tag = 0, last if not $TAGS{$tag}; #if there is no such tag ret=0 |
|
|
6
|
|
|
|
|
14
|
|
|
192
|
6
|
|
|
|
|
7
|
my ($num, $tag) = @{ $TAGS{$tag} }; |
|
|
6
|
|
|
|
|
13
|
|
|
193
|
6
|
50
|
|
|
|
13
|
if (ref($self) eq "Math::FractionManip") { |
|
194
|
6
|
|
|
|
|
8
|
@tags = @{ $self->{tags} }; |
|
|
6
|
|
|
|
|
13
|
|
|
195
|
6
|
100
|
|
|
|
15
|
$is_tag = 1, last if $tags[$num] eq $tag; |
|
196
|
3
|
50
|
33
|
|
|
9
|
$is_tag = undef, last if $tags[$num] eq undef and not $default; |
|
197
|
3
|
0
|
33
|
|
|
8
|
$is_tag = -1, last if $DEF{CURRENT}{TAGS}[$num] eq $tag |
|
|
|
|
33
|
|
|
|
|
|
198
|
|
|
|
|
|
|
and $tags[$num] eq undef and $default; |
|
199
|
3
|
|
|
|
|
6
|
$is_tag = 0; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
else { |
|
202
|
0
|
|
|
|
|
0
|
my $set; |
|
203
|
0
|
0
|
|
|
|
0
|
$set = 'CURRENT' unless $set = $_[0]; |
|
204
|
0
|
0
|
|
|
|
0
|
$set = 'BLANK' unless exists $DEF{$set}; |
|
205
|
0
|
0
|
|
|
|
0
|
$is_tag = 1, last if $DEF{$set}{TAGS}[$num] eq $tag; |
|
206
|
0
|
|
|
|
|
0
|
$is_tag = 0; |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
} |
|
209
|
6
|
|
|
|
|
27
|
return $is_tag; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub tags { |
|
213
|
5
|
|
|
5
|
1
|
9
|
my $self = shift; |
|
214
|
5
|
|
|
|
|
8
|
my @tags; |
|
215
|
5
|
50
|
|
|
|
14
|
if (ref($self) eq "Math::FractionManip") { |
|
|
|
50
|
|
|
|
|
|
|
216
|
0
|
0
|
|
|
|
0
|
my $inc_def = 1 if $_[0] eq 'INC_DEF'; |
|
217
|
0
|
|
|
|
|
0
|
@tags = @{ $self->{tags} }[0 .. $TAG_END]; |
|
|
0
|
|
|
|
|
0
|
|
|
218
|
0
|
|
|
|
|
0
|
my $num; |
|
219
|
0
|
|
|
|
|
0
|
foreach $num (0 .. $#tags) { |
|
220
|
0
|
0
|
0
|
|
|
0
|
$tags[$num] = $DEF_TAG[$num] if $tags[$num] eq undef and not $inc_def; |
|
221
|
0
|
0
|
0
|
|
|
0
|
$tags[$num] = $DEF{CURRENT}{TAGS}[$num] if $tags[$num] eq undef and $inc_def; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
elsif (ref($self) ne "Math::FractionManip") { |
|
225
|
5
|
|
|
|
|
6
|
my $set; |
|
226
|
5
|
100
|
|
|
|
11
|
$set = 'CURRENT' unless $set = $_[0]; |
|
227
|
5
|
50
|
|
|
|
11
|
$set = 'BLANK' unless exists $DEF{$set}; |
|
228
|
5
|
|
|
|
|
6
|
@tags = @{ $DEF{$set}{TAGS} }; |
|
|
5
|
|
|
|
|
52
|
|
|
229
|
|
|
|
|
|
|
} |
|
230
|
5
|
|
|
|
|
35
|
return @tags; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub digits { |
|
234
|
5
|
|
|
5
|
1
|
8
|
my $self = shift; |
|
235
|
5
|
|
|
|
|
6
|
my $set; |
|
236
|
5
|
100
|
|
|
|
13
|
$set = 'CURRENT' unless $set = $_[0]; |
|
237
|
5
|
50
|
|
|
|
11
|
$set = 'BLANK' unless exists $DEF{$set}; |
|
238
|
5
|
|
|
|
|
18
|
return $DEF{$set}{DIGITS}; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
############################### |
|
242
|
|
|
|
|
|
|
# These methods are used for managing default sets. |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub sets { |
|
245
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
246
|
0
|
|
|
|
|
0
|
return keys %DEF; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub name_set { |
|
250
|
1
|
|
|
1
|
1
|
2
|
shift; |
|
251
|
1
|
50
|
|
|
|
4
|
return $DEF{CURRENT}{NAME} if not $_[0]; |
|
252
|
1
|
50
|
|
|
|
5
|
$DEF{CURRENT}{NAME} = $_[0] if $_[0]; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub exists_set { |
|
256
|
0
|
|
|
0
|
1
|
0
|
return exists $DEF{ $_[1] }; |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub use_set { |
|
260
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
261
|
1
|
|
|
|
|
1
|
my $name = shift; |
|
262
|
1
|
50
|
33
|
|
|
7
|
if (exists $DEF{$name} and not $DEF{$name}{READONLY}) { |
|
263
|
1
|
|
|
|
|
2
|
$DEF{CURRENT} = $DEF{$name}; |
|
264
|
1
|
|
|
|
|
3
|
return $name; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
else { |
|
267
|
0
|
|
|
|
|
0
|
return undef; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub temp_set { |
|
272
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
273
|
0
|
|
|
|
|
0
|
my $name = shift; |
|
274
|
0
|
0
|
|
|
|
0
|
if (not $name) { |
|
275
|
0
|
|
|
|
|
0
|
$ID++; |
|
276
|
0
|
|
|
|
|
0
|
$name = "\cI\cD$ID"; |
|
277
|
0
|
|
|
|
|
0
|
$self->copy_set('CURRENT', $name); |
|
278
|
0
|
|
|
|
|
0
|
$self->copy_set('DEFAULT', 'CURRENT'); |
|
279
|
0
|
|
|
|
|
0
|
return $name; |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
else { #if $name; |
|
282
|
0
|
|
|
|
|
0
|
my $return = $self->copy_set($name, 'CURRENT'); |
|
283
|
0
|
|
|
|
|
0
|
$self->del_set($name); |
|
284
|
0
|
|
|
|
|
0
|
return $return; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
} |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub load_set { |
|
289
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
|
290
|
2
|
50
|
|
|
|
6
|
if (exists $DEF{ $_[0] }) { |
|
291
|
2
|
50
|
|
|
|
14
|
$self->copy_set($_[0], 'CURRENT') if exists $DEF{ $_[0] }; |
|
292
|
2
|
|
|
|
|
3
|
return $_[0]; |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
else { |
|
295
|
0
|
|
|
|
|
0
|
return undef; |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub save_set { |
|
300
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
301
|
1
|
|
|
|
|
2
|
my $name; |
|
302
|
1
|
50
|
|
|
|
5
|
$name = $DEF{CURRENT}{NAME} unless $name = shift; |
|
303
|
1
|
50
|
33
|
|
|
6
|
++$ID, $name = "\cI\cD:$ID" if not $name or $name eq 'RAND'; |
|
304
|
1
|
|
50
|
|
|
41
|
return $self->copy_set('CURRENT', $name) && $name; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub copy_set { |
|
308
|
3
|
|
|
3
|
1
|
6
|
shift; |
|
309
|
3
|
|
|
|
|
7
|
my ($name1, $name2) = @_; |
|
310
|
3
|
50
|
33
|
|
|
19
|
if ($DEF{$name2}{READONLY} or $name2 eq 'BLANK' or not exists $DEF{$name1}) { |
|
|
|
|
33
|
|
|
|
|
|
311
|
0
|
|
|
|
|
0
|
return 0; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
else { |
|
314
|
3
|
|
|
|
|
9
|
$DEF{$name2} = {}; # kill any links from use; |
|
315
|
3
|
|
|
|
|
4
|
$DEF{$name2}{TAGS} = [@{ $DEF{$name1}{TAGS} }]; |
|
|
3
|
|
|
|
|
10
|
|
|
316
|
3
|
|
|
|
|
5
|
$DEF{$name2}{DIGITS} = $DEF{$name1}{DIGITS}; |
|
317
|
3
|
100
|
|
|
|
7
|
$DEF{$name2}{NAME} = $name2 unless $name2 eq 'CURRENT'; |
|
318
|
3
|
100
|
|
|
|
7
|
$DEF{$name2}{NAME} = $name1 if $name2 eq 'CURRENT'; |
|
319
|
3
|
|
|
|
|
8
|
return 1; |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub del_set { |
|
324
|
0
|
0
|
0
|
0
|
1
|
0
|
if (exists $DEF{ $_[1] } and not $DEF{ $_[1] }{SYSTEM}) { |
|
325
|
0
|
|
|
|
|
0
|
delete $DEF{ $_[1] }; |
|
326
|
0
|
|
|
|
|
0
|
return $_[1]; |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
############################### |
|
331
|
|
|
|
|
|
|
# All of the modify methods are not meant to return anything, they modify |
|
332
|
|
|
|
|
|
|
# the object being referenced. |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# This method works almost like the new method except that it takes an |
|
335
|
|
|
|
|
|
|
# object as an argement and will modify it instead of creating a new |
|
336
|
|
|
|
|
|
|
# object, also any tags associated with the object are left in tact |
|
337
|
|
|
|
|
|
|
# unless a new tag is given to override the old. |
|
338
|
|
|
|
|
|
|
sub modify { |
|
339
|
0
|
|
|
0
|
1
|
0
|
my $me = shift; |
|
340
|
0
|
|
|
|
|
0
|
my $self; |
|
341
|
0
|
|
|
|
|
0
|
my @tags = @{ $me->{tags} }; |
|
|
0
|
|
|
|
|
0
|
|
|
342
|
0
|
|
|
|
|
0
|
$self = Math::FractionManip->new(@_, @tags, @_); # The extra @_ is there to override tags |
|
343
|
0
|
|
|
|
|
0
|
$me->{frac} = $self->{frac}; |
|
344
|
0
|
|
|
|
|
0
|
$me->{tags} = $self->{tags}; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
# XXX This method appears to break things? -GB |
|
348
|
|
|
|
|
|
|
sub modify_digits { |
|
349
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
350
|
1
|
|
|
|
|
3
|
$DEF{CURRENT}{DIGITS} = shift; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub modify_reduce { |
|
354
|
0
|
|
|
0
|
1
|
0
|
my $me = shift; |
|
355
|
0
|
|
|
|
|
0
|
my $self = $me->reduce; |
|
356
|
0
|
|
|
|
|
0
|
$me->{frac} = $self->{frac}; |
|
357
|
0
|
|
|
|
|
0
|
$me->{tags} = $self->{tags}; |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub modify_num { |
|
361
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
362
|
0
|
|
|
|
|
0
|
$self->[0] = $_[0]; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub modify_den { |
|
366
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
367
|
0
|
|
|
|
|
0
|
$self->[1] = $_[0]; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub modify_tag { |
|
371
|
5
|
|
|
5
|
1
|
702
|
my $self = shift; |
|
372
|
5
|
|
|
|
|
12
|
my ($return, @return); |
|
373
|
5
|
|
|
|
|
0
|
my $newtag; |
|
374
|
5
|
|
|
|
|
25
|
foreach $newtag (@_) { |
|
375
|
7
|
|
|
|
|
11
|
my $tagnum = _tagnum($newtag); |
|
376
|
7
|
50
|
|
|
|
20
|
if ($tagnum == -1) { |
|
|
|
100
|
|
|
|
|
|
|
377
|
0
|
|
|
|
|
0
|
push @return, undef; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
elsif (ref($self) eq "Math::FractionManip") { |
|
380
|
3
|
|
|
|
|
6
|
my @frac = @{ $self->{frac} }; |
|
|
3
|
|
|
|
|
7
|
|
|
381
|
3
|
|
|
|
|
5
|
my @tags = @{ $self->{tags} }; |
|
|
3
|
|
|
|
|
6
|
|
|
382
|
3
|
|
|
|
|
8
|
my @newtags = _tags(@tags, $newtag); |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Now transform the Fraction based on the new tag. |
|
385
|
3
|
100
|
|
|
|
10
|
if ($tagnum == $SIZE) { |
|
|
|
50
|
|
|
|
|
|
|
386
|
1
|
|
|
|
|
3
|
my $newtag = _tag($SIZE, \@newtags); |
|
387
|
1
|
50
|
|
|
|
3
|
@frac = map { "$_" + 0 } @frac if $newtag eq 'SMALL'; |
|
|
0
|
|
|
|
|
0
|
|
|
388
|
1
|
50
|
|
|
|
5
|
@frac = map { Math::BigInt->new($_) } @frac if $newtag eq 'BIG'; |
|
|
2
|
|
|
|
|
69
|
|
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
elsif ($tagnum == $REDUCE) { |
|
391
|
0
|
0
|
|
|
|
0
|
(undef, @frac) = _reduce(@frac) if _tag($REDUCE, \@newtags) eq 'REDUCE'; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# Finally Modify the Fraction |
|
395
|
3
|
|
|
|
|
46
|
$self->{frac} = \@frac; |
|
396
|
3
|
|
|
|
|
8
|
$self->{tags} = \@newtags; |
|
397
|
|
|
|
|
|
|
} |
|
398
|
|
|
|
|
|
|
else { |
|
399
|
4
|
|
|
|
|
8
|
$DEF{CURRENT}{TAGS}[$tagnum] = $newtag; |
|
400
|
|
|
|
|
|
|
} |
|
401
|
7
|
|
|
|
|
16
|
push @return, $newtag; |
|
402
|
|
|
|
|
|
|
} |
|
403
|
5
|
|
|
|
|
11
|
return @return; |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
############################### |
|
407
|
|
|
|
|
|
|
# These methods are meant to be called with the overload operators. |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub add { |
|
410
|
16
|
|
|
16
|
1
|
23
|
my @frac1 = @{ $_[0]->{frac} }; |
|
|
16
|
|
|
|
|
34
|
|
|
411
|
16
|
|
|
|
|
19
|
my @tags1 = @{ $_[0]->{tags} }; |
|
|
16
|
|
|
|
|
29
|
|
|
412
|
16
|
|
|
|
|
24
|
my (@frac2, @frac, @tags2, $frac); |
|
413
|
16
|
|
|
|
|
16
|
my $skipauto = 0; |
|
414
|
16
|
100
|
|
|
|
34
|
@frac2 = @{ $_[1]->{frac} }, @tags2 = @{ $_[1]->{tags} } if ref($_[1]) eq "Math::FractionManip"; |
|
|
10
|
|
|
|
|
19
|
|
|
|
10
|
|
|
|
|
16
|
|
|
415
|
16
|
100
|
|
|
|
62
|
@frac2 = _from_decimal($_[1]), $tags2[$INTERNAL] = 'CONVERTED' if ref($_[1]) ne "Math::FractionManip"; |
|
416
|
16
|
|
|
|
|
71
|
my @tags = _tags_preserve([@tags1], [@tags2]); |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
LOOP: { |
|
419
|
16
|
100
|
|
|
|
32
|
if (_tag($REDUCE, \@tags) eq 'NO_REDUCE') { |
|
|
17
|
|
|
|
|
32
|
|
|
420
|
4
|
|
|
|
|
14
|
@frac = ($frac1[0] * $frac2[1] + $frac2[0] * $frac1[1], $frac1[1] * $frac2[1]); |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
else { |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# Taken from Knuth v2 (rev 2), p313. |
|
425
|
|
|
|
|
|
|
# It will always return a reduced fraction. |
|
426
|
13
|
|
|
|
|
34
|
my $gcd1 = _gcd($frac1[1], $frac2[1]); |
|
427
|
13
|
|
|
|
|
28
|
my $tmp = $frac1[0] * ($frac2[1] / $gcd1) + $frac2[0] * ($frac1[1] / $gcd1); |
|
428
|
13
|
|
|
|
|
17
|
my $gcd2 = _gcd($tmp, $gcd1); |
|
429
|
13
|
|
|
|
|
32
|
@frac = ($tmp / $gcd2, ($frac1[1] / $gcd1) * ($frac2[1] / $gcd2)); |
|
430
|
13
|
|
|
|
|
22
|
$tags[$RED_STATE] = 'IS_REDUCED'; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
17
|
100
|
66
|
|
|
521
|
if ((_tag($AUTO, \@tags) eq 'AUTO') and (not $skipauto) and |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
433
|
|
|
|
|
|
|
($tags[$SIZE] eq 'SMALL') and ($frac[0] =~ /[eE]/ or $frac[1] =~ /[eE]/)) |
|
434
|
|
|
|
|
|
|
{ |
|
435
|
1
|
|
|
|
|
4
|
(@frac1[0 .. 1], @frac2[0 .. 1]) = map { Math::BigInt->new($_) } (@frac1, @frac2); |
|
|
4
|
|
|
|
|
216
|
|
|
436
|
1
|
|
|
|
|
37
|
$tags[$SIZE] = 'BIG'; |
|
437
|
1
|
|
|
|
|
2
|
$skipauto = 1; |
|
438
|
1
|
|
|
|
|
2
|
redo LOOP; |
|
439
|
|
|
|
|
|
|
} |
|
440
|
|
|
|
|
|
|
} |
|
441
|
16
|
|
|
|
|
47
|
return Math::FractionManip->new(@frac, @tags); |
|
442
|
|
|
|
|
|
|
} |
|
443
|
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
sub sub { |
|
445
|
1
|
|
|
1
|
1
|
8
|
my ($frac1, $frac2) = ($_[$_[2]], $_[not $_[2]]); # swap if needed |
|
446
|
1
|
50
|
|
|
|
5
|
$frac1 = Math::FractionManip->new($frac1, 'CONVERTED') if ref($frac1) ne "Math::FractionManip"; |
|
447
|
1
|
50
|
|
|
|
4
|
$frac2 = Math::FractionManip->new($frac2, 'CONVERTED') if ref($frac2) ne "Math::FractionManip"; |
|
448
|
|
|
|
|
|
|
|
|
449
|
1
|
|
|
|
|
3
|
$frac2 = Math::FractionManip->new($frac2->{frac}[0], -$frac2->{frac}[1], @{ $frac2->{tags} }); |
|
|
1
|
|
|
|
|
4
|
|
|
450
|
|
|
|
|
|
|
|
|
451
|
1
|
|
|
|
|
3
|
return $frac1 + $frac2; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub mul { |
|
455
|
7
|
|
|
7
|
1
|
12
|
my @frac1 = @{ $_[0]{frac} }; |
|
|
7
|
|
|
|
|
17
|
|
|
456
|
7
|
|
|
|
|
11
|
my @tags1 = @{ $_[0]{tags} }; |
|
|
7
|
|
|
|
|
14
|
|
|
457
|
7
|
|
|
|
|
11
|
my (@frac2, @frac, @tags2); |
|
458
|
7
|
100
|
|
|
|
18
|
@frac2 = @{ $_[1]->{frac} }, @tags2 = @{ $_[1]->{tags} } if ref($_[1]) eq "Math::FractionManip"; |
|
|
3
|
|
|
|
|
20
|
|
|
|
3
|
|
|
|
|
6
|
|
|
459
|
7
|
100
|
|
|
|
20
|
@frac2 = (_from_decimal($_[1])), $tags2[$INTERNAL] = 'CONVERTED' if ref($_[1]) ne "Math::FractionManip"; |
|
460
|
7
|
|
|
|
|
24
|
my @tags = _tags_preserve([@tags1], [@tags2]); |
|
461
|
7
|
|
|
|
|
16
|
my $skipauto = 0; |
|
462
|
|
|
|
|
|
|
LOOP: { |
|
463
|
7
|
100
|
|
|
|
8
|
if (_tag($REDUCE, \@tags) eq 'NO_REDUCE') { |
|
|
8
|
|
|
|
|
16
|
|
|
464
|
2
|
|
|
|
|
7
|
@frac = ($frac1[0] * $frac2[0], $frac1[1] * $frac2[1]); |
|
465
|
|
|
|
|
|
|
} |
|
466
|
|
|
|
|
|
|
else { |
|
467
|
6
|
|
|
|
|
12
|
my ($gcd1, $gcd2) = (_gcd($frac1[0], $frac2[1]), _gcd($frac2[0], $frac1[1])); |
|
468
|
6
|
|
|
|
|
15
|
$frac[0] = ($frac1[0] / $gcd1) * ($frac2[0] / $gcd2); |
|
469
|
6
|
|
|
|
|
11
|
$frac[1] = ($frac1[1] / $gcd2) * ($frac2[1] / $gcd1); |
|
470
|
6
|
|
|
|
|
9
|
$tags[$RED_STATE] = 'IS_REDUCED'; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
8
|
100
|
66
|
|
|
221
|
if ((_tag($AUTO, \@tags) eq 'AUTO') and (not $skipauto) and |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
473
|
|
|
|
|
|
|
($tags[$SIZE] eq 'SMALL') and ($frac[0] =~ /[eE]/ or $frac[1] =~ /[eE]/)) |
|
474
|
|
|
|
|
|
|
{ |
|
475
|
1
|
|
|
|
|
3
|
(@frac1[0 .. 1], @frac2[0 .. 1]) = map { Math::BigInt->new($_) } (@frac1, @frac2); |
|
|
4
|
|
|
|
|
120
|
|
|
476
|
1
|
|
|
|
|
37
|
$tags[$SIZE] = 'BIG'; |
|
477
|
1
|
|
|
|
|
2
|
$skipauto = 1; |
|
478
|
1
|
|
|
|
|
2
|
redo LOOP; |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
} |
|
481
|
7
|
|
|
|
|
21
|
return Math::FractionManip->new(@frac, @tags); |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
sub div { |
|
485
|
1
|
|
|
1
|
1
|
4
|
my ($frac1, $frac2) = ($_[$_[2]], $_[not $_[2]]); # swap if needed |
|
486
|
1
|
50
|
|
|
|
5
|
$frac1 = Math::FractionManip->new($frac1, 'CONVERTED') if ref($frac1) ne "Math::FractionManip"; |
|
487
|
1
|
50
|
|
|
|
4
|
$frac2 = Math::FractionManip->new($frac2, 'CONVERTED') if ref($frac2) ne "Math::FractionManip"; |
|
488
|
|
|
|
|
|
|
|
|
489
|
1
|
|
|
|
|
4
|
$frac2 = Math::FractionManip->new($frac2->{frac}[1], $frac2->{frac}[0], @{ $frac2->{tags} }); |
|
|
1
|
|
|
|
|
5
|
|
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
#Makes a copy of the fraction with the num and den switched. |
|
492
|
|
|
|
|
|
|
|
|
493
|
1
|
|
|
|
|
3
|
return $frac1 * $frac2; |
|
494
|
|
|
|
|
|
|
} |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
sub pow { |
|
497
|
2
|
|
|
2
|
1
|
6
|
my (@frac, @frac1, @tags1); |
|
498
|
2
|
50
|
|
|
|
9
|
@frac1 = @{ $_[$_[2]]->{frac} }, @tags1 = @{ $_[$_[2]]->{tags} } if ref($_[$_[2]]) eq "Math::FractionManip"; |
|
|
2
|
|
|
|
|
7
|
|
|
|
2
|
|
|
|
|
5
|
|
|
499
|
2
|
50
|
|
|
|
7
|
@frac1 = _from_decimal($_[$_[2]]) if ref($_[$_[2]]) ne "Math::FractionManip"; |
|
500
|
2
|
|
|
|
|
4
|
my $frac2; |
|
501
|
2
|
50
|
|
|
|
5
|
$frac2 = $_[not $_[2]]->decimal if ref($_[not $_[2]]) eq "Math::FractionManip"; |
|
502
|
2
|
50
|
|
|
|
6
|
$frac2 = $_[not $_[2]] if ref($_[not $_[2]]) ne "Math::FractionManip"; |
|
503
|
2
|
|
|
|
|
5
|
my @tags = @tags1; |
|
504
|
2
|
|
|
|
|
3
|
my $skipauto = 0; |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
LOOP: { |
|
507
|
2
|
|
|
|
|
3
|
@frac = ($frac1[0] ** $frac2, $frac1[1] ** $frac2); |
|
|
2
|
|
|
|
|
10
|
|
|
508
|
|
|
|
|
|
|
|
|
509
|
2
|
50
|
33
|
|
|
5
|
if ((_tag($AUTO, \@tags) eq 'AUTO') and (not $skipauto) and |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
510
|
|
|
|
|
|
|
($tags[$SIZE] eq 'SMALL') and ($frac[0] =~ /[eE]/ or $frac[1] =~ /[eE]/)) |
|
511
|
|
|
|
|
|
|
{ |
|
512
|
0
|
|
|
|
|
0
|
@frac1 = map { Math::BigInt->new($_) } @frac1; |
|
|
0
|
|
|
|
|
0
|
|
|
513
|
0
|
|
|
|
|
0
|
$tags[$SIZE] = 'BIG'; |
|
514
|
0
|
|
|
|
|
0
|
$skipauto = 1; |
|
515
|
0
|
|
|
|
|
0
|
redo LOOP; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
|
|
|
|
|
|
} |
|
518
|
|
|
|
|
|
|
|
|
519
|
2
|
|
|
|
|
7
|
return Math::FractionManip->new(@frac, @tags); |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub sqrt { |
|
523
|
1
|
|
|
1
|
1
|
907
|
my $self = shift; |
|
524
|
1
|
|
|
|
|
3
|
my @frac = @{ $self->{frac} }; |
|
|
1
|
|
|
|
|
4
|
|
|
525
|
1
|
|
|
|
|
3
|
my @tags = @{ $self->{tags} }; |
|
|
1
|
|
|
|
|
3
|
|
|
526
|
1
|
|
|
|
|
2
|
my $ans; |
|
527
|
1
|
50
|
|
|
|
3
|
if (ref($frac[0])) { |
|
528
|
0
|
|
|
|
|
0
|
$frac[0] = Math::BigFloat->new(Math::BigFloat::fsqrt($frac[0], $DEF{CURRENT}{DIGITS})); |
|
529
|
0
|
|
|
|
|
0
|
$frac[1] = Math::BigFloat->new(Math::BigFloat::fsqrt($frac[1], $DEF{CURRENT}{DIGITS})); |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
else { |
|
532
|
1
|
|
|
|
|
3
|
@frac = (sqrt($frac[0]), sqrt($frac[1])); |
|
533
|
|
|
|
|
|
|
} |
|
534
|
1
|
|
|
|
|
4
|
return Math::FractionManip->new(@frac, @tags); |
|
535
|
|
|
|
|
|
|
} |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub abs { |
|
538
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
539
|
0
|
|
|
|
|
0
|
my @frac = @{ $self->{frac} }; |
|
|
0
|
|
|
|
|
0
|
|
|
540
|
0
|
|
|
|
|
0
|
my @tags = @{ $self->{tags} }; |
|
|
0
|
|
|
|
|
0
|
|
|
541
|
0
|
|
|
|
|
0
|
return Math::FractionManip->new(abs($frac[0]), abs($frac[1]), @tags, 'IS_REDUCED'); |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
sub cmp { |
|
545
|
0
|
|
|
0
|
1
|
0
|
my @frac1 = @{ $_[0]->{frac} }; |
|
|
0
|
|
|
|
|
0
|
|
|
546
|
0
|
|
|
|
|
0
|
my @tags1 = @{ $_[0]->{tags} }; |
|
|
0
|
|
|
|
|
0
|
|
|
547
|
0
|
|
|
|
|
0
|
my (@frac2, @frac, @tags2, $x, $y); |
|
548
|
0
|
0
|
|
|
|
0
|
@frac2 = @{ $_[1]->{frac} }, @tags2 = @{ $_[1]->{tags} } if ref($_[1]) eq "Math::FractionManip"; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
549
|
0
|
0
|
|
|
|
0
|
@frac2 = _from_decimal($_[1]), @tags2 = qw(CONVERTED) if ref($_[1]) ne "Math::FractionManip"; |
|
550
|
0
|
|
|
|
|
0
|
my @tags = _tags_preserve([@tags1], [@tags2]); |
|
551
|
0
|
0
|
|
|
|
0
|
if (_tag($REDUCE, \@tags) == 'NO_REDUCE') { |
|
552
|
0
|
|
|
|
|
0
|
$x = $frac1[0] * $frac2[1]; |
|
553
|
0
|
|
|
|
|
0
|
$y = $frac2[0] * $frac1[1]; |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
else { |
|
556
|
0
|
|
|
|
|
0
|
my $gcd1 = _gcd($frac1[1], $frac2[1]); |
|
557
|
0
|
|
|
|
|
0
|
$x = $frac1[0] * ($frac2[1] / $gcd1); |
|
558
|
0
|
|
|
|
|
0
|
$y = $frac2[0] * ($frac1[1] / $gcd1); |
|
559
|
|
|
|
|
|
|
} |
|
560
|
0
|
|
|
|
|
0
|
return $x <=> $y; |
|
561
|
|
|
|
|
|
|
} |
|
562
|
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
################################ |
|
564
|
|
|
|
|
|
|
# These functions are internal |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
sub _fix_num { |
|
567
|
67
|
|
|
67
|
|
90
|
my $tagsref = shift; |
|
568
|
67
|
|
|
|
|
113
|
my @return = @_; |
|
569
|
67
|
|
|
|
|
91
|
my $auto = _tag($AUTO, $tagsref) eq 'AUTO'; |
|
570
|
67
|
|
|
|
|
97
|
$tagsref->[$SIZE] = _tag($SIZE, $tagsref); |
|
571
|
67
|
50
|
|
|
|
123
|
$tagsref->[$SIZE] = 'SMALL' if $auto; |
|
572
|
67
|
|
|
|
|
73
|
my $num; |
|
573
|
67
|
|
|
|
|
90
|
my $decimal = 0; |
|
574
|
67
|
|
|
|
|
93
|
foreach $num (@return) { |
|
575
|
133
|
50
|
|
|
|
444
|
if (ref($num) eq "Math::BigFloat") { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
576
|
0
|
0
|
|
|
|
0
|
$tagsref->[$SIZE] = 'BIG' unless $auto; |
|
577
|
0
|
|
|
|
|
0
|
$decimal = 1; |
|
578
|
|
|
|
|
|
|
} |
|
579
|
|
|
|
|
|
|
elsif (ref($num) eq "Math::BigInt") { |
|
580
|
4
|
50
|
|
|
|
8
|
$tagsref->[$SIZE] = 'BIG' unless $auto; |
|
581
|
|
|
|
|
|
|
} |
|
582
|
|
|
|
|
|
|
elsif (ref($num)) { |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
# do nothing |
|
585
|
|
|
|
|
|
|
} |
|
586
|
|
|
|
|
|
|
elsif ($num =~ /[\.\e]/) { |
|
587
|
9
|
|
|
|
|
11
|
$decimal = 1; |
|
588
|
|
|
|
|
|
|
} |
|
589
|
133
|
50
|
|
|
|
189
|
if ($auto) { |
|
590
|
133
|
|
|
|
|
312
|
$num =~ /[\+\-]?\s*0*([0-9]*)\s*\.?\s*([0-9]*)0*/; |
|
591
|
133
|
|
|
|
|
319
|
my $length = length($1) + length($2); |
|
592
|
133
|
100
|
|
|
|
244
|
$tagsref->[$SIZE] = 'BIG' if $length > 15; |
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
} |
|
595
|
67
|
100
|
|
|
|
120
|
if ($tagsref->[$SIZE] eq 'BIG') { |
|
596
|
2
|
50
|
|
|
|
6
|
@return = map { Math::BigInt->new("$_") } @return if not $decimal; |
|
|
4
|
|
|
|
|
138
|
|
|
597
|
2
|
50
|
|
|
|
127
|
@return = map { Math::BigFloat->new("$_") } @return if $decimal; |
|
|
0
|
|
|
|
|
0
|
|
|
598
|
|
|
|
|
|
|
} |
|
599
|
67
|
100
|
66
|
|
|
203
|
if ($tagsref->[$SIZE] eq 'SMALL' and $auto) { |
|
600
|
65
|
|
|
|
|
99
|
@return = map { "$_" + 0 } @return; |
|
|
129
|
|
|
|
|
296
|
|
|
601
|
|
|
|
|
|
|
} |
|
602
|
67
|
|
|
|
|
160
|
return ($decimal, @return); |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub _fix_auto { |
|
606
|
6
|
|
|
6
|
|
8
|
my $direction = shift; |
|
607
|
6
|
|
|
|
|
9
|
my $tagsref = shift; |
|
608
|
6
|
|
|
|
|
25
|
my @return = @_; |
|
609
|
6
|
|
|
|
|
9
|
$tagsref->[$SIZE] = 'SMALL'; |
|
610
|
6
|
|
|
|
|
8
|
my $num; |
|
611
|
6
|
|
|
|
|
13
|
foreach $num (@return) { |
|
612
|
12
|
|
|
|
|
59
|
$num =~ /[\+\-]?\s*0*([0-9]*)\s*\.?\s*([0-9]*)0*/; |
|
613
|
12
|
|
|
|
|
37
|
my $length = length($1) + length($2); |
|
614
|
12
|
50
|
|
|
|
23
|
$tagsref->[$SIZE] = 'BIG' if $length > 15; |
|
615
|
|
|
|
|
|
|
} |
|
616
|
6
|
50
|
33
|
|
|
31
|
if ($tagsref->[$SIZE] eq 'BIG' and $direction eq 'BOTH') { |
|
|
|
50
|
|
|
|
|
|
|
617
|
0
|
|
|
|
|
0
|
@return = map { Math::BigInt->new("$_") } @return; |
|
|
0
|
|
|
|
|
0
|
|
|
618
|
|
|
|
|
|
|
} |
|
619
|
|
|
|
|
|
|
elsif ($tagsref->[$SIZE] eq 'SMALL') { |
|
620
|
6
|
|
|
|
|
11
|
@return = map { "$_" + 0 } @return; |
|
|
12
|
|
|
|
|
40
|
|
|
621
|
|
|
|
|
|
|
} |
|
622
|
6
|
|
|
|
|
13
|
return (@return); |
|
623
|
|
|
|
|
|
|
} |
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
sub _is_decimal { |
|
626
|
302
|
100
|
|
302
|
|
526
|
return undef unless defined $_[0]; |
|
627
|
254
|
|
|
|
|
653
|
my $return = $_[0] =~ /^\s*[\+\-0-9eE\.]+\s*$/; |
|
628
|
254
|
|
|
|
|
885
|
return $return; |
|
629
|
|
|
|
|
|
|
} |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
sub _reduce { |
|
632
|
33
|
|
|
33
|
|
43
|
my @frac = @_; |
|
633
|
33
|
|
|
|
|
68
|
my $gcd = _gcd(@frac); |
|
634
|
33
|
100
|
|
|
|
57
|
if ($gcd == 1) { |
|
635
|
27
|
|
|
|
|
58
|
return (0, @frac); |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
else { |
|
638
|
6
|
|
|
|
|
15
|
return (1, $frac[0] / $gcd, $frac[1] / $gcd); |
|
639
|
|
|
|
|
|
|
} |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub _simplify_sign { |
|
643
|
55
|
|
|
55
|
|
79
|
my @frac = @_; |
|
644
|
55
|
|
|
|
|
66
|
my $sign = 1; |
|
645
|
55
|
100
|
|
|
|
117
|
$sign = ($frac[0] / CORE::abs($frac[0])) * ($frac[1] / CORE::abs($frac[1])) if $frac[0]; |
|
646
|
55
|
|
|
|
|
861
|
@frac = ($sign * CORE::abs($frac[0]), CORE::abs($frac[1])); |
|
647
|
55
|
|
|
|
|
374
|
return @frac; |
|
648
|
|
|
|
|
|
|
} |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
sub _tags { |
|
651
|
70
|
|
|
70
|
|
111
|
my @return = (undef, undef); |
|
652
|
70
|
|
|
|
|
117
|
my ($NUM, $VALUE) = (0, 1); |
|
653
|
|
|
|
|
|
|
|
|
654
|
70
|
|
|
|
|
110
|
foreach (@_) { |
|
655
|
194
|
100
|
|
|
|
332
|
next if not $TAGS{$_}; |
|
656
|
81
|
|
|
|
|
93
|
my ($num, $value) = @{ $TAGS{$_} }; |
|
|
81
|
|
|
|
|
146
|
|
|
657
|
81
|
|
|
|
|
140
|
$return[$num] = $value; |
|
658
|
|
|
|
|
|
|
} |
|
659
|
|
|
|
|
|
|
|
|
660
|
70
|
|
|
|
|
150
|
return @return; |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub _tag { |
|
664
|
416
|
|
|
416
|
|
479
|
my $item = shift; |
|
665
|
416
|
|
|
|
|
473
|
my $return; |
|
666
|
|
|
|
|
|
|
my $ref; |
|
667
|
416
|
|
|
|
|
607
|
foreach $ref (@_, $DEF{CURRENT}{TAGS}) { |
|
668
|
769
|
100
|
|
|
|
788
|
last if $return = ${$ref}[$item]; |
|
|
769
|
|
|
|
|
1289
|
|
|
669
|
|
|
|
|
|
|
} |
|
670
|
416
|
|
|
|
|
1044
|
return $return; |
|
671
|
|
|
|
|
|
|
} |
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
sub _tagnum { |
|
674
|
7
|
|
|
7
|
|
12
|
my $item = shift; |
|
675
|
7
|
50
|
|
|
|
17
|
if (exists $TAGS{$item}) { |
|
676
|
7
|
|
|
|
|
14
|
return $TAGS{$item}[0]; |
|
677
|
|
|
|
|
|
|
} |
|
678
|
|
|
|
|
|
|
else { |
|
679
|
0
|
|
|
|
|
0
|
return -1; |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub _tags_preserve { |
|
684
|
23
|
|
|
23
|
|
24
|
my @tags1 = @{ $_[0] }; |
|
|
23
|
|
|
|
|
40
|
|
|
685
|
23
|
|
|
|
|
29
|
my @tags2 = @{ $_[1] }; |
|
|
23
|
|
|
|
|
35
|
|
|
686
|
23
|
|
|
|
|
29
|
my @tags; |
|
687
|
23
|
50
|
|
|
|
52
|
if ($tags1[$INTERNAL] eq 'CONVERTED') { |
|
|
|
100
|
|
|
|
|
|
|
688
|
0
|
|
|
|
|
0
|
@tags = @tags2; |
|
689
|
|
|
|
|
|
|
} |
|
690
|
|
|
|
|
|
|
elsif ($tags2[$INTERNAL] eq 'CONVERTED') { |
|
691
|
10
|
|
|
|
|
20
|
@tags = @tags1; |
|
692
|
|
|
|
|
|
|
} |
|
693
|
|
|
|
|
|
|
else { |
|
694
|
13
|
50
|
|
|
|
25
|
@tags = map { $tags1[$_] eq $tags2[$_] and $tags1[$_] } (0 .. $#tags1); |
|
|
51
|
|
|
|
|
131
|
|
|
695
|
|
|
|
|
|
|
} |
|
696
|
23
|
|
|
|
|
54
|
return @tags; |
|
697
|
|
|
|
|
|
|
} |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
sub _gcd { |
|
700
|
71
|
|
|
71
|
|
127
|
my ($x, $y) = (CORE::abs($_[0]), CORE::abs($_[1])); |
|
701
|
71
|
50
|
|
|
|
96
|
if (ref($x)) { |
|
702
|
0
|
|
|
|
|
0
|
$x = Math::BigInt->new($x->bgcd($y)); |
|
703
|
|
|
|
|
|
|
} |
|
704
|
|
|
|
|
|
|
else { |
|
705
|
|
|
|
|
|
|
{ |
|
706
|
71
|
50
|
|
|
|
94
|
$x = 1, last if $y > 1e17; # If this is so % will thinks its a zero so if |
|
|
71
|
|
|
|
|
113
|
|
|
707
|
|
|
|
|
|
|
# $y>1e17 will simply will basicly give up and |
|
708
|
|
|
|
|
|
|
# have it return 1 as the GCD. |
|
709
|
71
|
|
|
|
|
72
|
my ($x0); |
|
710
|
71
|
|
|
|
|
107
|
while ($y != 0) { |
|
711
|
179
|
|
|
|
|
192
|
$x0 = $x; |
|
712
|
179
|
|
|
|
|
235
|
($x, $y) = ($y, $x % $y); |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# Note $x0 = $x, $x = $y, $y= $x % $y Before the Swith |
|
715
|
179
|
100
|
66
|
|
|
587
|
$x = 1, last if ($x0 > 99999999 or $x > 999999999) and int($x0 / $x) * $x + $y != $x0; |
|
|
|
|
100
|
|
|
|
|
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
# This is to see if the mod operater through up on us when dealing with |
|
718
|
|
|
|
|
|
|
# large numbers. If it did set the gcd = 1 and quit. |
|
719
|
|
|
|
|
|
|
} |
|
720
|
|
|
|
|
|
|
} |
|
721
|
|
|
|
|
|
|
} |
|
722
|
71
|
|
|
|
|
105
|
return $x; |
|
723
|
|
|
|
|
|
|
} |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
sub _de_decimal { |
|
726
|
3
|
|
|
3
|
|
5
|
my @frac = @_; |
|
727
|
3
|
|
|
|
|
4
|
my @return; |
|
728
|
3
|
|
|
|
|
6
|
my $big = _tag($SIZE, $_[2]); |
|
729
|
3
|
|
|
|
|
5
|
my (@int_part, @decimal_part); |
|
730
|
3
|
|
|
|
|
16
|
($int_part[0], $decimal_part[0]) = $frac[0] =~ /(\d+)\.(\d+)/; |
|
731
|
3
|
|
|
|
|
14
|
($int_part[1], $decimal_part[1]) = $frac[1] =~ /(\d+)\.(\d+)/; |
|
732
|
3
|
|
|
|
|
14
|
@decimal_part = sort { $a <=> $b } (length($decimal_part[0]), length($decimal_part[1])); |
|
|
3
|
|
|
|
|
9
|
|
|
733
|
3
|
|
|
|
|
6
|
my $factor = 10 ** $decimal_part[1]; |
|
734
|
3
|
|
|
|
|
8
|
@frac = ($_[0] * $factor, $_[1] * $factor); |
|
735
|
3
|
|
|
|
|
6
|
return @frac; |
|
736
|
|
|
|
|
|
|
} |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
sub _from_decimal { |
|
739
|
13
|
|
|
13
|
|
34
|
my $decimal = shift; # the decimal (1.312671267127) |
|
740
|
13
|
50
|
|
|
|
25
|
my $big = 'BIG' if ref($decimal); |
|
741
|
13
|
|
|
|
|
105
|
my ($repeat); # flag to keep track if it is repeating or not |
|
742
|
|
|
|
|
|
|
my ($sign); |
|
743
|
13
|
|
|
|
|
0
|
my ($factor, $int_factor); |
|
744
|
13
|
|
|
|
|
0
|
my ($factor2); |
|
745
|
13
|
|
|
|
|
0
|
my ($whole_num, $whole_num_len); |
|
746
|
13
|
|
|
|
|
0
|
my ($int_part); # integer part (1) |
|
747
|
13
|
|
|
|
|
0
|
my ($decimal_part, $decimal_part_len); # decimal part (312671267127) |
|
748
|
13
|
|
|
|
|
0
|
my ($decimal_part2); # decimal part - last bit \/ (312671267) |
|
749
|
13
|
|
|
|
|
0
|
my ($pat, $pat_len); # repeating pat (1267) |
|
750
|
13
|
|
|
|
|
0
|
my ($pat_lastb); # last bit of repeating pat (127) |
|
751
|
13
|
|
|
|
|
0
|
my ($beg_part, $beg_part_len); # non-repeating part (3) |
|
752
|
13
|
|
|
|
|
0
|
my ($other_part, $other_part_len); # repeating part (1267126712127) |
|
753
|
13
|
|
|
|
|
0
|
my ($frac1, $frac2, $frac3); |
|
754
|
|
|
|
|
|
|
|
|
755
|
13
|
|
|
|
|
53
|
my $rnd_mode = $Math::BigFloat::rnd_mode; # to avoid problems with incon. |
|
756
|
13
|
|
|
|
|
67
|
$Math::BigFloat::rnd_mode = 'trunc'; # rounding |
|
757
|
|
|
|
|
|
|
|
|
758
|
13
|
|
|
|
|
233
|
$decimal = "$decimal"; |
|
759
|
13
|
|
|
|
|
22
|
$decimal =~ s/\s//g; |
|
760
|
13
|
|
|
|
|
35
|
($sign, $int_part, $decimal_part) = $decimal =~ /([\+\-]?)\s*(\d*)\.(\d+)$/; |
|
761
|
13
|
|
|
|
|
23
|
$sign .= '1'; |
|
762
|
13
|
|
|
|
|
16
|
$decimal_part_len = length($decimal_part); |
|
763
|
13
|
100
|
|
|
|
24
|
$int_part = "" unless $int_part; |
|
764
|
13
|
|
|
|
|
24
|
$factor = '1' . '0' x (length($decimal_part)); |
|
765
|
13
|
50
|
|
|
|
21
|
$factor = Math::BigFloat->new($factor) if $big; |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# Make it a BigFloat now to simplfy latter |
|
768
|
13
|
|
|
|
|
19
|
$int_factor = '1' . '0' x (length($int_part)); |
|
769
|
13
|
|
|
|
|
14
|
$beg_part_len = 0; |
|
770
|
|
|
|
|
|
|
OuterBlock: |
|
771
|
13
|
|
|
|
|
32
|
while ($beg_part_len < $decimal_part_len) { |
|
772
|
4
|
|
|
|
|
7
|
$beg_part = substr($decimal_part, 0, $beg_part_len); |
|
773
|
4
|
|
|
|
|
7
|
$other_part = substr($decimal_part, $beg_part_len); |
|
774
|
4
|
|
|
|
|
16
|
$other_part_len = length($other_part); |
|
775
|
4
|
|
|
|
|
5
|
my $i; |
|
776
|
4
|
|
|
|
|
14
|
for ($i = 1; $i < ($other_part_len / 2 + 1); $i++) { |
|
777
|
4
|
|
|
|
|
8
|
$pat = substr($other_part, 0, $i); |
|
778
|
4
|
|
|
|
|
6
|
$pat_len = $i; |
|
779
|
4
|
|
|
|
|
6
|
local $_ = $other_part; |
|
780
|
4
|
|
|
|
|
18
|
$repeat = undef; |
|
781
|
4
|
|
|
|
|
7
|
while (1) { |
|
782
|
21
|
|
|
|
|
101
|
($_) = /^$pat(.*)/; |
|
783
|
21
|
|
|
|
|
30
|
my $length = length($_); |
|
784
|
|
|
|
|
|
|
|
|
785
|
21
|
100
|
|
|
|
35
|
if ($length <= $pat_len) { |
|
786
|
4
|
50
|
|
|
|
11
|
last unless $length; |
|
787
|
4
|
|
|
|
|
17
|
$pat_lastb = substr($pat, 0, $length); |
|
788
|
4
|
100
|
|
|
|
13
|
$repeat = 1, last OuterBlock if $pat_lastb eq $_; |
|
789
|
2
|
50
|
|
|
|
8
|
if ($pat_lastb eq $_ - 1) { |
|
790
|
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
# this is needed to see if it really is the repeating fracton |
|
792
|
|
|
|
|
|
|
# we intented it to be. If we don't do this 1.1212 would become |
|
793
|
|
|
|
|
|
|
# 1120/999 = 1.1211211211. |
|
794
|
|
|
|
|
|
|
# The first three lines converts it to a fraction and the |
|
795
|
|
|
|
|
|
|
# rests tests it to the actual repeating decimal/ |
|
796
|
|
|
|
|
|
|
# The NO_REDUCE flag is their to save time as reducing large |
|
797
|
|
|
|
|
|
|
# fraction can take a bit of time which is unnecessary as we will |
|
798
|
|
|
|
|
|
|
# be converting it to a decimal. |
|
799
|
2
|
|
|
|
|
18
|
$decimal_part2 = substr($decimal_part, 0, $decimal_part_len - length($pat_lastb)); |
|
800
|
2
|
|
|
|
|
6
|
$factor2 = '1' . '0' x (length($decimal_part2)); |
|
801
|
2
|
|
|
|
|
16
|
$frac1 = Math::FractionManip->new('0' . $beg_part, 1 . 0 x $beg_part_len, 'NO_REDUCE', $big); |
|
802
|
2
|
|
|
|
|
12
|
$frac2 = Math::FractionManip->new('0' . $pat, 9 x $pat_len . 0 x $beg_part_len, 'NO_REDUCE', $big); |
|
803
|
2
|
|
|
|
|
13
|
$frac3 = $frac1 + $frac2; |
|
804
|
2
|
|
|
|
|
14
|
my $what_i_get = $frac3->decimal; |
|
805
|
2
|
|
|
|
|
10
|
my $places = length($what_i_get); |
|
806
|
2
|
50
|
|
|
|
9
|
my $decimal_p_tmp = $decimal_part2 if not $big; |
|
807
|
2
|
50
|
|
|
|
7
|
$decimal_p_tmp = Math::BigFloat->new($decimal_part2) if $big; |
|
808
|
2
|
|
|
|
|
11
|
my $what_i_should_get = (($decimal_p_tmp) / $factor2) . "$pat" x ($places); |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
# The rest of this is doing nothing more but trying to compare |
|
811
|
|
|
|
|
|
|
# the what_i_get and what_i_should_get but becuse the stupid |
|
812
|
|
|
|
|
|
|
# BigFloat module is so pragmentic all this hopla is nessary |
|
813
|
2
|
50
|
|
|
|
6
|
$what_i_should_get = Math::BigFloat->new($what_i_should_get) if $big; |
|
814
|
2
|
50
|
|
|
|
4
|
$what_i_should_get = $what_i_should_get->fround(length($what_i_get) - 1) if $big; |
|
815
|
2
|
50
|
|
|
|
3
|
$what_i_should_get = Math::BigFloat->new($what_i_should_get) if $big; |
|
816
|
|
|
|
|
|
|
# ^^ Needed because the fround method does not return a BigFloat object! |
|
817
|
|
|
|
|
|
|
|
|
818
|
2
|
50
|
|
|
|
4
|
my $pass = "$what_i_get" eq "$what_i_should_get" if $big; |
|
819
|
2
|
50
|
|
|
|
16
|
$pass = $what_i_get == $what_i_should_get if not $big; |
|
820
|
2
|
50
|
|
|
|
11
|
$repeat = 1, last OuterBlock if ($pass); |
|
821
|
|
|
|
|
|
|
} |
|
822
|
|
|
|
|
|
|
} |
|
823
|
|
|
|
|
|
|
} |
|
824
|
|
|
|
|
|
|
} |
|
825
|
0
|
|
|
|
|
0
|
$beg_part_len++; |
|
826
|
|
|
|
|
|
|
} |
|
827
|
13
|
100
|
|
|
|
21
|
if ($repeat) { |
|
828
|
4
|
|
|
|
|
15
|
$frac1 = Math::FractionManip->new('0' . $beg_part, 1 . 0 x $beg_part_len, $big); |
|
829
|
4
|
|
|
|
|
16
|
$frac2 = Math::FractionManip->new('0' . $pat, 9 x $pat_len . 0 x $beg_part_len, $big); |
|
830
|
4
|
50
|
|
|
|
10
|
$int_part = Math::FractionManip->new('0' . $int_part, 1, 'BIG') if $big; |
|
831
|
4
|
|
|
|
|
11
|
$frac3 = $sign * ($int_part + $frac1 + $frac2); |
|
832
|
4
|
|
|
|
|
12
|
return @{ $frac3->{frac} }; |
|
|
4
|
|
|
|
|
19
|
|
|
833
|
|
|
|
|
|
|
} |
|
834
|
|
|
|
|
|
|
else { |
|
835
|
9
|
|
|
|
|
51
|
return ($decimal * $factor, $factor, $big); |
|
836
|
|
|
|
|
|
|
} |
|
837
|
0
|
|
|
|
|
|
$Math::BigFloat::rnd_mode = $rnd_mode; # set it back to what it was. |
|
838
|
|
|
|
|
|
|
} |
|
839
|
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
1; |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
__END__ |