File Coverage

blib/lib/Number/FormatEng.pm
Criterion Covered Total %
statement 59 59 100.0
branch 30 30 100.0
condition 9 9 100.0
subroutine 11 11 100.0
pod 5 6 83.3
total 114 115 99.1


line stmt bran cond sub pod time code
1             package Number::FormatEng;
2              
3 4     4   199999 use warnings;
  4         41  
  4         142  
4 4     4   23 use strict;
  4         9  
  4         114  
5 4     4   20 use Carp qw(croak);
  4         8  
  4         187  
6 4     4   1238 use POSIX qw(floor);
  4         19447  
  4         18  
7 4     4   4922 use Scalar::Util qw(looks_like_number);
  4         10  
  4         2469  
8              
9             require Exporter;
10             our @ISA = qw(Exporter);
11             our @EXPORT_OK = qw(format_eng format_pref unformat_pref use_e_zero no_e_zero);
12             our %EXPORT_TAGS = (all => \@EXPORT_OK);
13              
14             our $VERSION = '0.03';
15              
16             my %prefix = (
17             '-8' => 'y', '8' => 'Y',
18             '-7' => 'z', '7' => 'Z',
19             '-6' => 'a', '6' => 'E',
20             '-5' => 'f', '5' => 'P',
21             '-4' => 'p', '4' => 'T',
22             '-3' => 'n', '3' => 'G',
23             '-2' => 'u', '2' => 'M',
24             '-1' => 'm', '1' => 'k',
25             '0' => '' ,
26             );
27             my %exponent = reverse %prefix;
28              
29             my $no_e_zero = 1;
30              
31             sub use_e_zero {
32 1     1 1 1 $no_e_zero = 0;
33             }
34              
35             sub no_e_zero {
36 1     1 1 2 $no_e_zero = 1;
37             }
38              
39             sub format_pref {
40 47     47 1 2325 return format_num(1, @_);
41             }
42              
43             sub format_eng {
44 40     40 1 2442 return format_num(0, @_);
45             }
46              
47             sub format_num {
48 87     87 0 118 my $prefix_mode = shift;
49 87         112 my $num = shift;
50              
51 87 100       166 my $name = ($prefix_mode) ? 'format_pref' : 'format_eng';
52              
53             # Check validity of input
54 87 100       170 unless (defined $num) {
55 4         437 croak("Error: $name requires numeric input. ",
56             'It seems like no input was provided or input was undefined');
57             }
58 83 100       208 unless (looks_like_number($num)) {
59 8         695 croak("Error: $name requires numeric input. '$num' is not numeric");
60             }
61              
62 75 100       156 if ($num == 0) {
63 8 100 100     28 if ($prefix_mode or $no_e_zero) {
64 6         46 return '0';
65             }
66             else {
67 2         10 return '0e0';
68             }
69             }
70              
71 67 100       122 my $sign = ($num < 0) ? '-' : '';
72 67         90 $num = abs $num;
73              
74 67 100       102 if ($prefix_mode) {
75 38 100 100     138 if ( ($num >= 1e27) or ($num <= 1e-25) ) {
76             # switch to number exponent mode
77 5         6 $prefix_mode = 0;
78             }
79             }
80              
81 67         268 my $e = floor( log($num) / log(1000) );
82 67         141 my $mult = 1000**$e;
83 67         484 $num = 0 + sprintf '%.6f', ($num / $mult);
84              
85 67 100       140 if ($prefix_mode) {
86 33         246 return $sign . $num . $prefix{$e};
87             }
88             else {
89 34 100 100     132 if ($no_e_zero and ($e == 0)) {
90 9         68 return $sign . $num;
91             }
92             else {
93 25         179 return $sign . $num . 'e' . 3*$e;
94             }
95             }
96             }
97              
98             sub unformat_pref {
99 46     46 1 4151 my ($num) = @_;
100              
101             # Check validity of input
102 46 100       95 unless (defined $num) {
103 2         208 croak('Error: unformat_pref requires input. ',
104             'It seems like no input was provided or input was undefined');
105             }
106              
107             # Trim leading and trailing whitespace
108 44         127 $num =~ s/^\s+//;
109 44         90 $num =~ s/\s+$//;
110              
111 44 100       77 unless (length $num) {
112 2         162 croak('Error: unformat_pref requires input. ',
113             'It seems like no input was provided');
114             }
115              
116 42         66 my $prefix = substr $num, -1;
117 42 100       87 if (exists $exponent{$prefix}) {
118 26         39 chop $num;
119 26 100       76 unless (looks_like_number($num)) {
120 2         158 croak("Error: unformat_pref input '$num' is not numeric before prefix '$prefix'");
121             }
122 24         88 $num = $num * (1000**$exponent{$prefix});
123             }
124             else {
125 16 100       50 unless (looks_like_number($num)) {
126 4         321 croak("Error: unformat_pref input '$num' is not numeric");
127             }
128             }
129              
130 36         125 return $num;
131             }
132              
133              
134             =head1 NAME
135              
136             Number::FormatEng - Format a number using engineering notation
137              
138             =head1 VERSION
139              
140             This document refers to Number::FormatEng version 0.03.
141              
142             =head1 SYNOPSIS
143              
144             use Number::FormatEng qw(:all);
145             print format_eng(1234); # prints 1.234e3
146             print format_pref(-0.035); # prints -35m
147             unformat_pref('1.23T'); # returns 1.23e+12
148              
149             =head1 DESCRIPTION
150              
151             Format a number for printing using engineering notation.
152             Engineering notation is similar to scientific notation except that
153             the power of ten must be a multiple of three.
154             Alternately, the number can be formatted using an International
155             System of Units (SI) prefix representing a factor of a thousand.
156              
157             =head1 SUBROUTINES
158              
159             =over 4
160              
161             =item format_eng($number)
162              
163             Format a numeric value using engineering notation. This function
164             returns a string whose exponent is a multiple of 3. Here are some examples:
165              
166             format_eng(1234); # returns 1.234e3
167             format_eng(-0.03); # returns -30e-3
168             format_eng(7.8e7); # returns 78e6
169              
170             Since floating-point arithmetic is performed, rounding may occur.
171              
172             =item format_pref($number)
173              
174             Format a numeric value using engineering notation. This function
175             returns a string using one of the following SI prefixes (representing a
176             power of a thousand):
177              
178             m u n p f a z y
179             k M G T P E Z Y
180              
181             Notice that lower-case C is used instead of the Greek letter Mu.
182              
183             If the number is beyond the prefix ranges (y and Y), then C
184             returns the same formatted string as C. In other words, it
185             does not use an SI prefix.
186              
187             Here are some examples:
188              
189             format_pref(1234); # returns 1.234k
190             format_pref(-0.0004); # returns -400u
191             format_pref(1.27e13); # returns 12.7T
192             format_pref(7.5e60); # returns 7.5e60
193              
194             Since floating-point arithmetic is performed, rounding may occur.
195              
196             =item unformat_pref($string)
197              
198             Convert a string formatted using C into a numeric value.
199             Here are some examples:
200              
201             unformat_pref('1.23T'); # returns 1.23e+12
202             unformat_pref('-400u'); # returns -4e-4
203             unformat_pref(37.5); # returns 37.5
204              
205             =item use_e_zero() and no_e_zero()
206              
207             By default, if the exponent is zero, C is not displayed by
208             C. To explicitly display C, use the C method.
209             Use the C method to return to the default behavior.
210              
211             format_eng(55); # returns 55
212             Number::FormatEng::use_e_zero();
213             format_eng(55); # now returns 55e0
214             Number::FormatEng::no_e_zero();
215             format_eng(55); # back to 55
216              
217             =back
218              
219             =head1 EXPORT
220              
221             Nothing is exported by default. Functions may be exported individually, or
222             all functions may be exported at once, using the special tag C<:all>.
223              
224             =head1 DIAGNOSTICS
225              
226             Error conditions cause the program to die using C from the
227             L Core module.
228              
229             =head1 BUGS AND LIMITATIONS
230              
231             There are no known bugs in this module.
232              
233             =head1 SEE ALSO
234              
235             Refer to the following website:
236              
237             L
238              
239             =head1 AUTHOR
240              
241             Gene Sullivan (gsullivan@cpan.org)
242              
243             =head1 ACKNOWLEDGEMENTS
244              
245             Influenced by the following PerlMonks: BrowserUk, GrandFather and repellent.
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             Copyright (c) 2009 Gene Sullivan. All rights reserved.
250              
251             This module is free software; you can redistribute it and/or modify
252             it under the same terms as Perl itself. See L.
253              
254             =cut
255              
256             1;
257