Math::Bytes

Mayukh Bose

Doing Math in Computer Units

Themes

Adjust presentation theme to suit projector:
Black (default) - White - League - Sky - Beige - Simple
Serif - Blood - Night - Moon - Solarized

Why?

  • Several situations where I've worked with data like this:
    ``` [/home mb@raven 1252191]$ ls -lh -rw-r--r--. 1 vcm vcm 1.3M May 16 2015 m1252191-99_TINY.wmv -rw-r--r--. 1 vcm vcm 2.1M May 16 2015 m1252191-99_VERYLOW.flv -rw-r--r--. 1 vcm vcm 2.1M May 16 2015 m1252191-99_VERYLOW.mp4 -rw-r--r--. 1 vcm vcm 2.1M May 16 2015 m1252191-99_VERYLOW.webm -rw-r--r--. 1 vcm vcm 2.2M May 16 2015 m1252191-99_VERYLOW.wmv -rw-r--r--. 1 vcm vcm 60K May 16 2015 m1252191.jpg ```
  • Notice that some data is in KB, others in MB, something else could be in TB.
  • Quite often, it happens to be late at night when I'm looking at the data

The Problems

  • When it is late at night, 60 KB may appear to be larger than 1.2 MB, because 60 > 1.2
  • Is 7823.5K greater than 7.8M or not?
  • What if I have to sum up the sizes of groups of files from a list?
  • How many CDs do I need to backup a 7.25 GB file?

Searched CPAN yet?

  • Number::Bytes::Human does something similar, but not quite what I want
    ``` use Number::Bytes::Human qw(format_bytes parse_bytes); # The standard way my $bytes = parse_bytes('1.0K'); # 1024 my $bytes = parse_bytes('1.0KB'); # 1000, SI unit # The OO way $human = Number::Bytes::Human->new(bs => 1000, si => 1); $bytes = $human->parse('10MB'); # 10*1000*1000 $bytes = $human->parse('10MiB'); # 10*1024*1024 $bytes = $human->parse('10M'); # Error, no SI unit ```
  • Has a few issues...

Issues With This Module

  • Calculates sizes differently if unit is 'K' vs. 'KB' (not what I want).
    ``` use Number::Bytes::Human qw(parse_bytes); my $bytes = parse_bytes('1.0K'); # 1024 my $bytes = parse_bytes('1.0KB'); # 1000, SI unit ```
  • Works with K and KB, but not M and MB (M causes error in parse per docs)
  • Can't do arithmetic in KB, MB, GB etc.
  • Author says the module is alpha-software and it has been in alpha for about 10 years now.

Why Write my Own Module

  • Because the other examples don't do everything I want.
  • I haven't written a module in a while
  • In particular, I haven't mucked with perl's operator overloading features

What I Want

  • Want to be able to specify sizes and units explicitly.
  • Want to easily convert from one unit to another.
  • Want to be able to do arithmetic and comparisons.
  • Want to be able to print the data in the same unit that I created the object.
continued...

Use Cases: Create Sizes Explicitly

  • my $file_size = Math::Bytes->KB(25.2);
  • my $file_size = Math::Bytes->new(25.2, 'KB');
  • my $file_size = Math::Bytes->parse('25.2 KB');
  • my $file_size = Math::Bytes->parse('25.2KB');
  • my $file_size = Math::Bytes->parse('25.2 K');
  • Can create for bytes (B), KB, MB, GB, TB, PB, EB

Use Cases: Converting

  • Convert from One Unit to Another
  • For example:
    ``` my $file_size = Math::Bytes->KB(2523); print $file_size->to_bytes() . " bytes\n"; my $file_size2 = $file_size->to_MB(); my $file_size3 = $file_size->to_GB(); ```
  • Allows conversion to bytes, KB, MB, GB, TB, PB, EB

Use Cases: Arithmetic: Addition

  • I have an object of size 25KB and want to add 1200 bytes of padding at the end.
  • I have 5 objects of various sizes and I want to add them all
  • For example:
    ``` my $file_size = Math::Bytes->KB(25); my $padding = 1200; my $new_file_size = $file_size + $padding; my $file_size2 = Math::Bytes->MB(6.1); my $file_size3 = Math::Bytes->new(7.2, 'KB'); my $padding2 = Math::Bytes->bytes(2000); my $total_size = $new_file_size + $file_size2 + $file_size3 + $padding2; ```

Use Cases: Arithmetic: Subtraction

  • I have an object of size 25.2KB and want to subtract 900 bytes of header.
  • I have a large concatenated file and I want to see how much is saved by removing certain files from it.
  • For example:
    ``` my $file_size = Math::Bytes->KB(25.2); my $header_size = 900; my $data_size = $file_size - $header_size; my $large_file_size = Math::Bytes->MB(6.1); my $small_file_size = Math::Bytes->KB(1200); my $small_file_size2 = Math::Bytes->new(1300, 'KB'); my $smaller_size = $large_file_size - $small_file_size - $small_file_size2; ```

Use Cases: Arithmetic: Multiplication

  • I have 5 objects each X KB in size. How much space do they take.
  • For example:
    ``` my $file_size = Math::Bytes->KB(15.2); my $total_size = $file_size * 5; ```
  • Does not make sense to multiply two Math::Bytes objects together, so throw error in this case.

Use Cases: Arithmetic: Division

  • I have a large file and I want to know how many CDs I need to burn it.
  • I have a large file that I want to divide into 7 parts. What is the size of each part.
  • For example:
    ``` my $file_size = Math::Bytes->GB(15.2); my $cd_size = Math::Bytes->MB(640); my $num_cds = $file_size / $cd_size; print "# of CDs needed: $num_cds\n"; my $file_size2 = Math::Bytes->TB(1.25); my $num_parts = 7; my $part_size = $file_size2 / $num_parts; ```
  • Notice that the result of the first calculation is dimensionless

Use Cases: Comparison

  • I have an object of size 1200KB and another of 1.3 MB. Which is larger?
  • Sort a bunch of Math::Bytes object
  • For example:
    ``` my $file_size = Math::Bytes->KB(1200); my $file_size2 = Math::Bytes->MB(1.3); print "File1 is smaller\n" if ($file_size < $file_size2); ```

Use Cases: Printing

  • I have an object that I did a bunch of arithmetic on and want the final size.
  • Sort a bunch of Math::Bytes objects
  • For example:
    ``` my $file_size = Math::Bytes->KB(25); my $padding = 1200; my $new_file_size = $file_size + $padding; print "New file size = $new_file_size\n"; # Prints in the same unit as $file_size my $cd_size = Math::Bytes->GB(4.7); print "cd has ", $cd_size->to_KB, " kilobytes\n"; #Example Converting from one unit to another (including precision) # Convert to 4 decimal places precision my $cd_size = Math::Bytes->new(4.7, 'GB', {precision => 4}); print "cd has ", $cd_size->to_TB, " terabytes\n"; ```

Links and References