14
\$\begingroup\$

Edit: I will be posting a newer version of this question on meta-golf soon. Stay tooned!

Edit #2: I will no longer be updating the challenge, but will leave it open. The meta-golf version is available here: https://codegolf.stackexchange.com/questions/106509/obfuscated-number-golf

Background:

Most numbers can be written with only 6 different symbols:

  • e (Euler's Constant)
  • - (Subtraction, Not Negation)
  • ^ (Exponentiation)
  • (
  • )
  • ln (Natural Logarithm)

For example, you could convert the imaginary number i using this equation:

(e-e-e^(e-e))^(e^(e-e-ln(e^(e-e)-(e-e-e^(e-e)))))

Goal:

Given any integer k through any reasonable means, output the shortest representation possible of that number using only those 6 symbols.

Examples:

0 => "e-e"
1 => "ln(e)"
2 => "ln(ee)"
// Since - cannot be used for negation, this is not a valid solution: 
// ln(e)-(-ln(e))
-1 => "e-e-ln(e)"

Notes:

  • Ending parenthesis count towards the total amount of characters.
  • ln( only counts as 1 character.
  • Everything else counts as 1 character.
  • n^0=1
  • Order of operations apply
  • Parenthesis multiplying is acceptable, e.g. (2)(8)=16, 2(5)=10, and eln(e)=e.
  • ln e is not valid, you must do ln(e)
\$\endgroup\$
17
  • 3
    \$\begingroup\$ I think that formula (ln(ee...e)) is the best way to portray positives. Edit: no, its not. ln(e^(ln(eeeee)ln(eeee))) is better for 20 \$\endgroup\$ Jan 10, 2017 at 17:59
  • 6
    \$\begingroup\$ @JulianLachniet love the idea, would like to see the first 10-20 terms of the sequence requested though. Maybe put up an example for -10 to 10 for clarification. WheatWizard has already poked a couple holes, with those holes the objective criteria of "shortest possible" is hard to determine without concrete examples. \$\endgroup\$ Jan 10, 2017 at 18:03
  • \$\begingroup\$ Not sure about some of the higher ones, especially 20. \$\endgroup\$ Jan 10, 2017 at 18:05
  • 2
    \$\begingroup\$ ln(eeee)^ln(ee) is a shorter than ln(eeeeeeeeeeeeeeee) for 16 \$\endgroup\$
    – Wheat Wizard
    Jan 10, 2017 at 18:17
  • 8
    \$\begingroup\$ Just a word of suggestion. I think this might be more fun as a meta-golf challenge than as a code-golf challenge. Its really hard to demonstrate that some code always produces the optimal result so it might be better to score answers on how well they golf their output. \$\endgroup\$
    – Wheat Wizard
    Jan 10, 2017 at 18:19

1 Answer 1

2
\$\begingroup\$

Python 3, 402 bytes

from itertools import*
from ast import*
from math import*
v,r=lambda x:'UnaryOp'not in dump(parse(x)),lambda s,a,b:s.replace(a,b)
def l(x,y):
    for s in product('L()e^-',repeat=x):
        f=r(r(r(''.join(s),'L','log('),')(',')*('),'^','**')
        g=r(f,'ee','e*e')
        while g!=f:f,g=g,r(g,'ee','e*e')
        try:
            if eval(g)==y and v(g):return g
        except:0
def b(v):
    i=1
    while 1:
        r=l(i,v)
        if r:return r
        i+=1

Example usage:

>>> b(1)
'log(e)'
>>> b(0)
'e-e'
>>> b(-3)
'e-log(e*e*e)-e'
>>> b(8)
'log(e*e)**log(e*e*e)'

Note that although the output format may not reflect it, the code properly counts all lengths according to the question's specifications.

This is a dumb bruteforce through all the possible lengths of strings. Then I use some replacements so that Python can evaluate it. If it's equal to what we want, I also check to exclude unary negative signs by checking the AST.

I'm not very good at golfing in Python, so here's the semi-ungolfed code if anybody wants to help!

from itertools import*
from ast import*
from math import*

def valid(ev):
    return 'UnaryOp' not in dump(parse(ev))

def to_eval(st):
    f = ''.join(st).replace('L', 'log(').replace(')(', ')*(').replace('^', '**')
    nf = f.replace('ee', 'e*e')
    while nf != f:
        f, nf = nf, nf.replace('ee', 'e*e')
    return nf

def try_length(length, val):
    for st in product('L()e^-', repeat=length):
        ev = to_eval(st) 
        try:
            if eval(ev) == val and valid(ev):
                return st
        except:
            pass

def bruteforce(val):
    for i in range(11):
        res = try_length(i, val)
        if res:
            print(i, res)
            return res
\$\endgroup\$
1
  • \$\begingroup\$ Instead of indenting with tabs you can indent with spaces for one level of indent and tabs for 2. \$\endgroup\$
    – Wheat Wizard
    Jan 12, 2017 at 15:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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