File Coverage

blib/lib/Data/IEEE754/Tools.pm
Criterion Covered Total %
statement 93 93 100.0
branch 58 60 96.6
condition 6 6 100.0
subroutine 18 18 100.0
pod 7 7 100.0
total 182 184 98.9


line stmt bran cond sub pod time code
1             package Data::IEEE754::Tools;
2 6     6   77916 use 5.006;
  6         15  
3 6     6   19 use warnings;
  6         5  
  6         116  
4 6     6   17 use strict;
  6         12  
  6         87  
5 6     6   16 use Carp;
  6         6  
  6         359  
6 6     6   19 use Exporter 'import'; # just use the import() function, without the rest of the overhead of ISA
  6         6  
  6         176  
7            
8 6     6   2142 use version 0.77; our $VERSION = version->declare('0.011_004'); # underscore makes it "alpha"/"developer" on CPAN, so it will go thru CPAN TESTERS, but not distribute to the world
  6         7992  
  6         28  
9            
10             =pod
11            
12             =head1 NAME
13            
14             Data::IEEE754::Tools - Various tools for understanding and manipulating the underlying IEEE-754 representation of floating point values
15            
16             =head1 SYNOPSIS
17            
18             use Data::IEEE754::Tools qw/:floatingpoint :ulp/;
19            
20             # return -12.875 as decimal and hexadecimal floating point numbers
21             to_dec_floatingpoint(-12.875); # -0d1.6093750000000000p+0003
22             to_hex_floatingpoint(-12.875); # -0x1.9c00000000000p+0003
23            
24             # shows the smallest value you can add or subtract to 16.16 (ulp = "Unit in the Last Place")
25             print ulp( 16.16 ); # 3.5527136788005e-015
26            
27             # toggles the ulp: returns a float that has the ULP of 16.16 toggled
28             # (if it was a 1, it will be 0, and vice versa);
29             # running it twice should give the original value
30             print $t16 = toggle_ulp( 16.16 ); # 16.159999999999997
31             print $v16 = toggle_ulp( $t16 ); # 16.160000000000000
32            
33             =head1 DESCRIPTION
34            
35             *** ALPHA RELEASE v0.011_004: trying out a bugfix with CPAN Testers (since the bug
36             doesn't show up in any of my machines or perl versions, but is all throughout
37             CPAN Testers reports ***
38            
39             These tools give access to the underlying IEEE 754 floating-point 64bit representation
40             used by many instances of Perl (see L). They include functions for converting
41             from the 64bit internal representation to a string that shows those bits (either as
42             hexadecimal or binary) and back, functions for converting that encoded value
43             into a more human-readable format to give insight into the meaning of the encoded
44             values, and functions to manipulate the smallest possible change for a given
45             floating-point value (which is the L or
46             "Unit in the Last Place").
47            
48             =head2 IEEE 754 Encoding
49            
50             The L standard describes
51             various floating-point encodings. The double format (`binary64') is a 64-bit base-2
52             encoding, and correpsonds to the usual Perl floating value (NV). The format includes the
53             sign (s), the power of 2 (q), and a significand (aka, mantissa; the coefficient, c):
54             C. The C<(-1)**s> term evaluates to the sign of the
55             number, where s=0 means the sign is +1 and s=1 means the sign is -1.
56            
57             For most numbers, the coefficient is an implied 1 plus an encoded fraction,
58             which is itself encoded as a 52-bit integer divided by an implied 2**52. The range of
59             valid exponents is from -1022 to +1023, which are encoded as an 11bit integer from 1
60             to 2046 (where C). With an 11bit integer,
61             there are two exponent values (C<0b000_0000_0000 = 0 - 1023 = -1023> and
62             C<0b111_1111_1111 = 2047 - 1023 = +1024>), which are used to indicate conditions outside
63             the normal range: The first special encoded-exponent, C<0b000_0000_0000>, indicates that
64             the coefficient is 0 plus the encoded fraction, at an exponent of -1022; thus, the
65             floating-point zero is encoded using an encoded-exponent of 0 and an encoded-fraction of 0
66             (C<[0 + 0/(2**52)] * [2**-1022] = 0*(2**-1022) = 0>); other numbers
67             smaller than can normally be encoded (so-called "denormals" or "subnormals"), lying
68             between 0 and 1 (non-inclusive) are encoded with the same exponent, but have a non-zero
69             encoded-fraction. The second special encoded-exponent, C<0b111_1111_1111>, indicates a
70             number that is infinite (too big to represent), or something that is not a number (NAN);
71             infinities are indicated by that special exponent and an encoded-fraction of 0; NAN
72             is indicated by that special exponent and a non-zero encoded-fraction.
73            
74             =head2 Justification for the existence of B
75            
76             L, or the equivalent L recipe L>, do a
77             good job of converting a perl floating value (NV) into the big-endian bytes
78             that encode that value, but they don't help you interpret the value.
79            
80             L has a similar suite of tools to B, but
81             uses numerical methods rather than accessing the underlying bits. It L
82             shown|http://perlmonks.org/?node_id=1167146> that its interpretation function can take
83             an order of magnitude longer than a routine that manipulates the underlying bits
84             to gather the information.
85            
86             This B module combines the two sets of functions, giving
87             access to the raw IEEE 754 encoding, or a stringification of the encoding which
88             interprets the encoding as a sign and a coefficient and a power of 2, or access to
89             the ULP and ULP-manipulating features, all using direct bit manipulation when
90             appropriate.
91            
92             =head2 Compatibility
93            
94             B works with 64bit floating-point representations.
95            
96             If you have a Perl setup which uses a larger representation (for example,
97             C; print $Config{nvsize}; # 16 =E 128bit>), values reported by
98             this module will be reduced in precision to fit the 64bit representation.
99            
100             If you have a Perl setup which uses a smaller representation (for example,
101             C; print $Config{nvsize}; # 4 =E 32bit>), the installation
102             will likely fail, because the unit tests were not set up for lower precision
103             inputs. However, forcing the installation I still allow coercion
104             from the smaller Perl NV into a true IEEE 754 double (64bit) floating-point,
105             but there is no guarantee it will work.
106            
107             =head1 EXPORTABLE FUNCTIONS AND VARIABLES
108            
109             =cut
110            
111             my @EXPORT_RAW754 = qw(hexstr754_from_double binstr754_from_double hexstr754_to_double binstr754_to_double);
112             my @EXPORT_FLOATING = qw(to_hex_floatingpoint to_dec_floatingpoint);
113             my @EXPORT_ULP = qw(ulp toggle_ulp nextup nextdown nextafter);
114            
115             our @EXPORT_OK = (@EXPORT_FLOATING, @EXPORT_RAW754, @EXPORT_ULP);
116             our %EXPORT_TAGS = (
117             floating => [@EXPORT_FLOATING],
118             floatingpoint => [@EXPORT_FLOATING],
119             raw754 => [@EXPORT_RAW754],
120             ulp => [@EXPORT_ULP],
121             all => [@EXPORT_OK],
122             );
123            
124             =head2 :raw754
125            
126             These are the functions to do raw conversion from a floating-point value to a hexadecimal or binary
127             string of the underlying IEEE754 encoded value, and back.
128            
129             =head3 hexstr754_from_double( I )
130            
131             Converts the floating-point I into a big-endian hexadecimal representation of the underlying
132             IEEE754 encoding.
133            
134             hexstr754_from_double(12.875); # 4029C00000000000
135             # ^^^
136             # : ^^^^^^^^^^^^^
137             # : :
138             # : `- fraction
139             # :
140             # `- sign+exponent
141            
142             The first three nibbles (hexadecimal digits) encode the sign and the exponent. The sign is
143             the most significant bit of the three nibbles (so AND the first nibble with 8; if it's true,
144             the number is negative, else it's positive). The remaining 11 bits of the nibbles encode the
145             exponent: convert the 11bits to decimal, then subtract 1023. If the resulting exponent is -1023,
146             it indicates a zero or denormal value; if the exponent is +1024, it indicates an infinite (Inf) or
147             not-a-number (NaN) value, which are generally used to indicate the calculation has grown to large
148             to fit in an IEEE754 double (Inf) or has tried an performed some other undefined operation (divide
149             by zero or the logarithm of a zero or negative value) (NaN).
150            
151             The final thirteen nibbles are the encoding of the fractional value (usually C<1 + thirteennibbles /
152             16**13>, unless it's zero, denormal, infinite, or not a number).
153            
154             Of course, this is easier to decode using the L function, which interprets
155             the sign, fraction, and exponent for you. (See below for more details.)
156            
157             to_dec_floatingpoint(12.875); # +0d1.6093750000000000p+0003
158             # ^ ^^^^^^^^^^^^^^^^^^ ^^^^
159             # : : :
160             # : `- coefficient `- exponent (power of 2)
161             # :
162             # `- sign
163            
164             =head3 binstr754_from_double( I )
165            
166             Converts the floating-point I into a big-endian binary representation of the underlying
167             IEEE754 encoding.
168            
169             binstr754_from_double(12.875); # 0100000000101001110000000000000000000000000000000000000000000000
170             # ^
171             # `- sign
172             # ^^^^^^^^^^^
173             # `- exponent
174             # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
175             # `- fraction
176            
177             The first bit is the sign, the next 11 are the exponent's encoding
178            
179             =head3 hexstr754_to_double( I )
180            
181             The inverse of I: it takes a string representing the 16 nibbles
182             of the IEEE754 double value, and converts it back to a perl floating-point value.
183            
184             print hexstr754_to_double('4029C00000000000');
185             12.875
186            
187             =head3 binstr754_to_double( I )
188            
189             The inverse of I: it takes a string representing the 64 bits
190             of the IEEE754 double value, and converts it back to a perl floating-point value.
191            
192             print binstr754_to_double('0100000000101001110000000000000000000000000000000000000000000000');
193             12.875
194            
195             =cut
196             # Perl 5.10 introduced the ">" and "<" modifiers for pack which can be used to
197             # force a specific endianness.
198             if( $] lt '5.010' ) {
199             my $str = join('', unpack("H*", pack 'L' => 0x12345678));
200             if('78563412' eq $str) { # little endian, so reverse byteorder
201             *hexstr754_from_double = sub { return uc unpack('H*' => reverse pack 'd' => shift); };
202             *binstr754_from_double = sub { return uc unpack('B*' => reverse pack 'd' => shift); };
203            
204             *hexstr754_to_double = sub { return unpack('d' => reverse pack 'H*' => shift); };
205             *binstr754_to_double = sub { return unpack('d' => reverse pack 'B*' => shift); };
206            
207             *arr2x32b_from_double = sub { return unpack('N2' => reverse pack 'd' => shift); };
208             } elsif('12345678' eq $str) { # big endian, so keep default byteorder
209             *hexstr754_from_double = sub { return uc unpack('H*' => pack 'd' => shift); };
210             *binstr754_from_double = sub { return uc unpack('B*' => pack 'd' => shift); };
211            
212             *hexstr754_to_double = sub { return unpack('d' => pack 'H*' => shift); };
213             *binstr754_to_double = sub { return unpack('d' => pack 'B*' => shift); };
214            
215             *arr2x32b_from_double = sub { return unpack('N2' => pack 'd' => shift); };
216             } else {
217             # I don't handle middle-endian / mixed-endian; sorry
218             *hexstr754_from_double = sub { undef };
219             *binstr754_from_double = sub { undef };
220            
221             *hexstr754_to_double = sub { undef };
222             *binstr754_to_double = sub { undef };
223             }
224             } else {
225 153     153   393 *hexstr754_from_double = sub { return uc unpack('H*' => pack 'd>' => shift); };
226 91     91   5834 *binstr754_from_double = sub { return uc unpack('B*' => pack 'd>' => shift); };
227            
228 1261     1261   151830 *hexstr754_to_double = sub { return unpack('d>' => pack 'H*' => shift); };
229 55     55   5755 *binstr754_to_double = sub { return unpack('d>' => pack 'B*' => shift); };
230            
231 270     270   602 *arr2x32b_from_double = sub { return unpack('N2' => pack 'd>' => shift); };
232             }
233            
234             =head2 :floatingpoint
235            
236             =head3 to_hex_floatingpoint( I )
237            
238             =head3 to_dec_floatingpoint( I )
239            
240             Converts value to a hexadecimal or decimal floating-point notation that indicates the sign and
241             the coefficient and the power of two, with the coefficient either in hexadecimal or decimal
242             notation.
243            
244             to_hex_floatingpoint(-3.9999999999999996) # -0x1.fffffffffffffp+0001
245             to_dec_floatingpoint(-3.9999999999999996) # -0d1.9999999999999998p+0001
246            
247             It displays the value as (sign)(0base)(implied).(fraction)p(exponent):
248            
249             =cut
250            
251             sub to_hex_floatingpoint {
252             # thanks to BrowserUK @ http://perlmonks.org/?node_id=1167146 for slighly better decision factors
253             # I tweaked it to use the two 32bit words instead of one 64bit word (which wouldn't work on some systems)
254 68     68 1 316 my $v = shift;
255 68         88 my ($msb,$lsb) = arr2x32b_from_double($v);
256 68         83 my $sbit = ($msb & 0x80000000) >> 31;
257 68 100       98 my $sign = $sbit ? '-' : '+';
258 68         62 my $exp = (($msb & 0x7FF00000) >> 20) - 1023;
259 68         197 my $mant = sprintf '%05x%08x', $msb & 0x000FFFFF, $lsb & 0xFFFFFFFF;
260 68 100       114 if($exp == 1024) {
261 12 100       63 return $sign . "0x1.#INF000000000p+0000" if $mant eq '0000000000000';
262 10 100 100     40 return $sign . "0x1.#IND000000000p+0000" if $mant eq '8000000000000' and $sign eq '-';
263 9 100       186 return $sign . ( (($msb & 0x00080000) != 0x00080000) ? "0x1.#SNAN00000000p+0000" : "0x1.#QNAN00000000p+0000");
264             }
265 56         51 my $implied = 1;
266 56 100       70 if( $exp == -1023 ) { # zero or denormal
267 6         5 $implied = 0;
268 6 100       10 $exp = $mant eq '0000000000000' ? 0 : -1022; # 0 for zero, -1022 for denormal
269             }
270 56         1073 sprintf '%s0x%1u.%13.13sp%+05d', $sign, $implied, $mant, $exp;
271             }
272            
273             sub to_dec_floatingpoint {
274             # based on to_hex_floatingpoint
275 68     68 1 62 my $v = shift;
276 68         78 my ($msb,$lsb) = arr2x32b_from_double($v);
277 68         98 my $sbit = ($msb & 0x80000000) >> 31;
278 68 100       95 my $sign = $sbit ? '-' : '+';
279 68         67 my $exp = (($msb & 0x7FF00000) >> 20) - 1023;
280 68         165 my $mant = sprintf '%05x%08x', $msb & 0x000FFFFF, $lsb & 0xFFFFFFFF;
281 68 100       112 if($exp == 1024) {
282 12 100       60 return $sign . "0d1.#INF000000000000p+0000" if $mant eq '0000000000000';
283 10 100 100     42 return $sign . "0d1.#IND000000000000p+0000" if $mant eq '8000000000000' and $sign eq '-';
284 9 100       170 return $sign . ( (($msb & 0x00080000) != 0x00080000) ? "0d1.#SNAN00000000000p+0000" : "0d1.#QNAN00000000000p+0000");
285             }
286 56         36 my $implied = 1;
287 56 100       71 if( $exp == -1023 ) { # zero or denormal
288 6         18 $implied = 0;
289 6 100       11 $exp = $mant eq '0000000000000' ? 0 : -1022; # 0 for zero, -1022 for denormal
290             }
291             #$mant = (($msb & 0x000FFFFF)*4_294_967_296.0 + ($lsb & 0xFFFFFFFF)*1.0) / (2.0**52);
292             #sprintf '%s0d%1u.%.16fp%+05d', $sign, $implied, $mant, $exp;
293 56         102 my $other = abs($v) / (2.0**$exp);
294 56         1241 sprintf '%s0d%.16fp%+05d', $sign, $other, $exp;
295             }
296            
297            
298             =over
299            
300             =item sign
301            
302             The I will be + or -
303            
304             =item 0base
305            
306             The I<0base> will be C<0x> for hexadecimal, C<0d> for decimal
307            
308             =item implied.fraction
309            
310             The I indicates the hexadecimal or decimal equivalent for the coefficient
311            
312             I will be 0 for zero or denormal numbers, 1 for everything else
313            
314             I will indicate infinities (#INF), signaling not-a-numbers (#SNAN), and quiet not-a-numbers (#QNAN).
315            
316             I will range from decimal 0.0000000000000000 to 0.9999999999999998 for zero thru all the denormals,
317             and from 1.0000000000000000 to 1.9999999999999998 for normal values.
318            
319             =item p
320            
321             The I

introduces the "power" of 2. (It is analogous to the C in C<1.0e3> introducing the power of 10 in a

322             standard decimal floating-point notation, but indicates that the exponent is 2**exp instead of 10**exp.)
323            
324             =item exponent
325            
326             The I is the power of 2. Is is always a decimal number, whether the coefficient's base is hexadecimal or decimal.
327            
328             +0d1.500000000000000p+0010
329             = 1.5 * (2**10)
330             = 1.5 * 1024.0
331             = 1536.0.
332            
333             The I can range from -1022 to +1023.
334            
335             Internally, the IEEE 754 representation uses the encoding of -1023 for zero and denormals; to
336             aid in understanding the actual number, the I conversions represent
337             them as +0000 for zero, and -1022 for denormals: since denormals are C<(0+fraction)*(2**min_exp)>,
338             they are really multiples of 2**-1022, not 2**-1023.
339            
340             =back
341            
342             =head2 :ulp
343            
344             =head3 ulp( I )
345            
346             Returns the ULP ("Unit in the Last Place") for the given I, which is the smallest number
347             that you can add to or subtract from I and still be able to discern a difference between
348             the original and modified. Under normal (or denormal) circumstances, C $val>
349             is true.
350            
351             If the I is a zero or a denormal, C will return the smallest possible denormal.
352            
353             Since INF and NAN are not really numbers, C will just return the same I. Because
354             of the way they are handled, C $val> no longer makes sense (infinity plus
355             anything is still infinity, and adding NAN to NAN is not numerically defined, so a numerical
356             comparison is meaningless on both).
357            
358             =cut
359            
360             sub ulp($) {
361 30     30 1 61 my $val = shift;
362 30         33 my $rawbin = binstr754_from_double($val);
363 30         93 my ($sign, $exp, $fract) = ($rawbin =~ /(.)(.{11})(.{52})/);
364            
365             # check for special conditions
366 30 100       78 if( $exp == '1'x11 ) { # return self for INF or NAN
    100          
367 12         23 return $val;
368             } elsif ( $exp == '0'x11 ) { # ZERO or DENORMAL: build (+)(exp:0)(fract:0...1)
369 6         5 $fract = '0'x51 . '1';
370 6         8 $rawbin = join '', '0', $exp, $fract;
371 6         8 return binstr754_to_double($rawbin);
372             }
373            
374             # calculate normal ULP
375 12         14 my $tog = toggle_ulp( $val );
376 12         19 return abs($val - $tog);
377             }
378            
379             =head3 toggle_ulp( I )
380            
381             Returns the orginal I, but with the ULP toggled. In other words, if the ULP bit
382             was a 0, it will return a value with the ULP of 1 (equivalent to adding one ULP to a positive
383             I); if the ULP bit was a 1, it will return a value with the ULP of 0 (equivalent to
384             subtracting one ULP from a positive I). Under normal (or denormal) circumstances,
385             C is true.
386            
387             Since INF and NAN are not really numbers, C will just return the same I. Because
388             of the way they are handled, C no longer makes sense.
389            
390             =cut
391            
392             sub toggle_ulp {
393 38     38 1 66 my $val = shift;
394 38         41 my $rawbin = binstr754_from_double($val);
395 38         107 my ($sign, $exp, $fract) = ($rawbin =~ /(.)(.{11})(.{52})/);
396            
397             # INF and NAN do not have a meaningful ULP; just return SELF
398 38 100       87 if( $exp == '1'x11 ) {
399 12         19 return $val;
400             }
401            
402             # ZERO, DENORMAL, and NORMAL: toggle the last bit of fract
403 26         28 my $ulp_bit = substr $fract, -1;
404 26         37 substr $fract, -1, 1, (1-$ulp_bit);
405 26         31 $rawbin = join '', $sign, $exp, $fract;
406 26         31 return binstr754_to_double($rawbin);
407             }
408            
409             =head3 nextup( I )
410            
411             Returns the next floating point value numerically greater than I; that is, it adds one ULP.
412             Returns infinite when I is the highest normal floating-point value.
413             Returns I when I is positive-infinite or NAN; returns the largest negative normal
414             floating-point value when I is negative-infinite.
415            
416             C is an IEEE 754r standard function.
417            
418             =cut
419            
420             sub nextup {
421             # thanks again to BrowserUK: http://perlmonks.org/?node_id=1167146
422 172     172 1 177 my $val = shift;
423 172 100       330 return $val if $val != $val; # interestingly, NAN != NAN
424 152         191 my $h754 = hexstr754_from_double($val);
425 152 100       259 return $val if $h754 eq '7FF0000000000000'; # return self for +INF
426 150 100       191 return hexstr754_to_double('FFEFFFFFFFFFFFFF') if $h754 eq 'FFF0000000000000'; # return largest negative for -INF
427 138 100       168 return hexstr754_to_double('0000000000000001') if $h754 eq '8000000000000000'; # return +SmallestDenormal for -ZERO
428 134         144 my ($msb,$lsb) = arr2x32b_from_double($val);
429 134 100       220 $lsb += ($msb & 0x80000000) ? -1.0 : +1.0;
430 134 100       227 if($lsb == 4_294_967_296.0) {
    100          
431 22         21 $lsb = 0.0;
432 22 50       31 $msb += ($msb & 0x80000000) ? -1.0 : +1.0;
433             } elsif ($lsb == -1.0) {
434 30 50       44 $msb += ($msb & 0x80000000) ? -1.0 : +1.0;
435             }
436 134         90 $msb &= 0xFFFFFFFF; # v0.011_001: potential bugfix: ensure 32bit MSB
437 134         85 $lsb &= 0xFFFFFFFF; # v0.011_001: potential bugfix: ensure 32bit MSB
438 134         401 return hexstr754_to_double( sprintf '%08X%08X', $msb, $lsb );
439             }
440            
441             =head3 nextdown( I )
442            
443             Returns the next floating point value numerically lower than I; that is, it subtracts one ULP.
444             Returns -infinity when I is the largest negative normal floating-point value.
445             Returns I when I is negative-infinite or NAN; returns the largest positive normal
446             floating-point value when I is positive-infinite.
447            
448             C is an IEEE 754r standard function.
449            
450             =cut
451            
452             sub nextdown {
453 86     86 1 176 return - nextup( - $_[0] );
454             }
455            
456             =head3 nextafter( I, I )
457            
458             Returns the next floating point value after I in the direction of I. If the
459             two are identical, return I; if I is numerically above I, return
460             C)>; if I is numerically below I, return C)>.
461            
462             C is an IEEE 754r standard function.
463            
464             =cut
465            
466             sub nextafter {
467 270 100   270 1 994 return $_[0] if $_[0] != $_[0]; # return value when value is NaN
468 160 100       254 return $_[1] if $_[1] != $_[1]; # return direction when direction is NaN
469 140 100       218 return $_[1] if $_[1] == $_[0]; # return direction when the two are equal
470 112 100       211 return nextup($_[0]) if $_[1] > $_[0]; # return nextup if direction > value
471 56         74 return nextdown($_[0]); # otherwise, return nextdown()
472             }
473            
474             =head2 :all
475            
476             Include all of the above.
477            
478             =head1 INSTALLATION
479            
480             To install this module, use your favorite CPAN client.
481            
482             For a manual install, type the following:
483            
484             perl Makefile.PL
485             make
486             make test
487             make install
488            
489             (On Windows machines, you may need to use "dmake" instead of "make".)
490            
491             =head1 SEE ALSO
492            
493             =over
494            
495             =item * L
496            
497             =item * L for
498             inspiring me to go down the IEEE754-expansion trail in perl.
499            
500             =item * L as a resource
501             for how perl interacts with the various "edge cases" (+/-infinity, L,
502             signaling and quiet L.
503            
504             =item * L: I really wanted to use this module, but it didn't get me very far down the "Tools" track,
505             and included a lot of overhead modules for its install/test that I didn't want to require for B.
506             However, I was inspired by his byteorder-dependent anonymous subs (which were in turn derived from L);
507             they were more efficient, on a per-call-to-subroutine basis, than my original inclusion of the if(byteorder) in every call to
508             the sub.
509            
510             =item * L: Similar to this module, but uses numeric manipulation.
511            
512             =back
513            
514             =head1 AUTHOR
515            
516             Peter C. Jones Cpetercj AT cpan DOT orgE>
517            
518             Please report any bugs or feature requests emailing Cbug-Data-IEEE754-Tools AT rt.cpan.orgE>
519             or thru the web interface at L.
520            
521             =head1 COPYRIGHT
522            
523             Copyright (C) 2016 Peter C. Jones
524            
525             =head1 LICENSE
526            
527             This program is free software; you can redistribute it and/or modify it
528             under the terms of either: the GNU General Public License as published
529             by the Free Software Foundation; or the Artistic License.
530            
531             See L for more information.
532            
533             =cut
534            
535             1;