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