代码急转弯——Tupper(塔珀自指公式)

1、塔珀自指公式

塔珀自指公式(Tupper’s Self-Referential Formula)来自于Jeff Tupper在2001年发表的一篇论文,涉及到一个函数 f ( x , y ) f(x,y) f(x,y) ,一个参数 k k k,和一个图片 a a a
f ( x , y ) f(x,y) f(x,y) a a a 中的每一个点 ( x , y ) (x,y) (x,y) 进行判断,决定该点的颜色是0还是1,因此决定了 a a a 的图案。如果给定不同的 k k k,就会得到不同的图案。令人感到惊奇的是,有一个特别的 k k k,它会使得所得 a a a 竟然是 f f f 用来做判断的公式本身。下面就是塔珀公式,
1 2 < ⌊ m o d ( ⌊ y 17 ⌋ 2 − 17 ⌊ x ⌋ − m o d ( ⌊ y ⌋ , 17 ) , 2 ) ⌋ \frac{1}{2}< \left\lfloor mod(\left\lfloor\frac{y}{17}\right\rfloor2^{-17\lfloor x \rfloor-mod(\lfloor y \rfloor,17)},2) \right\rfloor 21<mod(17y217xmod(y,17),2)
其中, ⌊ x ⌋ \left\lfloor x \right\rfloor x 是向下取整函数, m o d ( a , b ) mod(a,b) mod(a,b) 计算 a a a 除以 b b b 的余数, 0 ≤ x ≤ 105 0\le x\le105 0x105 k ≤ y ≤ k + 16 k\le y\le k+16 kyk+16 k k k 会是一个什么样的数?
k = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719

print(len(str(k))
543

好家伙,足足有543位。我们来看看图片 a a a,体会其中的“自指”的含义。
在这里插入图片描述

2、如何绘制图片 a a a

import numpy as np
import matplotlib.pyplot as plt

def Tupper_self_referential_formula(k): 
    aa = np.zeros((17,106))
    def f(x, y):
        y += k
        a1 = 2**-(-17*x - y%17)
        a2 = (y // 17) // a1
        return 1 if a2 % 2 > 0.5 else 0
 
    for y in range(17):
        for x in range(106):
            aa[y, x] = f(x, y)
    
    return aa[:,::-1]

k = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
aa = Tupper_self_referential_formula(k)
plt.figure(figsize=(15,10))
plt.imshow(aa,origin='lower')

运行结果就是上面的图片。如果删除 k k k 前面的第一位数字9,那么将得到另一个完全不同的图片。
在这里插入图片描述
注意,不能直接按照公式编码计算,

a1 = 2**(-17*x - y%17)
a2 = (y // 17) * a1

这样做会溢出。

3、如何计算参数 k k k

在给定图片 a a a 后,如何找到 k k k
只要对 a a a 中的各元素进行排列,得到一个2进制数(因为 a a a 的元素都是1或者0),转换为10进制,再乘以17就得到了 k k k。排列顺序为,第0列自下而上,然后是第1列,也是自下而上,把各元素排列到一起,成为一个长长的二进制数字的字符串,如下例所示,

array([['a', 'b', 'c', 'd'],
       ['e', 'f', 'g', 'h'],
       ['i', 'j', 'k', 'l']], dtype='<U1')

排序的结果为 ieajfbkgclhd,从中可观察出排列的规则。下面是计算 k k k 代码,

b1 = aa[::-1] # 上下颠倒
b2 = b1.T.reshape(-1) # 降维成一维数组
b3 = [str(int(k)) for k in b2] # 各元素转变为0/1字母
b4 = ''.join(b3) # 拼接成二进制串
b5 = int(b4,2)*17 # 二进制串变为十进制数,再乘以17

''' 验证一下 '''
print('k - b5 =', k - b5)

现在用计算所得的 b 5 b5 b5 k k k 相减,结果为零。

k - b5 = 0

【下一个谜题】life游戏——最简元胞自动机

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值