Skip to main content
added code to find the numbers, improved answer by 5 bytes
Source Link
nthistle
  • 1.3k
  • 7
  • 13

Python 3.6.5 on Linux, 9090 85 bytes

h=hash;lambda f:h(f(.0869))%3%2*"a"+["tan","sin","cos"][h%3%2*"a"+"tscaionns"[h(f(.14864))%3]+h%3::3]+h(f(.511))%5%2*"h"

Like orlp's answer, it uses the functions from Python's built-in cmath module as input.

Saved 5 bytes by using slice indexing into the middle string

Finding the Magic Numbers

For completeness, here's (more or less) the script I used to find these magic numbers. I mostly just worked straight in a python terminal, so the code is messy, but it gets the job done.

import cmath
fns = [(fn, getattr(cmath, fn)) for fn in ["sin","cos","tan","asin","acos","atan","sinh","cosh","tanh","asinh","acosh","atanh"]]

count_length = lambda num, modulus, base_modulus : len(str(num).rstrip('0').lstrip('0')) + (1 + len(str(modulus)) if modulus != base_modulus else 0)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][0]=="a") or (val == 1 and fn[0][0]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(3,10):
   for i in range(100000):
      num = i/100000.
      mapping = {}
      is_valid = True
      for fn in fns:
         fn_type = "sin" if "sin" in fn[0] else "cos" if "cos" in fn[0] else "tan"
         val = hash(fn[1](num))%modulus%3
         if val in mapping and mapping[val] != fn_type:
            is_valid = False
            break
         mapping[val] = fn_type
      if is_valid:
         length = count_length(num, modulus, 3)
         if length < min_length:
            min_length = length
            min_choice = (modulus, num, mapping)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][-1]=="a") or (val == 1 and fn[0][-1]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

Python 3.6.5 on Linux, 90 bytes

h=hash;lambda f:h(f(.0869))%3%2*"a"+["tan","sin","cos"][h(f(.14864))%3]+h(f(.511))%5%2*"h"

Like orlp's answer, it uses the functions from Python's built-in cmath module as input.

Python 3.6.5 on Linux, 90 85 bytes

h=hash;lambda f:h(f(.0869))%3%2*"a"+"tscaionns"[h(f(.14864))%3::3]+h(f(.511))%5%2*"h"

Like orlp's answer, it uses the functions from Python's built-in cmath module as input.

Saved 5 bytes by using slice indexing into the middle string

Finding the Magic Numbers

For completeness, here's (more or less) the script I used to find these magic numbers. I mostly just worked straight in a python terminal, so the code is messy, but it gets the job done.

import cmath
fns = [(fn, getattr(cmath, fn)) for fn in ["sin","cos","tan","asin","acos","atan","sinh","cosh","tanh","asinh","acosh","atanh"]]

count_length = lambda num, modulus, base_modulus : len(str(num).rstrip('0').lstrip('0')) + (1 + len(str(modulus)) if modulus != base_modulus else 0)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][0]=="a") or (val == 1 and fn[0][0]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(3,10):
   for i in range(100000):
      num = i/100000.
      mapping = {}
      is_valid = True
      for fn in fns:
         fn_type = "sin" if "sin" in fn[0] else "cos" if "cos" in fn[0] else "tan"
         val = hash(fn[1](num))%modulus%3
         if val in mapping and mapping[val] != fn_type:
            is_valid = False
            break
         mapping[val] = fn_type
      if is_valid:
         length = count_length(num, modulus, 3)
         if length < min_length:
            min_length = length
            min_choice = (modulus, num, mapping)
print(min_choice)

min_length = float("inf")
min_choice = None
for modulus in range(2,10):
   for i in range(1,100000):
      num = i/100000.
      is_valid = True
      for fn in fns:
         val = hash(fn[1](num))%modulus%2
         if (val == 0 and fn[0][-1]=="a") or (val == 1 and fn[0][-1]!="a"):
            is_valid = False
      if is_valid:
         length = count_length(num, modulus, 2)
         if length < min_length:
            min_length = length
            min_choice = (modulus,num)
print(min_choice)
Source Link
nthistle
  • 1.3k
  • 7
  • 13

Python 3.6.5 on Linux, 90 bytes

h=hash;lambda f:h(f(.0869))%3%2*"a"+["tan","sin","cos"][h(f(.14864))%3]+h(f(.511))%5%2*"h"

This builds upon orlp's answer; but instead of finding 1 magic number, we find 3! This basically just saves bytes by avoiding putting the string literals for "sin", "cos", and "tan" multiple times, instead building the answer one part at a time.

The first magic number is used to determine whether it's one of the "arc" trigonometric functions, prepending an "a" accordingly, the second for whether it's one of the "sin", "cos", or "tan" based functions, selecting the appropriate string, and the third for whether it's one of the hyperbolic functions, appending a "h" accordingly.

Like orlp's answer, it uses the functions from Python's built-in cmath module as input.