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

Hi,
This is a re-hash of a question I asked on the XS list a few hours ago. (No replies yet.) It's an issue only with perls built with -Duse64bitint.

Consider the following code and output:
use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; int foo(SV * integer) { char * str; str = SvPV_nolen(integer); if(SvIOK(integer)) { printf("IV: %s\n", str); return 1; } if(SvNOK(integer)) { printf("NV: %s\n", str); return 2; } printf("Neither IV nor NV"); return 3; } EOC { use integer; $x = 2 ** 57 + 12345; } $y = 2 ** 57 + 12345; foo($x); foo($y); __END__ Outputs: IV: 144115188075868217 NV: 1.44115188075868e+17
Note that 'foo($y)' creates the string "1.44115188075868e+17". I need to make it create the same string as 'foo($x)' does - ie "144115188075868217". How do I do that from within the foo() function ? (I'm not interested in solutions that involve fiddling with the perl side of things.)

Cheers,
Rob

Replies are listed 'Best First'.
Re: XS and -Duse64bitint
by almut (Canon) on Feb 13, 2007 at 11:55 UTC

    You could add an explicit conversion to IV, e.g.

    ... char * str; sv_setiv(integer, SvIV(integer)); // <--- here str = SvPV_nolen(integer); ...

    However, when doing that, I get (note the difference in the last two digits):

    IV: 144115188075868217 IV: 144115188075868224

    I suppose this is due to the insufficient precision in the NV representation...   Actually, I think it's too late to deal with this within your XS routine, as the value will already have been converted to NV when the SV gets passed to foo() - unless you use integer on the Perl side (but you already figured that out :)

      I suppose this is due to the insufficient precision in the NV representation

      Yes, you're right - the precision has been lost. I was fooled by the fact that the following tests re $x (the IV) and $y (the NV) return "true":
      $x == $y $x - 1 == $y - 1 $x + 1 == $y + 1
      I took that to indicate that perl knows that $y contains the value 144115188075868217, and that my problem was merely one of how to get at that value. The following tests also return "true":
      $x == $y + 1 $x == $y - 1
      which doesn't fit too well with the hypothesis that "no precision was lost" :-)

      Thanks almut, for setting me straight.

      Cheers,
      Rob
Re: XS and -Duse64bitint
by Anonymous Monk on Feb 13, 2007 at 09:40 UTC
    use integer