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