File Coverage

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


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