不精确浮动在 Tupper 的自我参照公式中
Imprecise floats in Tupper's self-referential formula
我正在尝试制作一个绘制 Tupper's self-referential formula 的 Python 程序,但我 运行 遇到了一些问题。
首先,我的程序无法处理它必须处理的大浮点数,所以我决定使用 BigFloats
来解决我的问题。它起作用了,有点。我的问题是我有一个 540 位长的数字需要与 BigFloat
相乘,当我这样做时它会四舍五入使数字不精确,这会导致以后出现问题。我已尝试将 precision
提高到 1000,但它仍然会四舍五入该变量。
问题是有些数字可以在没有 BigFloat
的情况下处理到确切的值,但有些数字现在既不能正常处理也不能用 BigFloat
处理。
这里是计算出错的地方之一(这个不用BigFloat
也能处理):
import bigfloat
y = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
x = 0
with bigfloat.precision(1000):
(y//17 * bigfloat.pow(2,0)) % 2
该代码应该 return 1 但它 returns 0.
有没有办法让 BigFloat
更准确以便我可以在我的程序中使用它?
Tupper 公式不需要任何浮点数学运算。诀窍是 2-x 与 1/2x 相同,所以你只需要使用整数,因为你不需要计算浮点数 2-x 并将其与一个整数相乘,而是计算整数 2x 并将另一个整数除以该整数。应用于 Tupper 公式,2-17*int(x) - int(y)%17 部分变为 1/217*int(x) + int(y )%17。
看下面完全在整数域运行的Tupper函数的版本(如果你不知道**
是什么,那就是Python's power operator):
def tuppers_formula(x, y):
"""Return True if point (x, y) (x and y both start at 0) is to be drawn black, False otherwise
"""
k = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
return ((k + y)//17//2**(17*int(x) + int(y)%17))%2 > 0.5
你可以用下面的代码测试这个函数"draws"把Tupper公式的结果存入一个文本文件。
import codecs
import os
with codecs.open("tupper.txt", "w", "utf-8") as f:
values = [[tuppers_formula(x, y) for x in range(106)] for y in range(17)]
for row in values:
for value in row[::-1]: # x = 0 starts at the left so reverse the whole row
if value:
f.write("\u2588") # Write a block
else:
f.write(" ")
f.write(os.linesep)
结果是文件tupper.txt
,内容为:
█ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
██ █ █ █ █ ██ █ █ █ █ █ █ ██ ████ ███ ███ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ███ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ██ █ █
███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ ██ █ ██ ███ █ █ █ █ ███ ███ █ ███ ███ █ █ █ █ █
███ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
██ █ █ █ █ █ ██ ███ █ █ █ ██ █ ████ ████ █ █
█ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █
███ █ █ █ █ █ █ █ █
█ █ █ █ █ █
███ █ ███ ███ █ ███
我正在尝试制作一个绘制 Tupper's self-referential formula 的 Python 程序,但我 运行 遇到了一些问题。
首先,我的程序无法处理它必须处理的大浮点数,所以我决定使用 BigFloats
来解决我的问题。它起作用了,有点。我的问题是我有一个 540 位长的数字需要与 BigFloat
相乘,当我这样做时它会四舍五入使数字不精确,这会导致以后出现问题。我已尝试将 precision
提高到 1000,但它仍然会四舍五入该变量。
问题是有些数字可以在没有 BigFloat
的情况下处理到确切的值,但有些数字现在既不能正常处理也不能用 BigFloat
处理。
这里是计算出错的地方之一(这个不用BigFloat
也能处理):
import bigfloat
y = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
x = 0
with bigfloat.precision(1000):
(y//17 * bigfloat.pow(2,0)) % 2
该代码应该 return 1 但它 returns 0.
有没有办法让 BigFloat
更准确以便我可以在我的程序中使用它?
Tupper 公式不需要任何浮点数学运算。诀窍是 2-x 与 1/2x 相同,所以你只需要使用整数,因为你不需要计算浮点数 2-x 并将其与一个整数相乘,而是计算整数 2x 并将另一个整数除以该整数。应用于 Tupper 公式,2-17*int(x) - int(y)%17 部分变为 1/217*int(x) + int(y )%17。
看下面完全在整数域运行的Tupper函数的版本(如果你不知道**
是什么,那就是Python's power operator):
def tuppers_formula(x, y):
"""Return True if point (x, y) (x and y both start at 0) is to be drawn black, False otherwise
"""
k = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
return ((k + y)//17//2**(17*int(x) + int(y)%17))%2 > 0.5
你可以用下面的代码测试这个函数"draws"把Tupper公式的结果存入一个文本文件。
import codecs
import os
with codecs.open("tupper.txt", "w", "utf-8") as f:
values = [[tuppers_formula(x, y) for x in range(106)] for y in range(17)]
for row in values:
for value in row[::-1]: # x = 0 starts at the left so reverse the whole row
if value:
f.write("\u2588") # Write a block
else:
f.write(" ")
f.write(os.linesep)
结果是文件tupper.txt
,内容为:
█ █ █ ██ █ █ █ █ █ █ █ ██ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
██ █ █ █ █ ██ █ █ █ █ █ █ ██ ████ ███ ███ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ███ ███ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ ██ █ █
███ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
█ █ ██ █ ██ ███ █ █ █ █ ███ ███ █ ███ ███ █ █ █ █ █
███ █ █ █ █ █ █ █ █ █ █ █ ████ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
██ █ █ █ █ █ ██ ███ █ █ █ ██ █ ████ ████ █ █
█ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █
█ █ █ █ █ █ █ █ █ █
███ █ █ █ █ █ █ █ █
█ █ █ █ █ █
███ █ ███ ███ █ ███