27
\$\begingroup\$

The objective of this challenge is to write a program to convert an inputed string of what can be assumed as containing only letters and numbers from as many bases between 2 and 36 as possible, and find the base 10 sum of the results.

The input string will be converted to all the bases in which the number would be defined according to the standard alphabet for bases up to 36: 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ. For example, the input 2T would be valid in only bases 30 and up. The program would convert 2T from bases 30 through 36 to decimal and sum the results.

You may assume that the input string contains only letters and numbers. Your program may use uppercase or lowercase; it can, but does not need to, support both.


Test cases

Sample input: 2T

Chart of possible bases

Base   Value
30     89
31     91
32     93
33     95
34     97
35     99
36     101

Output: 665

Sample input: 1012

Chart of possible bases:

Base   Value
3      32
4      70
5      132
6      224
7      352
8      522
9      740
10     1012
11     1344
12     1742
13     2212
14     2760
15     3392
16     4114
17     4932
18     5852
19     6880
20     8022
21     9284
22     10672
23     12192
24     13850
25     15652
26     17604
27     19712
28     21982
29     24420
30     27032
31     29824
32     32802
33     35972
34     39340
35     42912
36     46694

Output: 444278

Sample input: HELLOworld

Chart of possible bases

Base   Value
33     809608041709942
34     1058326557132355
35     1372783151310948
36     1767707668033969

Output: 5008425418187214

An input of 0 would be read as 0 in all bases between 2 and 36 inclusive. There is no such thing as base 1.


This is code golf. Standard rules apply. Shortest code in bytes wins.

\$\endgroup\$
12
  • 5
    \$\begingroup\$ Are builtins for base conversion allowed? \$\endgroup\$
    – lirtosiast
    Dec 4 '15 at 16:29
  • 2
    \$\begingroup\$ Important test case: 0 \$\endgroup\$ Dec 4 '15 at 17:12
  • 3
    \$\begingroup\$ @MartinBüttner Why is 0 an important test case? 0 is 0 in every base, and there's no such thing as base 1. \$\endgroup\$
    – Arcturus
    Dec 4 '15 at 18:33
  • 4
    \$\begingroup\$ @Eridan because some languages might try converting that from base 1 and fail. \$\endgroup\$ Dec 4 '15 at 18:44
  • 1
    \$\begingroup\$ The HELLOworld implies that the program must be able to output greater than 32-bit integers. Is this correct or can we just 32 bit outputs? If not, do we do just up to 64 bit integers, or do we need to arbitrary precision? \$\endgroup\$ Dec 4 '15 at 22:18

26 Answers 26

13
\$\begingroup\$

Python 3, 72 71 69 bytes

Thanks to FryAmTheEggman for saving a byte!

Thanks to DSM for saving 2 bytes!

N=x=0
y=input()
while N<36:
 N+=1
 try:x+=int(y,N)
 except:0
print(x)
\$\endgroup\$
8
  • \$\begingroup\$ @ThomasKwa that will add a zero, which will not work for purely numeric inputs as that functions as checking if it's base 10 (which will make some results too large) \$\endgroup\$
    – Kevin W.
    Dec 4 '15 at 16:57
  • \$\begingroup\$ @FryAmTheEggman Thanks! I have adjusted it \$\endgroup\$
    – Adnan
    Dec 4 '15 at 17:41
  • \$\begingroup\$ Just checked for you. The try except will let you do range(37). Two bytes! \$\endgroup\$
    – Sherlock9
    Dec 4 '15 at 17:47
  • \$\begingroup\$ @Sherlock9 It won't work for purely numeric inputs, these will be interpreted as base 10 numbers. \$\endgroup\$
    – Adnan
    Dec 4 '15 at 17:50
  • \$\begingroup\$ Oh right, darn. @Adnan \$\endgroup\$
    – Sherlock9
    Dec 4 '15 at 17:54
9
\$\begingroup\$

Pyth, 20 19 11 bytes

sm.xizd0S36

Blatantly stole Adnan's idea from his Python answer.

Try it here

\$\endgroup\$
2
  • \$\begingroup\$ @orlp You can remove the S char \$\endgroup\$
    – Blue
    Dec 4 '15 at 20:20
  • \$\begingroup\$ Nope. Test 1012. \$\endgroup\$
    – orlp
    Dec 4 '15 at 23:39
6
\$\begingroup\$

Pure Bash, 26

