in reply to Re: Splitting String???
in thread Splitting String???

Okay, I want to truncate the decimal places to 6 decimal places, this is how I'm doing it but my $lat and $lon variables are coming out blank. I'm splitting the string, truncating the decimal places and then recombining them. But the variables aren't printing any values.

What's wrong? Is there a simpler way to do this? Perhaps in a single function?
#!/usr/bin/perl my $declon = -88.9999999999999999999; my $declat = 44.1111111111111111111; my @lon = split(/\./,"$declon"); my @lat = split(/\./,"$declat"); $lon[1]=substr($lon[1],0,6); $lat[1]=substr($lat[1],0,6); my $lat = join(@lat); my $lon = join(@lon); print "$lat\n"; print "$lon";

Replies are listed 'Best First'.
Re^3: Splitting String???
by ikegami (Patriarch) on Apr 26, 2005 at 06:23 UTC

    You forgot join's first argument.

    #!/usr/bin/perl my $declon = -88.9999999999999999999; my $declat = 44.1111111111111111111; print($declon, "\n"); # -89 print($declat, "\n"); # 44.1111111111111 my @lon = split(/\./, $declon); my @lat = split(/\./, $declat); $lon[1] = substr($lon[1], 0, 6); $lat[1] = substr($lat[1], 0, 6); my $lat = join('.', @lat); my $lon = join('.', @lon); print "$lat\n"; print "$lon";

    Again, I removed the useless quotes around $declon and $declat.

    As you can see by the two prints I added near the top, -88.9999999999999999999 gets stringified as -89. You're going beyond the precision of a double. This also demonstrates where your algorithm fails. (-89 prints as "-89." instead of "-89.000000".) What you want is

    # Round (.5 rounds up) $num = int($num * 1000000 + 0.5) / 1000000;

    or maybe

    # Truncate towards 0. $num = int($num * 1000000) / 1000000;

    You can also do it using string manipluation for a little bit more precision:

    $lon = sprintf('%.6f', $declon); $lat = sprintf('%.6f', $declat);

    Example 1:

    #!/usr/bin/perl use strict; use warnings; my $declon = -88.9999999999999999999; my $declat = 44.1111111111111111111; my $lon = int($declon * 1000000 + 0.5) / 1000000; my $lat = int($declat * 1000000 + 0.5) / 1000000; printf("%.6f\n", $lon); # -88.999999 printf("%.6f\n", $lat); # 44.111111

    Example 2:

    #!/usr/bin/perl use strict; use warnings; my $declon = -88.9999999999999999999; my $declat = 44.1111111111111111111; printf("$declon\n"); # -89 printf("$declat\n"); # 44.1111111111111 printf("%.6f\n", $declon); # -89.000000 printf("%.6f\n", $declat); # 44.111111
Re^3: Splitting String???
by eibwen (Friar) on Apr 26, 2005 at 06:23 UTC

    Truncating is fairly simple:

    my $number = 123.1234567; $number =~ s/(?<=\.)(\d{1,6}).*$/$1/; print $number; # 123.123456

    =~ s/indicates that we're going to apply a regex to $number
    (?<=\.)signifies that the match is to be made after a literal decimal.
    (\d{1,6})captures the first six \d characters in the class [0-9], and stores the value in $1.
    .*$matches the remainder of the variable contents.
    /seperates the match from the replacement.
    $1is the first six decimal places as captured earlier.

    /;signifies the end of the regex and line respectively.

    If you want to round, that can be done as well (see UPDATE):

    $number =~ s/(?<=\.)(\d{1,6})(\d).*$/$2>4?$1+1:$1/e;

    $2>4?$1+1:$1is a ternary conditional, which tests whether the seventh digit should be rounded ($2 > 4), and then returns either $1 + 1 or $1 as appropriate.
    /einstructs perl to evaluate the replacement as opposed to returning a literal value

    UPDATE: The truncation code works; however the rounding code does not. Given that 9 would round to 10, which has the potential to be iterative, eg 9.9999999, it would affect both itself and the preceeding character, which obviously has the ability to affect characters on both sides of the decimal point. Preliminary testing has shown that the correct line is more complex than a simple example. Nevertheless, it remains a decent demonstration of /e.

    As it turns out the rounding code is considerably easier than I had originally thought:

    my $number = 123.1234567; $number += .0000005; # Add 5 to the seventh digit $number =~ s/(?<=\.)(\d{1,6}).*$/$1/; # truncate to six digits print $number; # 123.123456

    It's essentially the same thing as the truncation code above, save the addition of the += line. Adding 5 to the decimal is a fairly common way to round an int -- I guess I just didn't realize it applied to rounding the 7th decimal place as well.

Re^3: Splitting String???
by holli (Abbot) on Apr 26, 2005 at 07:47 UTC
    Okay, I want to truncate the decimal places to 6 decimal places ... Is there a simpler way to do this?
    You mean like this?
    my $declon = -88.9999999999999999999; my $declat = 44.1111111111111111111; print substr(sprintf ("%.7f", $declon),0,-1), "\n", substr(sprintf ("%.7f", $declat),0,-1);
    Note: The substr is there to avoid the rounding of sprintf. You could write sprintf ("%.6f", $declon) but then the value will get rounded.


    holli, /regexed monk/