Home > Enterprise >  shell: arithmetic with custom number bases
shell: arithmetic with custom number bases

Time:03-31

I have to write a command line that take two numbers in two different custom base and output in a third one.

By custom base, I mean that I have things like that:

  • Input base 1: "!?\
  • Input base 2: ajedpoi
  • Output: rAfeB oiX

So starting from that I guess that bc doesn't help, right?

Is there such a command or should I write some custom script? Could you give me some clues? I'm completly lost.

EDIT: the exercice exact instructions are:

Write a command line that takes numbers from variables FT_NBR1, in ’"?! base, and FT_NBR2, in mrdoc base, and displays the sum of both in gtaio luSnemf base.

In a way that with the following values:

FT_NBR1=\'?"\"'\
FT_NBR2=rcrdmddd

I would get the following output:

Salut

CodePudding user response:

How would one convert the string 789 into a number?

Well, 789 is equal to

7 × 102 8 × 101 9 × 100

But we're writing a program and we'll want to take advantage of looping.

( ( 7 ) × 10 8 ) × 10 9

Better yet,

( ( ( 0 ) × 10 7 ) × 10 8 ) × 10 9

We don't start with digits 7, 8 and 9, but their string representation.

(
   (
      (
         0
      ) × 10   [ offset of "7" in "0123456789" ]
   ) × 10   [ offset of "8" in "0123456789" ]
) × 10   [ offset of "9" in "0123456789" ]

And finally, let's remove the last bit of reliance on base 10.

(
   (
      (
         0
      ) × [ number of symbols in "0123456789" ]   [ offset of "7" in "0123456789" ]
   ) × [ number of symbols in "0123456789" ]   [ offset of "8" in "0123456789" ]
) × [ number of symbols in "0123456789" ]   [ offset of "9" in "0123456789" ]

So the code would look like this:

  1. Set n to 0.
  2. Set base to the number of symbols in the base.
  3. For each digit,
    1. Set n to the result of the multiplication of n and base.
    2. Get the offset of the digit in the array of symbols that make up the base.
    3. Set n to the result of the addition of n and the offset.

Example Perl implementation:

my @syms = split //, "01234567890";
my %sym_offset = map { $syms[$_] => $_ } 0 .. $#syms; 

my $s = "...";

my $n = 0;
for my $sym ( split //, $s ) {
   my $offset = $sym_offset{ $sym };
   $n = $n * @syms   $offset;
}

$s = $syms[ 0 ] if !length( $s );

say $n;

The opposite of this process can be taken to take a number and convert it to base. Instead of repeatedly multiplying, one would repeatedly divide, using the remainder as an index into the list of symbols that make up the base.

  1. Set base to the number of symbols in the base.
  2. Set s to an empty string.
  3. While n is greater than zero,
    1. Find the remainder of n divided by base.
    2. Get the symbol found at the offset equal to the remainder.
    3. Prepend the symbol to s.
    4. Set n to the result of the subtraction of the remainder from n.
    5. Set n to the result of the division of n by base.
  4. If s is an empty string,
    1. Set s to the first symbol.

Example Perl implementation:

my @syms = split //, "01234567890";
my %sym_offset = map { $syms[$_] => $_ } 0 .. $#syms; 

my $n = ...;

my $s = "";
while ( $n ) {
   my $offset = $n % @syms;
   $s = $syms[ $offset ] . $s;
   $n = ( $n - $offset ) / @syms;
}

say $n;

CodePudding user response:

Well, I was'nt clever enough. I can do it with just tr and bc

I use tr to convert from and back the weird "bases" and bc with normal numbers.

Here's what I have done:

#!/bin/sh
NUM1=$(echo "$FT_NBR1" | tr \'\\\\\"\?\! '01234')
NUM2=$(echo "$FT_NBR2" | tr mrdoc '01234')
RES=$(echo "obase=13; ibase=5; $NUM1   $NUM2" | bc)

echo $RES | tr '0123456789abc' 'gtaio luSnemf'
  • Related