Do I have a rounding error? Perl

My script should do the following. It takes an old list of scalars and creates a new, matching list of numbers. The old list is called @oldMarkers and the new list is like @newMarkers.

Input Example: chr1, chr2, IMP, chr3, IMP, IMP, IMP, chr4

An example output looks like this: 1, 2, 2.1, 3, 3.1, 3.2, 3.3, 4

The point of the script is to read the @oldMarkers list and output the list, where for each instance of the element containing the letters "chr", an integer is entered into the @newMarkers array. For each IMP instance in @oldMarkers, the decimal is appended to @newMarkers. The new decimal has the same "base integer" as the previous number, but is added to it .1. In other words, it is assumed that several subsequent instances of "IMP" should have the same integer as the last record read "chr", with the decimal value referenced counts the number of IMPs that match the last "chr" record.

The script below works almost 100%. It even usually works in the following example. @OldMarkers has a lot of IMP entries in some places. If there are more than 10 IMPs in the line, then it is assumed that the code should insert values ​​in @newMarkers, so that all the "IMPs" of this block of records have the same integer, which also corresponds to the number corresponding to the last one; read the "chr" instance in @oldMarkers. To this integer is added 0.1. And when the decimal value reaches 0.9, the decimals will β€œstart” back to .1 and go from there, to the end of the IMP record segment.

For example, if @oldMarkers has a block of 13 "IMPs" and is: chr1, chr2, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, chr2

then @newMarkers should be: 1, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.1, 2.2, 2.3, 2.4, 3

Summary script:

. , . - , - "chr4" "IMP" . while , @oldMarkers.

. script , @newMarkers "chr" "IMP" @oldMarker. if else.

, , , "chr" "IMP" . if else .

@newMarker, .

, . , , IMP 10, script "" . , .1 . , 10, . "".

?

my @oldMarkers = ();
my @newMarkers = ();

while ( my $line = <$FILE> )
    {
    chomp $line;
    my @entries = split( '\t', $line );
    push( @oldMarkers, $entries[ 1 ] ); 
    } ### end of while


for ( my $i = 0 ; $i < scalar @oldMarkers   ; $i++ )
    {  
     if ( $oldMarkers[ $i ] =~ m/chr/ ) ### is a marker
        {
         if ( $oldMarkers[ $i - 1 ] =~ m/IMP/ ) ### new marker comes after imputed site
            {
             push( @newMarkers, int( $newMarkers[ $i - 1 ] ) + 1 );            
            }

       else  ### is coming after a marker                                       
           {
            push( @newMarkers, $newMarkers[ $i - 1 ] + 1 ); 
           }    

      } ### if

   else    ### is an imputed site
      {
       if ( $oldMarkers[ $i - 1 ] =~ m/IMP/ ) ### imputed site is after another imputed site
          {
           my $value = $newMarkers[ $i - 1 ] - int( $newMarkers[ $i - 1 ] );

           if ( $value < .9 )
                {
                 push( @newMarkers, $newMarkers[ $i - 1 ] + .1 );   
                }

          elsif ( $value > .9 )
                {
                 push( @newMarkers, int( $newMarkers[ $i - 1 ] ) + .1  );   
                } 


        } ### if

   else ### imputed site is after a marker
        {
         push( @newMarkers, int( $newMarkers[ $i - 1 ] ) + .1 ); 
        }    

    } ### else   

} ### for    


print $newMarkerfile join( "\t", @newMarkers);             
+2
6

, . , : . . . 10, reset 1:

my @newMarkers;
my $chrCount = 0;
my $impCount = 0;

foreach my $marker (@oldMarkers) {
    if ( $marker =~ /^chr\d+$/ ) {
        $chrCount++;
        $impCount = 0;
        push @newMarkers, $chrCount;
    } elsif ( $marker eq "IMP" ) {
        $impCount++;
        $impCount = 1 if $impCount == 10;
        push @newMarkers, "$chrCount.$impCount";
    } else {
        die "Unrecognized marker $marker";
    }
}

( codepad.org)

+6

10 & # xD7; 0,1 = 1,

>perl -E"$x=0; $x += 0.1 for 1..10; say sprintf('%0.16f', $x); say int($x);"
0.9999999999999999
0

- , .

. , 1/3 ? , 1/10 . 2/10, 3/10, 4/10, 6/10, 7/10, 8/10 9/10. .

+3

, :

$imp_order = 0;
$chr_order = 0;
for my $old (@oldMarkers) {   
  if ( $old =~ m/chr/ ) ### is a marker
  {

    $imp_order = 0;
    $chr_order++;

    push( @newMarkers,  $chr_order );    

  } ### if

  else    ### is an imputed site
  {
      $imp_order = 0 if $imp_order == 9;
      $imp_order++;
      push( @newMarkers, $chr_order + $imp_order / 10 );   

  } ### else   

} ### for    
+3

, int() . POSIX, ceil() floor(), .

: http://perldoc.perl.org/perlfaq4.html#Does-Perl-have-a-round%28%29-function%3F-What-about-ceil%28%29-and-floor%28%29%3F-Trig-functions%3F

, , , , ​​ :

elsif ( $value > .9 )
    {
        push( @newMarkers, int( $newMarkers[ $i - 1 ] ) + .1  );   
    }

:

elsif ( $value > .9 )
    {
        push( @newMarkers, ceil( $newMarkers[ $i - 1 ] ) + .1  );   
    }

, int() .

: , "chr" count/order "imp" count/order , float. , , , .

+1

, , .

use strict;
use warnings;

my @old = do {
  open my $fh, '<', 'markers.txt' or die $!;
  map /([^\t]+)$/, <$fh>;
};

my @new;
my @marker;
my $chr = 0;

for (@old) {
  if ( /chr/ ) {
    @marker = (++$chr);
  }
  elsif ( @marker > 1 and $marker[1] == 9 ) {
    $marker[1] = 1;
  }
  else {
    $marker[1]++;
  }
  push @new, [@marker];
}

@new = map join('.', @$_), @new;

print join(', ', @new), "\n";

1, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.1, 2.2, 2.3, 2.4, 3
0

: 1 2 2,1 2,2 2,3 2,4 2,5 2,6 2,7 2,8 2,9 3,1 3,1 3,3 4

> use > =

Then you have 2 options: int ($ newMarkers [$ i - 1]) + $ value +.100000 or add 1 to the int value newMarkers [$ i - 1]

-1
source

All Articles