1

I'm searching for a calculator in base 31, i.e., I want both input and output to be in base 31. (I actually don't care much about the format of digits, only that it would be easy writable. So, for example `013456789ABCDEFGHIJKLMNOPQRSTU' would be fine.)

bc seems to be good option for small bases as you can define ibase=x; obase=x. But there is an upper limit for ibase — that is 16 as it doesn't want to use bigger digits than F.

Is there some workaround for that? Or, maybe a way how to recompile bc in a way it would support bigger bases? Or, alternatively is there some alternative to bc which would do at least basic arithmetic (like +, -, /, *, ^)?

phuclv
  • 37,963
  • 15
  • 156
  • 475

4 Answers4

1

POSIX bc won't bases higher than 16, but GNU bc will. From the manual,

A simple expression is just a constant. `bc' converts constants into
internal decimal numbers using the current input base, specified by the
variable IBASE. (There is an exception in functions.)  The legal values
of IBASE are 2 through 16.  Assigning a value outside this range to
IBASE will result in a value of 2 or 16.  Input numbers may contain the
characters 0-9 and A-F. (Note: They must be capitals.  Lower case
letters are variable names.)  Single digit numbers always have the
value of the digit regardless of the value of IBASE. (i.e. A = 10.)
For multi-digit numbers, `bc' changes all input digits greater or equal
to IBASE to the value of IBASE-1.  This makes the number `FFF' always
be the largest 3 digit number of the input base.
Mike Pierce
  • 1,390
  • 1
  • 12
  • 35
1

dc is another solution. Originally bc was implemented using dc although nowadays the two are separated. The only thing is that dc is more difficult to use

$ echo 31o 16i DEADBEEFp | dc
04 06 15 09 18 22 15

The only thing with it is that large digits are displayed as values instead of letters and you'll need to map that to characters if you want

$ echo 31o 16i DEADBEEFp | dc | awk -v RS=" " -v FS="" '{ if (NR > 1) { if (int($0) < 10) { printf int($0) } else { printf "%c", ($0 - 10 + 0x61) } } } END { printf "\n" }'
46f9imf

Compare with Wolfram Alpha:

Wolfram Alpha 0xDEADBEEF in base 31

Some more examples:

$ echo "31o 31 p" | dc
01 00

$ echo "31o 31 31 * p" | dc
01 00 00

$ echo "31o 31 31 31 * * p" | dc
01 00 00 00
phuclv
  • 37,963
  • 15
  • 156
  • 475
0

If you just want to do some calculations and not heavy number crunching you can use my calculator Kalkulon together with a simple Kalkulon script for big number arithmetic. An interactive Kalkulon session looks like this:

Load("examples/bignum.k")
                    outl[1] = 0

string2Bn("1234567890ABCDEFGHIJKLMNOPQRSTU",31)
                    outl[2] = {587, 938220, 58035, 844882, 441786, 886253, 755598, 800665}

string2Bn("UTSR",31)
                    outl[3] = {922494}

mulBn(outl[2], outl[3])
                    outl[4] = {542, 369480, 374217, 718688, 983253, 751847, 772017, 360020, 658510}

printBn(out)
542369480374217718688983253751847772017360020658510
                    outl[5] = 51

Bn2string(outl[4],31)
                    outl[6] = "121UOIC5UEHLRAUOIC5UOIC5UOIC5UNHB64"

divBn(outl[4], outl[2])
                    outl[7] = {922494}

Bn2string(out,31)
                    outl[8] = "UTSR"

I am just curious: why do you want to calculate in base 31?

j.holetzeck
  • 4,048
  • 2
  • 21
  • 29
  • Thanks, I got a simple program with similar functions from my colege. The problem is that the syntax is too complicated. I need to calculate a lot of calculations and think about them, which is kind of hard, if you have to write complicated expression like: Bn2string(mulBn(string2Bn("HI"),string2Bn("HELLO"))). – Jakub Opršal May 08 '13 at 10:32
  • And, the reason was that I'm creating a puzzle for a puzzlehunt. Somewhat 31 is a good number, because I can use all letters of alphabet as digits (we added some specifick Czech letters to get to 31), and secondly it's prime. So another motivation for such calculator is to calculate something in p-adic numbers, or at least get a better grab of them. – Jakub Opršal May 08 '13 at 10:36
  • It would be really great to have something similar to bc (i.e., basically bc clone) for p-adic arithmetic. (For some info on p-adic numbers see http://en.wikipedia.org/wiki/P-adic_number.) – Jakub Opršal May 08 '13 at 10:39
  • @Iacob that's interesting! I must admit that Kalkulon is not the right tool then, but at least it would be possible to simplify the syntax a little bit `base=31, mul(x,y)=Bn2string(mulBn(string2Bn(x, base), string2Bn(y,base)), base)` and `add(x,y)=Bn2string(addBn(string2Bn(x, base), string2Bn(y,base)), base)`, so `add(mul("HI", "HELLO"), "GOOD") = "9S6UAIB"` – j.holetzeck May 08 '13 at 13:00
0

You can use Perl, with either the Math::BaseCalc module

$ echo $(( 31*31*31 )) | perl -n -MMath::BaseCalc -e 'my $calc = new Math::BaseCalc(digits => [ "0".."9", "a".."u" ]); print $calc->to_base($_) . "\n"'
1000

$ echo 0xDEADBEEF | perl -n -MMath::BaseCalc -e 'my $calc = new Math::BaseCalc(digits => [ "0".."9", "a".."u" ]); print $calc->to_base($_) . "\n"'
46f9imf

or the Math::Base::Convert module

$ echo $(( 31*31*31*31 )) | perl -n -MMath::Base::Convert -e '$f = new Math::Base::Convert("10", [ "0".."9", "a".."u" ]); print $f->cnv(int($_)) . "\n"'
10000

$ perl -MMath::Base::Convert -e '$f = new Math::Base::Convert("10", [ "0".."9", "a".."u" ]); print $f->cnv(31*31*31) . "\n"'
1000

$ perl -MMath::Base::Convert -e '$f = new Math::Base::Convert("10", [ "0".."9", "a".."u" ]); print $f->cnv(0xDEADBEEF) . "\n"'
46f9imf

In both cases [ "0".."9", "a".."u" ] is the digit list to use, which contains 31 symbols for base 31

phuclv
  • 37,963
  • 15
  • 156
  • 475