http://qs1969.pair.com?node_id=1197808


in reply to Math::Base - arithmetics with baseX integers (updated)

This is a neat idea, but encode spins forever when $num is negative and returns an empty string when it's zero. You could do this:
my $val = abs($num); do { push @ret, $chars[$val % $base]; $val = int($val / $base); } while $val; push @ret, '-' if $num < 0;
But '-' is in the @chars array.

Replies are listed 'Best First'.
Re^2: Math::Base - arithmetics with baseX integers (OP updated)
by shmem (Chancellor) on Aug 23, 2017 at 12:16 UTC

    What I did is to mimic the behavior of sprintf and hex in encode(), i.e. roll over:

    $num = (~abs($num))+1 if $num < 0;

    And the return line now reads:

    return join( '', reverse @ret) || 0;

    I've updated the op with the new version. Thanks for your hints!

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      $num = int $num;
      $num = (~abs($num))+1 if $num < 0;

      You can get the same effect with $num |= 0; ...but... why? Why would you want two's complement behavior in other bases?

      Truncating at $n bits is mathematically equivalent to:

      $num %= 2 ** $n;

      That's only meaningful for base-2. You can truncate at $n base-$b digits using this:

      $num %= $b ** $n;

      So -1 becomes 999999 in base-10 or 666666 in base-7. If you want, you can pick a big number of digits that still fits in a double-precision float like this:

      $num %= $base ** int(36.73/log($base));
        That's only meaningful for base-2.

        Well, that's how computers work, don't they... since the whole business of this convoluted module is only yielding the string representation of a value $n to base $b via a charset @c, while all calculations are carried out on the number/integer slots of its objects - it doesn't really calculate in base $b (no such machine except $base == 2) - the only thing is to find a good stringified representation of the underlying numbers, whilst not limiting the native number range.

        So I guess the best way to go here is outlawing '-' from the valid chars array and using that as a prefix for negative numbers. That would reduce the maxbase to 90, which I deem not to be a big loss. Would that be a good way to go?

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        ...but... why? Why would you want two's complement behavior in other bases?

        I think that you are both over- and under-thinking this. (We've clashed before on the benefits or otherwise of 'machine representation', so you may chose to simply ignore this.)

        On computers (popular, common, generic), numbers are stored and manipulated internally as binary. Whether we choose to view those numbers as signed or unsigned, integers or floats, decimal or hexadecimal or octal or (indeed) binary; internally they are held and maintained in binary form.

        Even your favored (Python) infinite precision numbers are stored and manipulated using a binary representation. And that means that it had to deal with exactly the same problems as shmem's code, and solved them in essentially the same way as you are now critiquing.

        For the full skinny, read PEP-0237.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". The enemy of (IT) success is complexity.
        In the absence of evidence, opinion is indistinguishable from prejudice. Suck that fhit
Re^2: Math::Base - arithmetics with baseX integers
by shmem (Chancellor) on Aug 22, 2017 at 16:02 UTC

    This is one of the reasons why I wrote Far from complete (besides missing pod, tests, you name it.)

    The perl builtins suffer from negative integer flaws also. The format %x of sprintf expects a signed an unsigned integer, but nonetheless

    say $f = sprintf "%x", -15; say hex $f; __END__ fffffffffffffff1 18446744073709551601

    on a 64bit system. The object could get a sign flag set by the constructor which is honored by arithmetic operations, but the string representation would be ambiguous anyways if the string has a leading dash.

    I'm not sure what to do about that. Perhaps limiting to unsigned integers is the way to go, and encode should croak if the number is negative; don't know yet.

    update: unsigned, yes, that's the point; common typo. It is coerced into an unsigned. Thanks Anonymous Monk fo pointing out the glitch.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      %x is clearly documented as taking an unsigned int in the page you link to.