知乎热榜 ( ) • 2024-03-15 11:25
Crossin的回答

说个有意思的不等式:

它的名字叫做塔珀自指公式(Tupper's self-referential formula)。其中⌊⋅⌋表示向下取整,mod表示模取。

这个公式的神奇之处在于:按照这个公式绘制出的二维图像与公式本身一样。就像这样:

当然这不是函数的完整图像,只是其中取特定值时的部分片段:当

k=960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719

在0≤x≤105,k≤y≤k+16的位置上,就会显示出这样的图像(要注意坐标轴方向)。

from functools import reduce
import matplotlib.pyplot as plt
import math
xs = []
ys = []
k = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
for x in range(106):
    for y in range(k, k+17):
        d = ((-17 * x) - (y % 17))
        e = reduce(lambda x, y: x * y, [2 for x in range(-d)]) if d else 1
        if 0.5 < math.floor((math.floor(y//17)//e) % 2):
            xs.append(x)
            ys.append(y-k)
plt.figure(figsize=(20,3))
plt.xlim(106, -1)
plt.ylim(17, -1)
plt.scatter(xs, ys, marker='s')

它的原理可以理解为:这个公式通过常数k来解码一个黑白位图。理论上来说,它可以表示106x17大小的任意图像。

并且这种解码和编码是双向的,也就是说你可以通过一个已有的点阵图,反推k值。

于是,又有人整了这么个工具:Tupper's Self-Referential Formula Playground

你可以借助它来找到特定的k,放到代码里就可以绘制出你想要的图案。比如这样:

另外,看到有回答提到爱心曲线,之前我也写过类似的几种实现:

可以绘制出爱心的函数有不止一种:

for y in range(9, -6, -1):
    for x in range(-8, 9):
        print('*##*'[(x+10)%4] if (x*x+y*y-25)**3 < 25*x*x*y*y*y else '-', end=' ')
    print()
size = 10
for x in range(size):
    for y in range(4*size+1):
        dist1 = ((x-size)**2 + (y-size)**2) ** 0.5
        dist2 = ((x-size)**2 + (y-3*size)**2) ** 0.5
        if dist1 < size + 0.5 or dist2 < size + 0.5:
            print('V', end=' ')
        else:
            print(' ', end=' ')
    print()

for x in range(1, 2*size):
    for y in range(x):
        print(' ', end=' ')
    for y in range(4*size+1-2*x):
        print('V', end=' ')
    print()
from math import pi, sin, cos
import matplotlib.pyplot as plt
no_pieces = 100
dt = 2*pi/no_pieces
t = 0
vx = []
vy = []
while t <= 2*pi:
    vx.append(16*sin(t)**3)
    vy.append(13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t))
    t += dt
plt.plot(vx, vy)
plt.show()