((s+={36..2}#$1,))
echo $s

Try it online!


Old answer from 5 years ago:

Pure Bash (no utilities), 38

Assuming built-in base conversions are allowed:

for((b=36;s+=$b#$1;b--));{ :;}
echo $s

This will output an error to STDERR. I'm assuming this is OK as per this meta answer.

Test output:

$ for t in 0 2T 1012 HELLOworld; do ./basesum.sh $t; done 2> /dev/null
0
665
444278
5008425418187214
$ 
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I've just written the same answer in zsh and I'm very sad that you got it first!! \$\endgroup\$
    – pxeger
    Jan 20 '21 at 17:16
3
\$\begingroup\$

Seriously, 65 bytes

,û;╗rk`"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"íu`MSd:37:@x`╜¿`MΣ.

Contains unprintables, hexdump:

2c963bbb726b6022303132333435363738394142434445464748494a4b4c4d4e4f505152535455565758595a22a175604d53643a33373a407860bda8604de42e7f

Unfortunately I don't have a good way to filter from a list based on types. Note to self: add that.

Takes input like "2T"

Try it online (you will have to manually enter input)

Explanation:

,û    get input and convert to uppercase
;╗    make a copy and save to register 0
rk    explode string into list
`"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"íu`M  map the function over the list:
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"íu    get the character's index in the string and add one to get a value in [1,36]
Sd    get maximum element (maximum base aka max_base) from list by sorting and popping the last element off and pushing it to the stack
:37:@x  push range(max_base,37)
`╜¿`M  map the function over the list:
    ╜¿    convert value in register 0 to an int, interpreting it as a base-n int (n is value from list)
Σ.    sum and print
0x7f  quit
\$\endgroup\$
2
  • \$\begingroup\$ Perhaps Seriously should have a command that produces the alphabet and/or the numbers 0-9? \$\endgroup\$
    – Arcturus
    Dec 5 '15 at 2:16
  • \$\begingroup\$ @Eridan It seriously should - getting that index costs half the bytes. \$\endgroup\$
    – user45941
    Dec 5 '15 at 7:48
2
\$\begingroup\$

Mathematica, 57 bytes

#~Sum~{x,Max@CoefficientList[#,x]+1,36}&@FromDigits[#,x]&
\$\endgroup\$
1
  • \$\begingroup\$ You can use infix form for the FromDigits. \$\endgroup\$ Dec 5 '15 at 0:15
2
\$\begingroup\$

Matlab, 98 bytes

function y=f(s)
[~,m]=max(bsxfun(@eq,s,[48:57 65:90]'));y=0;for n=max(m):36
y=y+base2dec(s,n);
end
\$\endgroup\$
2
\$\begingroup\$

Octave, 75 73 bytes

function v=u(a) m([48:57 65:90])=0:35;v=sum(polyval(t=m(a),max(t)+1:36));

Explanation:

function v=u(a) 
   m([48:57 65:90])=0:35; %// create a map: '0'-'9' = 0-9
                          %//               'A'-'Z' = 10-35
   t=m(a);                %// convert string to mapped values
   b=max(t)+1;            %// find minimum base
   p=polyval(t,b:36);     %// calculate polynomial for each base (vectorized)
   v=sum(p);              %// and return the sum of the resulting vector

polyval has an advantage over base2dec in that it's vectorized, so no for loop is required.

Only '0'..'9' and upper-case 'A'..'Z' are supported as input.

\$\endgroup\$
1
  • \$\begingroup\$ Very clever use of polyval to vectorize! \$\endgroup\$
    – Luis Mendo
    Dec 4 '15 at 22:50
2
\$\begingroup\$

Husk, 22 bytes

or 21 bytes with only lowercase input

§ṁ`Bö-1…36→▲mö%48%87c_

Try it online!

§ṁ`Bö-1…36→▲mö%48%87c_
§                       # fork: apply 2 functions to same argument
 ṁ`B                    # function 1: 
 ṁ                      # sum of elements of argument
  `B                    # interpreted as base N, with N given by
    ö-1…36→▲            # function 2:
    ö                   # combine 4 funcitions:
     -1                 # remove elements equal to 1 from 
       …36              # series from 36 to
          →             # one less than
           ▲            # max value of argument
            mö%48%87c_  # fork argument:
            mö          # map 4 functions over input:
                     _  # convert to lowercase  
                    c   # get ASCII value
                 %87    # MOD 87
              %48       # MOD 48
\$\endgroup\$
0
2
\$\begingroup\$

Haskell, 77 bytes

f s|d<-[mod(fromEnum c+30)39|c<-s]=sum[foldl1((+).(b*))d|b<-[2..36],all(<b)d]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

R, 44 bytes

sum(sapply(2:36,strtoi,x=scan(,"")),na.rm=T)

Try it online!

R has a builtin, strtoi, to convert from a string to an integer in base 2:36 using only digits and capital letters, returning NA if it's invalid in that base. We can then sum them up, removing the NAs with na.rm=T.

Luckily, sapply is smart enough about named arguments to make this work.

\$\endgroup\$
2
\$\begingroup\$

Desmos, 85 bytes

f(x)=x+3.5sign(60-x)-51.5
l=i.length
\sum_{n=f(i).max+1}^{36}\sum_{m=1}^lf(i[m])n^{l-m}

View it on Desmos (includes a bonus version that costs 2 extra bytes)

Explanation:

Input is through an array of integers i, as Desmos doesn't support strings. Capital letters are required.

The first function transforms a codepoint to the value in base-36, or any other base that it's valid in. The second function simply stores i.length, as it's expensive to call.

The third function can be understood as such:

\sum_{n=f(i).max+1}^{36}    Iterate n from 1+the largest codepoint value, which will be the smallest valid base, to 36, the largest valid base
\sum_{m=1}^l                Iterate m over the indices of i (Desmos is 1-indexed)
f(i[m])                     Find the value of the mth character
n^{l-m}                     Multiply by the base to the power of its distance to the right
                            Add everything up (due to using sums earlier)
\$\endgroup\$
2
\$\begingroup\$

Scala, 64 bytes

Requires uppercase input

s=>(s.map(_%55%48).max+1 to 36).map(b=>(0L/:s)(_*b+_%55%48)).sum

Try it in Scastie

-7 bytes by using a Long (0L) instead of a BigInt (BigInt(0))

This might have been shorter if I'd used try/catch with BigInt(number, base), but I didn't want to do that. Still wish I could inline n, but I need it to determine the first valid base. Apparently, it's one byte shorter by not doing val n=s.map(_%55%48) and reusing n.

Explanation:

s =>                        //Input
  (s.map(_ % 55 % 48)       //Turn the characters into numbers 0-35
    .max+1                  //The maximum of that (minimum base)
      to 36)                //Range of bases up to 36
  .map(b =>                 //For each base b, interpret the input in that base
    (BigInt(0)              //Starting with 0,
              /:s)          //Fold left over the input
    (_ * b +                //Multiply the accumulator by the base
      _ % 55 % 48)          //And add the next digit (put it in the range [0, 35])
  ).sum                     //Take the sum
\$\endgroup\$
2
\$\begingroup\$

Jelly, 13 bytes

ØBiⱮµ’ḅṀr36ƊS

Try it online!

Works only for uppercase letters.

Explanation

ØBiⱮµ’ḅṀr36ƊS   Monadic link
   Ɱ            Map over argument:
  i             Find 1-based index in...
ØB              ...base digits: "0123456789ABCD...YZabcd...yz"
    µ           Use as argument to new monadic chain
     ’          Decrement (to get 0-based indices)
      ḅ         Convert to base... (auto-mapped)
           Ɗ    ...treat 3 preceding atoms as a single link:
       Ṁ        Maximum [of argument, which is the 1-based indices]
        r36     Inclusive range to 36
            S   Sum
\$\endgroup\$
1
\$\begingroup\$

CJam, 28 27 bytes

Thanks to Reto Koradi for saving 1 byte.

This is kinda horrible...

qA,s'[,65>+f#_:e>)37,>\fb:+

Requires upper case letters.

Test it here.

CJam doesn't have built-in base-36 conversion from strings, so we have to letters out the strings ourselves. I've been trying all sorts of divmod shenanigans, but it seems to be shortest to build a string of all 36 digits and just find the index of each character in that string.

\$\endgroup\$
2
  • \$\begingroup\$ q{'0-_9>7*-}% is just as short. \$\endgroup\$ Dec 4 '15 at 18:17
  • \$\begingroup\$ @PeterTaylor Oh, right... \$\endgroup\$ Dec 4 '15 at 19:49
1
\$\begingroup\$

C function, 93 (32 bit integer output only)

Assuming its OK for the output to only go up to INT_MAX, then we can do this:

i,n,x;f(char *s){char *e;for(i=36,x=0;n=strtol(s,&e,i--),!*e&&i;)x+=*e?0:n;printf("%d\n",x);}

The last testcase implies that this is probably not sufficient. If so, then with 64-bit integers we have:

C function, 122

#include<stdlib.h>
f(char *s){long long i=36,n,x=0;char *e;for(;n=strtoll(s,&e,i--),!*e&&i;)x+=*e?0:n;printf("%lld\n",x);}

Unfortunately the #include <stdlib.h> is required so the return type of strtoll() is correct. We need to use long long to handle the HELLOworld testcase. Otherwise this could be a fair bit shorter.

Test driver:

#include<stdlib.h>
f(char *s){long long i=36,n,x=0;char *e;for(;n=strtoll(s,&e,i--),!*e&&i;)x+=*e?0:n;printf("%lld\n",x);}

int main (int argc, char **argv)
{
    f("0");
    f("2T");
    f("1012");
    f("HELLOworld");
}

Test output:

$ ./basesum
0
665
444278
5008425418187214
$ 
\$\endgroup\$
2
  • \$\begingroup\$ In C can you remove the space in #include <stdlib.h> like you can in C++? \$\endgroup\$
    – Alex A.
    Dec 4 '15 at 19:17
  • \$\begingroup\$ @AlexA. Yes - I didn't know that - thanks! \$\endgroup\$ Dec 4 '15 at 22:10
1
\$\begingroup\$

Japt -x, 17 16 bytes

36õ2 k@kUnXXãnX

Try it

\$\endgroup\$
1
\$\begingroup\$

Factor, 38 bytes

[ 37 iota [ base> ] with map sift Σ ]

Try it online!

Explanation:

It's a quotation (anonymous function) that takes a string from the data stack as input and leaves an integer on the data stack as output.

  • 37 iota Create a range from 0 to 36 inclusive.
  • [ base> ] with map Convert the input to base 10 from each base between 0 and 36. If the input can't be converted from particular base, base> returns f.
  • sift Remove all the f from a sequence.
  • Σ Sum.
\$\endgroup\$
0
\$\begingroup\$

Japt, 26 bytes

1+U¬r@XwYn36}0)o37 £UnX} x

Try it online!

Ungolfed and explanation

1+U¬ r@   XwYn36}0)o37 £    UnX} x
1+Uq rXYZ{XwYn36}0)o37 mXYZ{UnX} x

           // Implicit: U = input string
