File Coverage

blib/lib/Math/BigInt/Named/English.pm
Criterion Covered Total %
statement 74 74 100.0
branch 30 32 93.7
condition 11 12 91.6
subroutine 6 6 100.0
pod 1 1 100.0
total 122 125 97.6


line stmt bran cond sub pod time code
1             #!perl
2              
3             package Math::BigInt::Named::English;
4              
5 3     3   77350 use strict;
  3         15  
  3         95  
6 3     3   17 use warnings;
  3         7  
  3         85  
7              
8 3     3   459 use Math::BigInt::Named;
  3         7  
  3         26  
9             our @ISA = qw< Math::BigInt::Named >;
10              
11             our $VERSION = '0.07';
12              
13             my $SMALL = [ qw/
14             zero
15             one
16             two
17             three
18             four
19             five
20             six
21             seven
22             eight
23             nine
24             ten
25             eleven
26             twelve
27             thirteen
28             fourteen
29             fifteen
30             sixteen
31             seventeen
32             eighteen
33             nineteen
34             / ];
35              
36             my $TENS = [ qw /
37             ten
38             twenty
39             thirty
40             fourty
41             fifty
42             sixty
43             seventy
44             eighty
45             ninety
46             / ];
47              
48             my $HUNDREDS = [ qw /
49             one
50             two
51             three
52             four
53             five
54             six
55             seven
56             eight
57             nine
58             / ];
59              
60             my $TRIPLE = [ qw /
61             mi
62             bi
63             tri
64             quadri
65             penti
66             hexi
67             septi
68             octi
69             / ];
70              
71             sub name {
72 56     56 1 34637 my $x = shift;
73 56 50       154 $x = Math::BigInt -> new($x) unless ref($x);
74              
75 56         92 my $class = ref($x);
76              
77 56 50       152 return '' if $x -> is_nan();
78              
79 56         368 my $ret = '';
80 56         133 my $y = $x -> copy();
81 56         1101 my $rem;
82              
83 56 100       131 if ($y -> sign() eq '-') {
84 1         7 $ret = 'minus ';
85 1         12 $y -> babs();
86             }
87              
88 56 100       490 if ($y < 1000) {
89 45         5091 return $ret . $class -> _triple($y, 1, 0);
90             }
91              
92             # Split the number into numerical triplets.
93              
94 11         1208 my @num = ();
95 11         33 while (!$y -> is_zero()) {
96 25         331 ($y, $rem) = $y -> bdiv(1000);
97 25         5525 unshift @num, $rem;
98             }
99              
100             # Convert each numerical triplet into a string.
101              
102 11         146 my @str = ();
103 11         32 for my $i (0 .. $#num) {
104 25         42 my $num = $num[$i];
105 25         36 my $str;
106 25         42 my $index = $#num - $i;
107              
108 25         37 my $count;
109 25         55 $count = $class -> _triple($num, 0, $i);
110 25         1876 $str .= $count;
111              
112 25 100       75 if ($index > 0) {
113 14         76 my $triple_name = $class -> _triple_name($#num - $i, $num);
114 14         102 $str .= ' ' . $triple_name;
115             }
116              
117 25         62 $str[$i] = $str;
118             }
119              
120             # 1100 -> "one thousand one hundred" (not "one thousand and one hundred")
121             # 1099 -> "one thousand and ninety-nine" (not "one thousand ninety-nine")
122             # 1098 -> "one thousand and ninety-eight" (not "one thousand ninety-eight")
123             # ...
124             # 1001 -> "one thousand and one" (not "one thousand one")
125             # 1000 -> "one thousand" (not "one thousand and zero")
126              
127 11 100 66     57 if (@num > 1 && 0 < $num[-1] && $num[-1] < 100) {
      100        
128 5         1116 splice @str, -1, 0, "and";
129             }
130              
131 11         1256 $ret . join(" ", grep /\S/, @str);
132             }
133              
134             sub _triple_name {
135 49     49   1336 my ($self, $index, $number) = @_;
136             # index => 0 hundreds, tens and ones
137             # index => 1 thousands
138             # index => 2 millions
139              
140 49 100 100     197 return '' if $index == 0 || $number -> is_zero();
141 44 100       753 return 'thousand' if $index == 1;
142              
143 35         62 my $postfix = 'llion';
144 35         57 my $plural = 's';
145 35 100       90 if (($index & 1) == 1) {
146 16         30 $postfix = 'lliard';
147             }
148 35 100       79 $postfix .= $plural unless $number -> is_one();
149 35         511 $index -= 2;
150 35         172 return $TRIPLE -> [$index >> 1] . $postfix;
151             }
152              
153             sub _triple {
154             # return name of a triple
155             # input: number >= 0, < 1000
156             # only true if triple is the only triple
157 70     70   144 my ($self, $number, $only) = @_;
158              
159             # 0 => null, but only if there is just one triple
160 70 100 100     152 return '' if $number -> is_zero() && !$only;
161              
162             # we have the full name for these
163 65 100       864 return $SMALL -> [$number] if $number <= $#$SMALL;
164              
165             # New code:
166              
167 30         3250 my @num = ();
168 30         89 $num[1] = $number % 100; # tens and ones
169 30         5354 $num[0] = ($number - $num[1]) / 100; # hundreds
170              
171 30         9056 my @str = ();
172              
173             # Do the hundreds, if any.
174              
175 30 100       99 if ($num[0]) {
176 18         435 my $str;
177 18         49 $str = $HUNDREDS -> [$num[0] - 1];
178 18         3730 $str .= " hundred";
179 18         48 push @str, $str;
180             }
181              
182             # Do the tens and ones, if any.
183              
184 30 100       337 if ($num[1]) {
185 19         434 my $str;
186 19         47 my $ones = $num[1] % 10;
187 19         3307 my $tens = ($num[1] - $ones) / 10;
188 19 100       6041 if ($num[1] <= $#$SMALL) {
189 3         309 $str = $SMALL -> [ $num[1] ];
190             } else {
191 16         1715 $str = $TENS -> [ $tens - 1];
192 16 100       3285 if ($ones > 0) {
193 15         2415 $str .= "-";
194 15         41 $str .= $SMALL -> [ $ones ];
195             }
196             }
197 19         623 push @str, $str;
198             }
199              
200 30         439 return join " and ", @str;
201             }
202              
203             1;
204              
205             __END__