in reply to Trying to translate overflowing JS code to Perl

It seems that the Javascript is doing 32-bit signed math. So the easiest way is to do your calculations and then pack it into 32bit as 4 bytes, and then to reinterpret these four bytes as signed integer:

perl -E 'say unpack "l", pack "L", (1169367104<<5)' -1234958336

Replies are listed 'Best First'.
Re^2: Trying to translate overflowing JS code to Perl
by bliako (Abbot) on Nov 28, 2023 at 19:57 UTC

    Pack Man Wow! thanks Corion that does it sub _leftshift32 { my ($n, $s) = @_; unpack "l", pack "L", ($n << $s) }

    I probably now have to implement all other arithemtic operators used in that JS code as above.

      I probably now have to implement all other arithmetic operators used in that JS code as above.

      I can't come up with a better solution ... but if you were to use a perl whose ivsize was 4, then I think (not rigorously tested) you could take care of it with a simple use integer; at the top of the script.
      On perl-5.38.0, built with just that configuration:
      D:\>perl -V:ivsize ivsize='4'; D:\>perl -le "print 1169367104<<5;" 3060008960 D:\>perl -Minteger -le "print 1169367104<<5;" -1234958336
      Cheers,
      Rob

      I believe you can do the complete calculation without conversion and just at the end downgrade to 32 bit and convert to signed. The following should work:

      sub calc_32bit_signed( $value ) { return unpack( "l", pack "L", ($value & 0xffffffff))) } ... say calc_32bit_signed( $n << 6 ); say calc_32bit_signed( $n + 2 );
        return unpack( "l", pack "L", ($value & 0xffffffff)))

        For which finite numeric values do any of the following 3 renditions differ:
        say unpack( "l", pack "L", ($value & 0xffffffff)); say unpack( "l", pack "L", ($value)); say unpack( "l", pack "l", ($value));
        Sorry ... I'm not trying to be critical ... not even nitpicking ... but I haven't found any such values, and I'm genuinely curious as to whether they exist.)

        Cheers,
        Rob

        I don't think that will work, for example consider something like ($value << 6) + length($value). So if the first part overflows in JS then it is necessary to overflow (the first part) in Perl too. Simulating the overflow for the sum would not do. At the moment I am running JS code via shelling out to node.js and that works just fine.

        I was hoping that there would be a module like Math::BigInt where you specify the number of bits or something like use smallint; But now, come to think of it, perhaps a new module could consist of only overloading arithmetic operators. Let me see if I can whip up something based on your pack receipe.

        Edit: see Re: Trying to translate overflowing JS code to Perl with working code for this.

      package Math32 { use Inline 'C', <<~'END'; #include <stdint.h> long calc(long input) { return (int32_t)((int32_t)input << 5); } END } use v5.36; say Math32::calc(1169367104);
      -1234958336

      Then all you need to do is write all the JS code in C, using int32_t variables and typecasts. If you want to declare the function parameter and return type as int32_t, you'd need to add it to the typemap, which is a hassle.