http://qs321.pair.com?node_id=143492

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

Today I ran into a puzzler regarding how perl interprets a scalar.
The problem cropped up in a program that basically gets a large string from a database and then using substr extracts substrings.
Some of these substrings are ASCII representations of floats, ie 0.123 or 21.654.

The odd thing is that when these values are used for calculations they will behave as if they were integers. For example multiplying a scalar, say $v2, containing 21.654 with 2 yields the result 42!!

Trying to duplicate the problem with a small testscript failed, that is it works as expected.
When checking debug printouts from the original program with a hex editor no strange/unexpected characters are found.

Any ideas someone ??

---
It's unfair to be an expert.

Replies are listed 'Best First'.
Re: 0.123, float or integer
by derby (Abbot) on Feb 05, 2002 at 23:22 UTC
    guha,

    That is weird. Well either something is forcing the initial scalar to integer or afterwards forcing the product to integer. I would say Devel::Peek is your friend. Place some Dump calls before and after your multiplication and check for NV, IV, and PV values.

    #!/usr/local/bin/perl -wd use Devel::Peek; $v = "21.654"; $w = 2; $x = ""; $x = $w * $v; Dump( $x ); $x = int($x); Dump( $x );

    -derby

      After a good nights sleep I looked more thoroughly using Devel::Peek as you pointed me to.
      And now I think we're closing in.

      In the test script:

      Dump($v2); ## prints SV = PV(0x176ec38) at 0x1765274 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x17601c0 "3.25"\0 CUR = 4 LEN = 8 my $v3 = 2.5 * $v2; Dump($v3); ## prints SV = NV(0x1761830) at 0x177ee88 REFCNT = 1 FLAGS = (PADBUSY,PADMY,NOK,pNOK) NV = 8.125
      BUT with the original program
      Dump($v2); ## prints SV = PV(0x1b69008) at 0x1b87164 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x1b6ab58 "3.25"\0 CUR = 4 LEN = 5 my $v3 = 2.5 * $v2; Dump($v3); ## prints SV = NV(0x178ecbc) at 0x1b87218 REFCNT = 1 FLAGS = (PADBUSY,PADMY,NOK,pNOK) NV = 7,5
      From this I gather that the problem has something to do with the decimal delimiter, maybe the locale or somesuch has been changed under my feet. The difference between the original script and the test is that the original uses DBI

      I will now upgrade my Activestate 623 distribution to 631 to see if this resolves the problem

      More ideas ?

      ---
      It's unfair to be an expert.


        Well done. That's interesting. I've been bitten by that before but not in Perl.
        perl -le 'print 2 * "21.654"' # 43.308 perl -le 'print 2 * "21,654"' # 42

        --
        John.

      A quick test with Devel::Peek revealed the following info:
      Testscript: SV = PV(0x176ec4c) at 0x1765288 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) PV = 0x17601c0 "0.123"\0 CUR = 5 LEN = 8
      Original program: SV = PVIV(0x1adb6f4) at 0x1b874d8 REFCNT = 1 FLAGS = (PADBUSY,PADMY,POK,pPOK) IV = 0 PV = 0x1ade30c "83.4"\0 CUR = 4 LEN = 8

      Perhaps because it's late at night but, I can't figure out anything else than that the number is interpreted as a string.
      But that is odd too, I thought a string would evaluate to zero or the number not int($number) ???

      ---
      It's unfair to be an expert.

Re: 0.123, float or integer
by VSarkiss (Monsignor) on Feb 05, 2002 at 23:48 UTC

    Well, if your small test script worked, the problem is not with Perl in general, no? ;-)

    First, how are you reaching the conclusion that the value is an integer? If the script is printing it out, are you sure it's not doing printf "%d" or some such. As another post in this thread pointed out, Devel::Peek can be very helpful to see what the variable contains. If it's a standalone script, you could use the debugger as well.

    If the value is indeed an integer, check that the script hasn't done a use integer. It may be at the top of the script, but just has to be in the scope of the troublesome arithmetic.

    HTH

Re: 0.123, float or integer
by chipmunk (Parson) on Feb 06, 2002 at 05:56 UTC
    It sounds to me like you have a bug in your code. Since you haven't shown us your code, I can't be more specific than that. As a guess, perhaps when you use substr you're truncating the number. Perl certainly has no trouble doing calculations on floating point numbers.
Re: 0.123, float or integer
by guha (Priest) on Feb 06, 2002 at 21:42 UTC
    Solution:

    As indicated previously in this thread the culprit was DBI.
    After the DBI->connect statement the decimalpoint was changed to decimalcomma, though that's not entirely true as decimal comma was not allowed in the perlcode.

    I have solved this by resetting the LC_NUMERIC parameter directly after the connect command

    use POSIX qw(locale_h); . . my $dbh = DBI->connect("DBI:ODBC:$dsn") or die "Could not connect to $ +dsn\n"; setlocale(LC_NUMERIC, "C"); . .
    Just hoping that I won't be bitten in the back by some other aspect of locales ;-/
    Anyway thanks all for your support and Hey I got to know Devel::Peek and locales along the journey!
    ---
    I would like to change the world but God won't let me have the source code.