Uq rXYZ{   // Split U into chars, and reduce each item Y and previous value X by:
XwYn36     //  Choosing the larger of X and parseInt(Y,36),
}0         // starting at 0.
1+   )o37  // Add 1 and create a range from this number to 36.
mXYZ{UnX}  // Map each item X in this range to parseInt(U,X)
x          // and sum.
           // Implicit: output last expression
\$\endgroup\$
0
\$\begingroup\$

Python 3, 142 bytes

Adnan has me soundly beat with their solution, but I did want to add my own attempt.

def f(s):
 t=0
 for x in range(37):
  n=0
  for i in s:
   try:m=int(i)
   except:m=ord(i)-55
   if x<=m:n=0;break
   n=n*x+m
  t+=n
 return t

This function only handles uppercase inputs. Add .upper() to for i in s, and it will handle both uppercase and lowercase.

\$\endgroup\$
0
\$\begingroup\$

Pyth, 16 bytes

V36 .x=+ZizhN ;Z

Try it online

Explaination:

                 # Implicit: Z = 0, z = input
V36              # For N in range 36
    .x           # Try except
      =+Z        # Z = Z + izhN
         izhN    # Convert z from base N+1 to decimal
              ;  # Infinite ), for closing the for loop
               Z # Print Z
\$\endgroup\$
0
\$\begingroup\$

