File Coverage

blib/lib/Math/BaseCalc.pm
Criterion Covered Total %
statement 60 60 100.0
branch 20 22 90.9
condition 6 6 100.0
subroutine 8 8 100.0
pod 4 4 100.0
total 98 100 98.0


line stmt bran cond sub pod time code
1 6     6   32924 use strict;
  6         26  
  6         283  
2             package Math::BaseCalc;
3             {
4             $Math::BaseCalc::VERSION = '1.019';
5             }
6 6     6   31 use Carp;
  6         13  
  6         4007  
7              
8             sub new {
9 11     11 1 5487 my ($pack, %opts) = @_;
10 11         27 my $self = bless {}, $pack;
11 11         36 $self->{has_dash} = 0;
12 11         35 $self->digits($opts{digits});
13 11         30 return $self;
14             }
15              
16             sub digits {
17 23     23 1 4364 my $self = shift;
18 23 50       65 if (@_) {
19             # Set the value
20              
21              
22 23 100       60 if (ref $_[0]) {
23 16         24 $self->{digits} = [ @{ shift() } ];
  16         55  
24             } else {
25 7         19 my $name = shift;
26 7         16 my %digitsets = $self->_digitsets;
27 7 50       22 croak "Unrecognized digit set '$name'" unless exists $digitsets{$name};
28 7         58 $self->{digits} = $digitsets{$name};
29             }
30 23         47 foreach my $digit (@{$self->{digits}}) {
  23         50  
31 256 100       616 if ($digit eq '-') {
    100          
32 2         7 $self->{has_dash} = 1;
33             } elsif ($digit eq '.') {
34 1         2 $self->{has_dot} = 1;
35             }
36             }
37              
38 23         48 $self->{trans} = {};
39             # Build the translation table back to numbers
40 23         55 @{$self->{trans}}{@{$self->{digits}}} = 0..$#{$self->{digits}};
  23         148  
  23         42  
  23         49  
41              
42             }
43 23         43 return @{$self->{digits}};
  23         52  
44             }
45              
46              
47             sub _digitsets {
48             return (
49 7     7   140 'bin' => [0,1],
50             'hex' => [0..9,'a'..'f'],
51             'HEX' => [0..9,'A'..'F'],
52             'oct' => [0..7],
53             '64' => ['A'..'Z','a'..'z',0..9,'+','/'],
54             '62' => [0..9,'a'..'z','A'..'Z'],
55             );
56             }
57              
58             sub from_base {
59 67     67 1 3200 my $self = shift;
60 67 100 100     346 return -1*$self->from_base(substr($_[0],1)) if !$self->{has_dash} && $_[0] =~ /^-/; # Handle negative numbers
61 64         111 my $str = shift;
62 64         91 my $dignum = @{$self->{digits}};
  64         106  
63              
64             # Deal with stuff after the decimal point
65 64         94 my $add_in = 0;
66 64 100 100     277 if (!$self->{has_dot} && $str =~ s/\.(.+)//) {
67 2         7 $add_in = $self->from_base(reverse $1)/$dignum**length($1);
68             }
69              
70 64         122 $str = reverse $str;
71 64         95 my $result = 0;
72 64         96 my $trans = $self->{trans};
73 64         141 while (length $str) {
74             ## no critic
75 248 100       551 return undef unless exists $trans->{substr($str,0,1)};
76             # For large numbers, force result to be an integer (not a float)
77 246         581 $result = int($result*$dignum + $trans->{chop $str});
78             }
79              
80             # The bizarre-looking next line is necessary for proper handling of very large numbers
81 62 100       175 return $add_in ? $result + $add_in : $result;
82             }
83              
84             sub to_base {
85 57     57 1 19799 my ($self,$num) = @_;
86 57 100       159 return '-'.$self->to_base(-1*$num) if $num<0; # Handle negative numbers
87              
88 56         260 my $dignum = @{$self->{digits}};
  56         107  
89              
90 56         96 my $result = '';
91 56         134 while ($num>0) {
92 204         8732 substr($result,0,0) = $self->{digits}[ $num % $dignum ];
93 6     6   1987 use integer;
  6         53  
  6         39  
94 204         5396 $num /= $dignum;
95             #$num = (($num - ($num % $dignum))/$dignum); # An alternative to the above
96             }
97 56 100       540 return length $result ? $result : $self->{digits}[0];
98             }
99              
100              
101             1;
102             __END__