Weekly Challenge #084 Task #1 :: (Raku) 
Tags: challenge, perlweeklychallenge, raku, perl
Published: 2020-10-26 07:10:54

## [**TASK #1 › Reverse Integer**](https://perlweeklychallenge.org/blog/perl-weekly-challenge-084/#TASK1)

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
```

### **32 bit in 2020??**
Looks easy for me because [*.flip*](https://docs.raku.org/routine/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)*](https://en.wikipedia.org/wiki/Two's_complement)
I'm not a computer scientist.. I don't understand them all, but more interestingly 2³¹ - 1
(2147483647) is also [a prime number](https://en.wikipedia.org/wiki/2,147,483,647
). Let's listen what Raku is about to say 🎤
```perl
> is-prime(2³¹ - 1).raku.say
Bool::True
```
Okay Raku told us in formal way but we can simply understand it as "True".

### **Flip**
```perl
> 123.flip
321
```
looks like a solution. done. however we need to filter the result.
the number seen as above can be rewritten like below as well.
```perl
> 1 +< 32 -1 # when positive integer
2147483647
```
*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?

```perl
> "1231230512".flip
2150321321
> 2150321321 < 2³¹ - 1
False
```
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*
```perl
> 123 <=> 456
Less
> "123" cmp "456"
Less
> 45 <=> 123
Less
> "45" cmp "123"
More # ????
```
So I decided to compare the length of both numbers before string comparison. and I had got another problem.

### **300**
```perl
> 300.flip # or "300".flip or 300.Str.flip
003
```
*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.
```perl
> S/^0+// with (300.Str.flip)
3
```
📚 [*S//*](https://docs.raku.org/language/regexes#S///_non-destructive_substitution)
### **Subroutines I Made**
To check limitation, I made a subroutine to get the number(absoulte)
```perl
sub abslim (Str $n, $bit = 32) {
    (1 +< $bit.pred) - ($n.substr(^1) ne "-")
}
```

To reverse(or flip) the string ..
```perl
sub rev-int ( Int $n --> Str ) {
    ("","-")[+($n < 0)] ~ $n.abs.flip
}
```
I applied [abs](https://docs.raku.org/routine/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).

```perl
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} ]
}
```

### **Final Code**
I applied 📚[∘ infix](https://docs.raku.org/routine/%E2%88%98) for my curiosity. so looks more unusual but it was fun!!!
```perl
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);
}
```

Thank you for reading~!!

please visit [🐪🦋PWC](https://perlweeklychallenge.org/) for more challenge and further update !!!