Scala 2.11, 93 bytes

This is run on the scala console.

val i=readLine
var s=0
for(j<-2 to 36)try{s=s+Integer.parseInt(i,j)}catch{case _:Exception=>}
\$\endgroup\$
0
\$\begingroup\$

Haskell, 97 bytes

i c|'_'<c=fromEnum c-87|1<2=read[c]
f s=sum$map((`foldl1`map i s).((+).).(*))[1+i(maximum s)..36]

Supports only lowercase characters. Usage example:

f "2t"           -> 665
f "helloworld"   -> 5008425418187214

It's so massive, because I have to implement both char-to-ASCII and base conversion myself. The corresponding pre-defined functions are in modules which require even more expensive imports.

How it works: i converts a character c to it's digit value (e.g. i 't' -> 29). f calculates the value of the input string for every possible base and sums it. A non-pointfree version of the inner loop is map (\base -> foldl1 (\value digit -> value*base + digit) (map i s)) [ ...bases... ].

\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 86 bytes

s=>eval(`p=parseInt;b=2;[...s].map(d=>(v=p(d,36))>b?b=v:0);for(r=0;++b<37;)r+=p(s,b)`)

Explanation

s=>
  eval(`                     // use eval to enable for loop without return keyword or {}
    p=parseInt;
    b=2;                     // b = minimum base of s
    [...s].map(d=>           // iterate through each digit d
      (v=p(d,36))            // get it's base-36 value
        >b?b=v:0             // set b to the max value
    );
    for(r=0;++b<37;)         // r = sum of all base values
      r+=p(s,b)              // add each base value from b to 36 to r
  `)                         // implicit: return r

