File Coverage

blib/lib/Math/BaseCalc.pm
Criterion Covered Total %
statement 61 61 100.0
branch 16 18 88.8
condition 3 3 100.0
subroutine 9 9 100.0
pod 4 4 100.0
total 93 95 97.8


line stmt bran cond sub pod time code
1             package Math::BaseCalc;
2              
3 5     5   54513 use strict;
  5         11  
  5         206  
4 5     5   28 use Carp;
  5         11  
  5         547  
5 5     5   37 use vars qw($VERSION);
  5         14  
  5         4609  
6             $VERSION = '1.014';
7              
8             sub new {
9 8     8 1 41212 my ($pack, %opts) = @_;
10 8         33 my $self = bless {}, $pack;
11 8         46 $self->{has_dash} = 0;
12 8         31 $self->digits($opts{digits});
13 8         27 return $self;
14             }
15              
16             sub digits {
17 20     20 1 6310 my $self = shift;
18 20 50       69 if (@_) {
19             # Set the value
20              
21              
22 20 100       62 if (ref $_[0]) {
23 13         21 $self->{digits} = [ @{ shift() } ];
  13         64  
24             } else {
25 7         14 my $name = shift;
26 7         18 my %digitsets = $self->_digitsets;
27 7 50       26 croak "Unrecognized digit set '$name'" unless exists $digitsets{$name};
28 7         90 $self->{digits} = $digitsets{$name};
29             }
30 20         44 $self->{has_dash} = grep { $_ eq '-' } @{$self->{digits}};
  250         431  
  20         51  
31              
32 20         43 $self->{trans} = {};
33             # Build the translation table back to numbers
34 20         57 @{$self->{trans}}{@{$self->{digits}}} = 0..$#{$self->{digits}};
  20         236  
  20         38  
  20         58  
35              
36             }
37 20         45 return @{$self->{digits}};
  20         56  
38             }
39              
40              
41             sub _digitsets {
42             return (
43 7     7   238 'bin' => [0,1],
44             'hex' => [0..9,'a'..'f'],
45             'HEX' => [0..9,'A'..'F'],
46             'oct' => [0..7],
47             '64' => ['A'..'Z','a'..'z',0..9,'+','/'],
48             '62' => [0..9,'a'..'z','A'..'Z'],
49             );
50             }
51              
52             sub from_base {
53 45     45 1 3826 my $self = shift;
54 45 100 100     263 return -1*$self->from_base(substr($_[0],1)) if !$self->{has_dash} && $_[0] =~ /^-/; # Handle negative numbers
55 42         67 my $str = shift;
56 42         56 my $dignum = @{$self->{digits}};
  42         83  
57              
58             # Deal with stuff after the decimal point
59 42         61 my $add_in = 0;
60 42 100       118 if ($str =~ s/\.(.+)//) {
61 2         7 $add_in = $self->from_base(reverse $1)/$dignum**length($1);
62             }
63              
64 42         77 $str = reverse $str;
65 42         58 my $result = 0;
66 42         68 my $trans = $self->{trans};
67 42         104 while (length $str) {
68             ## no critic
69 188 100       429 return undef unless exists $trans->{substr($str,0,1)};
70             # For large numbers, force result to be an integer (not a float)
71 186         511 $result = int($result*$dignum + $trans->{chop $str});
72             }
73              
74             # The bizarre-looking next line is necessary for proper handling of very large numbers
75 40 100       145 return $add_in ? $result + $add_in : $result;
76             }
77              
78             sub to_base {
79 35     35 1 8911 my ($self,$num) = @_;
80 35 100       108 return '-'.$self->to_base(-1*$num) if $num<0; # Handle negative numbers
81              
82 34         193 my $dignum = @{$self->{digits}};
  34         74  
83              
84 34         60 my $result = '';
85 34         90 while ($num>0) {
86 146         6315 substr($result,0,0) = $self->{digits}[ $num % $dignum ];
87 5     5   2847 use integer;
  5         47  
  5         33  
88 146         3970 $num /= $dignum;
89             #$num = (($num - ($num % $dignum))/$dignum); # An alternative to the above
90             }
91 34 100       406 return length $result ? $result : $self->{digits}[0];
92             }
93              
94              
95             1;
96             __END__