loading...
Cover image for Weekly Challenge #084 Task #1 :: (Raku)

Weekly Challenge #084 Task #1 :: (Raku)

jeongoon profile image Myoungjin Jeon ・4 min read

TASK #1 › Reverse Integer

Submitted by: Mohammad S Anwar

You are given an integer $N.

Write a script to reverse the given integer and print the result. Print 0 if the result doesn’t fit in 32-bit signed integer.

The number 2,147,483,647 is the maximum positive value for a 32-bit signed binary integer in computing.

Example 1:

Input: 1234
Output: 4321

Example 2:

Input: -1234
Output: -4321

Example 3:

Input: 1231230512
Output: 0
Enter fullscreen mode Exit fullscreen mode

32 bit in 2020??

Looks easy for me because .flip method... but actually needed more time to get used to 32-bit singed integer

To express a signed integer in 8 bit, one precious bit needs to be sacrificed to express both positive and negative value. and somehow positive-side seems to decide to give their be-loved single bit to negative-team. (of course there is a reason)
I'm not a computer scientist.. I don't understand them all, but more interestingly 2³¹ - 1
(2147483647) is also a prime number. Let's listen what Raku is about to say 🎤

> is-prime(2³¹ - 1).raku.say
Bool::True
Enter fullscreen mode Exit fullscreen mode

Okay Raku told us in formal way but we can simply understand it as "True".

Flip

> 123.flip
321
Enter fullscreen mode Exit fullscreen mode

looks like a solution. done. however we need to filter the result.
the number seen as above can be rewritten like below as well.

> 1 +< 32 -1 # when positive integer
2147483647
Enter fullscreen mode Exit fullscreen mode

negative don't need to subtract 1 from the number

So when we have "1231230512", flip the string and compare it with (2³¹ - 1). don't we?

> "1231230512".flip
2150321321
> 2150321321 < 2³¹ - 1
False
Enter fullscreen mode Exit fullscreen mode

oh... a something have changed my mind.

Overflow

My laptop is 64bit machine I don't really need to worry about 32 bit but.. maybe this is one more hidden task. writing the solution as if we are using 32 bit machine. so we cannot make a number above (2³¹ - 1) because after that we will get negative value. What a temper it is.
So thinking about the limit we can maybe compare the number as a string

String Comparison is Not The Same Thing

One more problem we have is that string comparison is not acting as like a integer one.
for example

> 123 <=> 456
Less
> "123" cmp "456"
Less
> 45 <=> 123
Less
> "45" cmp "123"
More # ????
Enter fullscreen mode Exit fullscreen mode

So I decided to compare the length of both numbers before string comparison. and I had got another problem.

300

> 300.flip # or "300".flip or 300.Str.flip
003
Enter fullscreen mode Exit fullscreen mode

003 means 3 and the length of the "300" is 3 but length of "3" is now "1" again. So starting all the Persian must be destroyed. (What a racist !!!👿) and I used the regular expression here.

> S/^0+// with (300.Str.flip)
3
Enter fullscreen mode Exit fullscreen mode

📚 S//

Subroutines I Made

To check limitation, I made a subroutine to get the number(absoulte)

sub abslim (Str $n, $bit = 32) {
    (1 +< $bit.pred) - ($n.substr(^1) ne "-")
}
Enter fullscreen mode Exit fullscreen mode

To reverse(or flip) the string ..

sub rev-int ( Int $n --> Str ) {
    ("","-")[+($n < 0)] ~ $n.abs.flip
}
Enter fullscreen mode Exit fullscreen mode

I applied abs before flip to handle negative value as well. and get a side effect of removing any "+" sign mark before proceeding.
and prepend the "-" sign if needed.

To filter the number I used a little twisted syntax by using List or Hash because sometimes I missed the functional programming style declaration of a variable(actually a function).

sub filter32bit( Str $nstr ) {
    # assume this is 32bit machine
    # so this will get a reversed string (with sign prepended)
    # and compare it with limit value as strings

    my $lstr = abslim($nstr).Str;
    my $nstr-abs = S/^0+//   # remove zeroes in the beginging. for better cmp.
                   with $nstr.subst("-","");       # disgard the sign as well.

        say "[FLTR] ",($nstr-abs gt $nstr ?? "-" !! ""),$lstr if $d;

        # better read bottom up
        ($nstr.Int but "0",
         $nstr.Int)[
            ( Less => True,
              Same => $nstr lt $lstr,
              More => False,
            ).Hash.{$nstr-abs.chars <=> $lstr.chars} ]
}
Enter fullscreen mode Exit fullscreen mode

Final Code

I applied 📚∘ infix for my curiosity. so looks more unusual but it was fun!!!

our $d is export = False; # `export' is needed to use globaly

sub rev-int ( Int $n --> Str ) {
    ("","-")[+($n < 0)] ~ $n.abs.flip
}

# return absoulte value of limitation in 32 bit (without sign)
# with check sign of $n
sub abslim (Str $n, $bit = 32) {
    (1 +< $bit.pred)-($n.substr(^1) ne "-")
}
sub filter32bit( Str $nstr ) {
    # assume this is 32bit machine
    # so this will get a reversed string (with sign prepended)
    # and compare it with limit value as strings

    my $lstr = abslim($nstr).Str;
    my $nstr-abs = S/^0+//   # remove zeroes in the beginging. for better cmp.
                   with $nstr.subst("-","");       # disgard the sign as well.

        say "[FLTR] ",($nstr-abs gt $nstr ?? "-" !! ""),$lstr if $d;

        # better read bottom up
        ($nstr.Int but "0",
         $nstr.Int)[
            ( Less => True,
              Same => $nstr lt $lstr,
              More => False,
            ).Hash.{$nstr-abs.chars <=> $lstr.chars} ]
}

sub dmsg-tap (Any $a) { say("[DBG",$++,"] $a"); $a;};

multi MAIN (Int:D \N, Bool:D :$v = False) {
    # side effect?: when use multi with MAIN (even though has a MAIN declared),
    #               raku gives a simple help message with invalid args.

    my @solution-chain = &filter32bit, &rev-int;
    my @speaker = ($v
                  ?? |(&dmsg-tap) xx @solution-chain.elems # say each step
                  !! &say);                                 # or just result
    my @app-chain = (roundrobin @speaker, @solution-chain).flat;

    if $v {
        $d = True;
        "the chain of subroutines looks like ...".say;
        for (reverse @app-chain).kv -> $i, $r {
            say "$i: {$r.raku}";
        }
        "and answer is ...\n".say;
    }

    ([] @app-chain)(N);
    # or we can save it as a variable and execute.
    # but it was skipped as single usage.
    # i.e.
    # my $app = [∘] @app-chain;
    # $app(N);
}
Enter fullscreen mode Exit fullscreen mode

Thank you for reading~!!

please visit 🐪🦋PWC for more challenge and further update !!!

Discussion

pic
Editor guide