madM has asked for the wisdom of the Perl Monks concerning the following question:

Hi.. I´m trying to calculate de logarithm of each value in this matrix but i get this error.. "Can't take log of 0 at aprende3.pl line 44." any suggestions? thanks!
my @matrix =( [0.54, 0.03, 0.03, 0.03, 0.08, 0.04, 0.05, 0.05, 0.02, 0.02, 0.03, 0.0 +4, 0.03, 0.01, 0.06, 0.11, 0.06, 0.01, 0.01,0.06], [0.02, 0.57, 0.03, 0.01, 0.02, 0.06, 0.03, 0.01, 0.04, 0.01, 0.01, 0.1 +1, 0.02, 0.01, 0.01, 0.02, 0.02, 0.01, 0.01, 0.01], [0.01, 0.02, 0.48, 0.06, 0.01, 0.03, 0.03, 0.03, 0.05, 0.01, 0.01, 0.0 +3, 0.01, 0.00, 0.01, 0.04, 0.03, 0.00, 0.02, 0.01], [0.02, 0.01, 0.09, 0.57, 0.01, 0.04, 0.11, 0.02, 0.03, 0.00, 0.00, 0.0 +3, 0.01, 0.00, 0.02, 0.04, 0.02, 0.00, 0.01, 0.00], [0.01, 0.00, 0.00, 0.00, 0.57, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0 +0, 0.00, 0.01, 0.00, 0.01, 0.01, 0.01, 0.01, 0.01], [0.02, 0.04, 0.03, 0.02, 0.01, 0.42, 0.05, 0.01, 0.04, 0.01, 0.01, 0.0 +5, 0.02, 0.00, 0.01, 0.02, 0.02, 0.01, 0.01, 0.01], [0.04, 0.04, 0.05, 0.13, 0.01, 0.11, 0.52, 0.02, 0.03, 0.01, 0.01, 0.0 +7, 0.01, 0.00, 0.02, 0.04, 0.04, 0.01, 0.01, 0.01], [0.05, 0.02, 0.05, 0.03, 0.02, 0.02, 0.02, 0.77, 0.02, 0.00, 0.00, 0.0 +2, 0.01, 0.00, 0.01, 0.04, 0.01, 0.01, 0.00, 0.01], [0.01, 0.01, 0.02, 0.01, 0.01, 0.02, 0.01, 0.00, 0.54, 0.00, 0.00, 0.0 +1, 0.01, 0.02, 0.01, 0.01, 0.01, 0.02, 0.04, 0.00], [0.02, 0.01, 0.01, 0.00, 0.03, 0.01, 0.01, 0.00, 0.01, 0.50, 0.10, 0.0 +1, 0.09, 0.04, 0.01, 0.01, 0.03, 0.02, 0.01, 0.18], [0.03, 0.02, 0.01, 0.01, 0.03, 0.03, 0.01, 0.00, 0.02, 0.13, 0.60, 0.0 +2, 0.19, 0.09, 0.02, 0.02, 0.02, 0.02, 0.03, 0.08], [0.03, 0.14, 0.06, 0.03, 0.01, 0.09, 0.06, 0.02, 0.05, 0.01, 0.01, 0.5 +0, 0.02, 0.01, 0.02, 0.04, 0.03, 0.01, 0.01, 0.01], [0.01, 0.01, 0.00, 0.00, 0.01, 0.02, 0.00, 0.00, 0.01, 0.03, 0.05, 0.0 +1, 0.42, 0.02, 0.00, 0.01, 0.01, 0.01, 0.01, 0.02], [0.01, 0.01, 0.00, 0.00, 0.02, 0.01, 0.00, 0.00, 0.03, 0.02, 0.04, 0.0 +0, 0.04, 0.61, 0.00, 0.01, 0.01, 0.07, 0.14, 0.01], [0.03, 0.01, 0.01, 0.01, 0.00, 0.01, 0.01, 0.01, 0.02, 0.00, 0.01, 0.0 +1, 0.01, 0.00, 0.72, 0.03, 0.01, 0.00, 0.00, 0.01], [0.07, 0.03, 0.06, 0.04, 0.05, 0.04, 0.03, 0.03, 0.02, 0.01, 0.01, 0.0 +4, 0.02, 0.01, 0.04, 0.43, 0.09, 0.02, 0.01, 0.01], [0.04, 0.02, 0.04, 0.02, 0.04, 0.03, 0.03, 0.01, 0.02, 0.02, 0.02, 0.0 +3, 0.03, 0.01, 0.02, 0.09, 0.52, 0.01, 0.01, 0.04], [0.00, 0.00, 0.00, 0.00, 0.01, 0.00, 0.00, 0.00, 0.01, 0.00, 0.00, 0.0 +0, 0.00, 0.02, 0.00, 0.00, 0.00, 0.71, 0.02, 0.00], [0.00, 0.01, 0.01, 0.00, 0.01, 0.01, 0.00, 0.00, 0.05, 0.01, 0.01, 0.0 +1, 0.01, 0.10, 0.00, 0.01, 0.01, 0.06, 0.61, 0.01], [0.05, 0.01, 0.01, 0.01, 0.07, 0.02, 0.02, 0.01, 0.01, 0.20, 0.07, 0.0 +1, 0.06, 0.03, 0.01, 0.02, 0.06, 0.02, 0.02, 0.51]); my @frequency = ([0.08477395, 0.05103334, 0.03837665, 0.05740129, 0.01 +256165, 0.03471746, 0.06883297, 0.07907659, 0.02077239, 0.06813598, 0.08906677, 0.06501537 +, 0.02318017, 0.03823936, 0.04036729, 0.05668318, 0.05721648, 0.00871765 +, 0.02785317, 0.07797831]); my $mutrate=0; my $matrix2={}; for (my $i=0; $i<20; $i++){ $mutrate += $frequency[0][$i]*(1-$matrix[$i][$i]); } my @PAM1= @matrix; my @lnpam=(); for (my $i=0; $i<20; $i++){ for (my $j=0; $j<20; $j++){ $lnpam[$i][$j] = log $matrix[$i][$j]; } }