Test

<input type="text" id="input" value="HELLOworld" />
<button onclick="result.textContent=(

s=>eval(`p=parseInt;b=2;[...s].map(d=>(v=p(d,36))>b?b=v:0);for(r=0;++b<37;)r+=p(s,b)`)

)(input.value)">Go</button>
<pre id="result"></pre>

\$\endgroup\$
3
  • \$\begingroup\$ &&b=v saves 1 byte over ?b=v:0. \$\endgroup\$
    – Neil
    Dec 6 '15 at 19:15
  • \$\begingroup\$ @Neil Did you test it? I'm pretty sure that would be an invalid left-hand of assignment. \$\endgroup\$
    – user81655
    Dec 6 '15 at 21:58
  • \$\begingroup\$ Sorry I confused it with a similar case in another golf. \$\endgroup\$
    – Neil
    Dec 7 '15 at 10:42
0
\$\begingroup\$

Perl 6, 35 bytes

{[+] map {+(":$^a"~"<$_>")||0},^37}

usage:

# store it somewhere
my &code = {[+] map {+(":$^a"~"<$_>")||0},^37}

say code 'HELLOworld' # 5008425418187214

say map &code, <2T 1012>
# (665 444278)

say code 'qwertyuiopasdfghjklzxcvbnm1234567890'
# 79495849566202185148466281109757186006261081372450955140
\$\endgroup\$
0
\$\begingroup\$

Ceylon, 100 96 bytes

Integer b(String s)=>sum(((any(s*.letter)then 11else 2)..36).map((r)=>parseInteger(s,r)else 0));

I first had this simpler version taking just 69 bytes:

Integer b(String s)=>sum((2..36).map((r)=>parseInteger(s,r)else 0));

But this fails with the first test case, returning 2000000000665 instead of 665. (The reason is that the T in 2T is parsed as Tera, i.e. multiplies the 2 with 10^12, when the radix is 10.) Therefore we need to catch this case separately. Thanks to Neil for suggesting a different way of doing this which saved 4 bytes.

Formatted:

// Find sum of all possible base representations.
//
// Question:  https://codegolf.stackexchange.com/q/65748/2338
// My Answer: https://codegolf.stackexchange.com/a/65836/2338

Integer b(String s) =>
// take the sum of ...
        sum(
    // span from 2 to 36. (Though
    // if there are letters in there, we start at 11,
    // because the other ones can't be valid.
    // Also, parseInteger(s, 10) behaves a bit strange in Ceylon.)
    ((any(s*.letter) then 11 else 2) .. 36)
    // map each r of them to ...
        .map((r) =>
            // try parsing s as a number using base r
            parseInteger(s, r)
            // if that didn't succeed, use 0.
                    else 0
    )
);
\$\endgroup\$
1
  • \$\begingroup\$ Can you perhaps shorten the code by starting from base 11 if the string contains a letter, thus avoiding having to special-case base 10? \$\endgroup\$
    – Neil
    Dec 6 '15 at 19:12
0
\$\begingroup\$

K (ngn/k), 38 35 bytes

{+/t{y/x}/:(|/t:x+7*3>x-:55)_1+!36}

Try it online!

Takes capitalized input, e.g. "2T".

  • t:x+7*3>x-:55 map input from characters to 0..35, storing in t
  • (|/t...)_1+!36 identify the valid bases (those larger than the largest value in the input)
  • t{y/x}/: convert t, interpreted as each valid base, to decimal
  • +/ take the sum and return
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.