in reply to Strange behaviour when printing certain numeric values

I'm going to guess (and not take the time to verify, but maybe this gives you a lead to follow) that the constant got parsed as an SVt_NV at compile time, and then some optimization re-used that same SV since it was a constant, so the loop is operating on the same underlying SV 3 times.

Then at runtime when perl has to try to figure out what to do at "$_ + 1", it probably does a bunch of logic to decide whether to do floating point addition or integer addition, and that function in the PR was previously returning True to indicate that lossless conversion from NV to IV *is* possible, and somehow it used the NV for the calculation but cached the IV back into the SV struct. Going forward, the SV appears to be both an NV and IV and so later addition uses integer math since it is faster. But, that wasn't true because the NV already lost the low 7 bits or so of the IV, so the IV is incorrect/not accurate and should not have been cached into the SV. After the patch, the lossless conversion function will return false, will not cache the IV, and should keep using NV math on each repeat operation.

It seems like maybe a better fix would be to tell the parser to record the integer value at parse time since it would fit, but I really don't know enough about the parser internals to make a recommendation like that.

  • Comment on Re: Strange behaviour when printing certain numeric values

Replies are listed 'Best First'.
Re^2: Strange behaviour when printing certain numeric values
by hv (Prior) on Jan 17, 2024 at 19:55 UTC
    # with my Ubuntu system perl v5.26.1 % perl -MDevel::Peek -wle 'for(0x1p+60, 0x1p+60, 0x1p+60) { Dump($_); +print $_ + 1; Dump($_) }' SV = NV(0x558a66569f70) at 0x558a66569f88 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pNOK) NV = 1.15292150460685e+18 1.15292150460685e+18 SV = PVNV(0x558a665410f0) at 0x558a66569f88 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pIOK,pNOK) IV = 1152921504606846976 NV = 1.15292150460685e+18 PV = 0 SV = NV(0x558a66569f88) at 0x558a66569fa0 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pNOK) NV = 1.15292150460685e+18 1152921504606846977 SV = NV(0x558a66569f88) at 0x558a66569fa0 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pNOK) NV = 1.15292150460685e+18 SV = NV(0x558a6656a018) at 0x558a6656a030 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pNOK) NV = 1.15292150460685e+18 1152921504606846977 SV = NV(0x558a6656a018) at 0x558a6656a030 REFCNT = 2 FLAGS = (NOK,READONLY,PROTECT,pNOK) NV = 1.15292150460685e+18

    So a) it is a different scalar coming in each time; b) the contents of the scalar on entry to the loop are identical each time (at least as far as Devel::Peek is showing). Perversely, the first time it shows as an NV and caches an IV value, whereas subsequently it shows as an IV but does not cache an IV value.

    So it feels like some internal state of the interpreter is changing and affecting future calls, which would suggest a bug.

    My inclination would be to single step through the sprintf implementation (Perl_sv_vcatpvfn_flags in sv.c) to see where and why behaviour changes between first and second pass; if I find a confluence of time and will I'll have a go at that, since I'm pretty familiar with that code.

    Update: Oh, I tried changing the testcase to Dump($_); Dump($_+1), which takes print out of the equation: it's pp_hot.c: pp_add() that needs looking at. (Not pp.c: pp_i_add(), which should be relevant only under use integer.) And the sprintf implementation wasn't relevant anyway, since we were doing a plain print: that was just me looking for the keys under the lamppost.

    Hugo

      So it feels like some internal state of the interpreter is changing and affecting future calls, which would suggest a bug

      If there is a bug, then there's the question of whether the PR fixes the bug, or merely works around it.
      I'll ask about it on the PR thread, mentioning that I've also raised it here.

      Cheers,
      Rob
Re^2: Strange behaviour when printing certain numeric values
by choroba (Cardinal) on Jan 17, 2024 at 19:11 UTC
    > It seems like maybe a better fix would be

    This comment should go to the PR, too.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]