Replies are listed 'Best First'.
Re: Calculate log of matrix values
by choroba (Cardinal) on Aug 09, 2013 at 13:44 UTC
    The log function is not defined for 0. You can check for zeros in the loop:
    $lnpam[$i][$j] = log $matrix[$i][$j] if $matrix[$i][$j];

    The resulting matrix would have undefined values in the corresponding places.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      i solved the problem using this:
      LINE: for (my $i=0; $i<20; $i++){ for (my $j=0; $j<20; $j++){ if ($matrix[$i][$j] =~ /[^0.00]/){ $lnpam[$i][$j] = log $matrix[$i][$j]; }else{ next LINE; } } }
      thanks a lot for the quick answer!
        if ($matrix[$i][$j] =~ /[^0.00]/){

        This does not do what you think it does, but it is at least close. You are really only doing if ($matrix[$i][$j] =~ /[^0.]/){ IE: does the string have at least one character that is not a literal '0' or a '.'

        See: Bracketed Character Classes

        Why not make the test if ($matrix[$i][$j] > 0)? That's much simpler and faster, and will not fail on "-0.00 " or " 0.00" or regular negative numbers.

Re: Calculate log of matrix values
by BrowserUk (Patriarch) on Aug 09, 2013 at 14:08 UTC

    Rather than having to testing for 0 (or undef) in all your further calculations, it may be easier (and mathematically acceptable) to replace your zeros with a very small number, say 1e-308:

    map $_//= 1e-308, @$_ for @matrix;

    which should have negligible affect upon any calculations, but avoid lot of special casing.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      The POSIX HUGE_VAL would be closer to the mathamatical concept. It would never be mistaken for "unassigned". Attempts to use it in an expression would always throw an exception. A huge negative would be even better, but we do not seem to have that option.
      Bill
        Attempts to use it in an expression would always throw an exception.

        I think you've misunderstood my post. If I wanted to causes exceptions, I'd leave the zeros in place. or replace them with #NaN.

        My point was that by replacing the zeros with a very, very small number, you can avoid exceptions, or the need for conditional tests to avoid exceptions, as it will allow most calculations to operate correctly whilst introducing negligible changes to the final results.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        HUGE_VAL does not help here, we need kind of a TINY_VAL. 1 / HUGE_VAL does not work:
        $ perl -MPOSIX=HUGE_VAL -e 'print log(1 / HUGE_VAL)' Can't take log of 0 at -e line 1.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Calculate log of matrix values
by toolic (Bishop) on Aug 09, 2013 at 13:43 UTC
Re: Calculate log of matrix values
by QM (Parson) on Aug 09, 2013 at 13:45 UTC
    Don't take the log of 0?

    You have several 0.00 entries in your example. What do you want to output for log(0)?

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      Thanks you all for the reply! it really helped!
Re: Calculate log of matrix values
by RichardK (Parson) on Aug 09, 2013 at 13:51 UTC

    My suggestion: don't try to take the log of zero as it's not defined :) see logarithm

    Really, it'll depends on what you're going to do with the logs. You could set the result to undef and detect that in your later code.

Re: Calculate log of matrix values
by Perlbotics (Archbishop) on Aug 09, 2013 at 13:58 UTC

    Computationally hazardous(!), but you could try one of these modifications with e.g. 1e-300 as an approximation for zero and see how far you get... Take care of error propagation.

    $lnpam[$i][$j] = log( $matrix[$i][$j] || 1e-300);

    $lnpam[$i][$j] = $matrix[$i][$j] ? log( $matrix[$i][$j]) : -1000;