Data-MATFile

 view release on metacpan or  search on metacpan

lib/Data/MATFile.pm  view on Meta::CPAN


    my $n = n_from_dim (\@dim);

Given the dimensions of a matrix, return the total number of
elements in the matrix.

=cut

sub n_from_dim
{
    my ($dim) = @_;
    my $n = 1;
    for (@$dim) {
        $n *= $_;
    }
    return $n;
}

=head2 get_doubles

    my $doubles = $obj->get_doubles ($n_bytes);

Get C<$n_bytes / 8> doubles and put them in an array.

=cut

sub get_doubles
{
    my ($obj, $n_bytes) = @_;
    if ($n_bytes % 8 != 0) {
        $obj->error ("Bad byte count $n_bytes for doubles");
    }
    my $n_doubles = $n_bytes / 8;
    my $bytes = $obj->read_bytes ($n_bytes);
    my @doubles;
    for (0..$n_doubles - 1) {
        my $double = parse_double (substr ($bytes, $_ * 8, 8));
        if ($obj->{verbose}) {
            printf "Got a $double.\n";
        }
        push @doubles, $double;
    }
    return \@doubles;
}

=head2 parse_double

    my $double = parse_double ($bytes);

This converts the MAT-File double (eight bytes, the IEEE 754 "double
64" format) into a Perl floating point number.

=cut

# http://www.perlmonks.org/bare/?node_id=703222

sub double_from_hex { unpack 'd', scalar reverse pack 'H*', $_[0] }

use constant POS_INF => double_from_hex '7FF0000000000000';
use constant NEG_INF => double_from_hex 'FFF0000000000000';
use constant NaN     => double_from_hex '7FF8000000000000';

sub parse_double
{
    my ($bytes) = @_;
    my ($bottom, $top) = unpack ("LL", $bytes);
    # Reference:
    # http://en.wikipedia.org/wiki/Double_precision_floating-point_format

    # Eight zero bytes represents 0.0.
    if ($bottom == 0) {
        if ($top == 0) {
            return 0;
        }
        elsif ($top == 0x80000000) {
            return -0;
        }
        elsif ($top == 0x7ff00000) {
            return POS_INF;
        }
        elsif ($top == 0xfff00000) {
            return NEG_INF;
        }
    }
    elsif ($top == 0x7ff00000) {
        return NaN;
    }
    my $sign = $top >> 31;
#    print "$sign\n";
    my $exponent = (($top >> 20) & 0x7FF) - 1023;
#    print "$exponent\n";
    my $e = ($top >> 20) & 0x7FF;
    my $t = $top & 0xFFFFF;
#    printf ("--> !%011b%020b \n--> %032b\n", $e, $t, $top);
    my $mantissa = ($bottom + ($t*(2**32))) / 2**52 + 1;
#    print "$mantissa\n";
    my $double = (-1)**$sign * 2**$exponent * $mantissa;
    return $double;
}

=head2 get_array_name

    my $name = $obj->get_array_name ();

Get the name of an array from the next point in the file. If the array
does not have a name, the return value is the undefined value.

=cut

sub get_array_name
{
    my ($obj) = @_;
    if ($obj->{verbose}) {
        print "Trying to read the array's name.\n";
    }
    my ($type, $n_bytes, $data) = $obj->read_data_header ();
    if ($type != miINT8) {
        $obj->error ("bad type $type for array name");
    }
    # Arrays within a struct have name fields with zero bytes.
    if ($n_bytes == 0) {
        return undef;
    }
    if (! $data) {
        $data = $obj->read_bytes ($n_bytes);
    }
    # Remove trailing bytes from the string.
    $data = substr $data, 0, $n_bytes;
    if ($obj->{verbose}) {
        print "The array's name is \"$data\".\n";
    }
    return $data;
}

=head2 get_array_dimensions

    my @dim = $obj->get_array_dimensions ();

Get the dimensions of an array from the file, as an array. Matlab
arrays always have at least two dimensions, so @dim is at least size
2.

=cut

sub get_array_dimensions
{



( run in 1.817 second using v1.01-cache-2.11-cpan-140bd7fdf52 )