Как заставить Python использовать в вычислениях более 15 десятичных знаков?

В этом вопросе я утверждал, что такая конструкция пятиугольников всегда будет сходиться.

Первые 50 итераций я нарисовал с помощью Geogebra здесь. Однако увеличение масштаба на 50-й итерации привело к значительной задержке и неточному рендерингу, что затруднило дальнейшее исследование. Кроме того, ручное кодирование конструкций в GeoGebra занимало много времени (более 6 часов на 50 итераций).

Для расчета пятиугольников мне нужно было использовать другой инструмент, кроме GeoGebra, поэтому я написал этот код на Python:

import math 
# enter your coordinates here
A=[0,0]
B=[0,0]
C=[0,0]
D=[0,0]
E=[0,0]
print("Number of pentagons")
n=int(input() )
print("Enter A_1")
A[0]=float (input() )
A[1]=float (input() )
print("Enter B_1")
B[0]=float (input() )
B[1]=float (input() )
print("Enter C_1")
C[0]=float (input() )
C[1]=float (input() )
print("Enter D_1")
D[0]=float (input() )
D[1]=float (input() )
print("Enter E_1")
E[0]=float (input() )
E[1]=float (input() )
X=[0,0]
Y=[0,0]
Z=[0,0]
W=[0,0]
T=[0,0]


#defining some useful functions
def v(a,b):
    result= [b[0]-a[0], b[1]-a[1]]
    return result 
def crs(a, b):
    result = [-0.5*((a[0]*b[1])-(a[1]*b[0]))]
    return result
def dis(a,b):
    result =[math.sqrt((a[0]-b[0])**2+(a[1]-b[1])**2)]
    return result 




for i in range (2,n+1):
    AB= dis(A,B)[0]
    BC= dis(B,C)[0]
    CD= dis(C,D)[0]
    DE= dis(D,E)[0]
    EA= dis(E,A)[0]



    #Here to calculate A_n
    x=   CD*crs(v(D,C),v(D,E))[0]
    y=  -CD*crs(v(E,D),v(E,B))[0]+  2*DE*crs(v(C,B),v(C,D))[0]
    z=  -CD*crs(v(C,B),v(C,E))[0]+  2*BC*crs(v(D,C),v(D,E))[0]
    t=   CD*crs(v(C,B),v(C,D))[0]
    X[0]=(x *B[0]+y*C[0]+z*D[0]+t*E[0])/(x+y+z+t)
    X[1]=(x *B[1]+y*C[1]+z*D[1]+t*E[1])/(x+y+z+t)



    #Here to calculate B_n
    x=   DE*crs(v(E,D),v(E,A))[0]
    y=  -DE*crs(v(A,E),v(A,C))[0]+  2*EA*crs(v(D,C),v(D,E))[0]
    z=  -DE*crs(v(D,C),v(D,A))[0]+  2*CD*crs(v(E,D),v(E,A))[0]
    t=   DE*crs(v(D,C),v(D,E))[0]
    Y[0]=(x *C[0]+y*D[0]+z*E[0]+t*A[0])/(x+y+z+t)
    Y[1]=(x *C[1]+y*D[1]+z*E[1]+t*A[1])/(x+y+z+t)



    #Here to calculate C_n
    x=   EA*crs(v(A,E),v(A,B))[0]
    y=  -EA*crs(v(B,A),v(B,D))[0]+  2*AB*crs(v(E,D),v(E,A))[0]
    z=  -EA*crs(v(E,D),v(E,B))[0]+  2*DE*crs(v(A,E),v(A,B))[0]
    t=   EA*crs(v(E,D),v(E,A))[0]
    Z[0]=(x *D[0]+y*E[0]+z*A[0]+t*B[0])/(x+y+z+t)
    Z[1]=(x *D[1]+y*E[1]+z*A[1]+t*B[1])/(x+y+z+t)



    #Here to calculate D_n
    x=   AB*crs(v(B,A),v(B,C))[0]
    y=  -AB*crs(v(C,B),v(C,E))[0]+  2*BC*crs(v(A,E),v(A,B))[0]
    z=  -AB*crs(v(A,E),v(A,C))[0]+  2*EA*crs(v(B,A),v(B,C))[0]
    t=   AB*crs(v(A,E),v(A,B))[0]
    W[0]=(x *E[0]+y*A[0]+z*B[0]+t*C[0])/(x+y+z+t)
    W[1]=(x *E[1]+y*A[1]+z*B[1]+t*C[1])/(x+y+z+t)



    #Here to calculate E_n
    x=   BC*crs(v(C,B),v(C,D))[0]
    y=  -BC*crs(v(D,C),v(D,A))[0]+  2*CD*crs(v(B,A),v(B,C))[0]
    z=  -BC*crs(v(B,A),v(B,D))[0]+  2*AB*crs(v(C,B),v(C,D))[0]
    t=   BC*crs(v(B,A),v(B,C))[0]
    T[0]=(x *A[0]+y*B[0]+z*C[0]+t*D[0])/(x+y+z+t)
    T[1]=(x *A[1]+y*B[1]+z*C[1]+t*D[1])/(x+y+z+t)
    A=X
    B=Y
    C=Z
    D=W
    E=T

    
    print(f"A_{i}= {A}")
    print(f"B_{i}= {B}")
    print(f"C_{i}= {C}")
    print(f"D_{i}= {D}")
    print(f"E_{i}= {E}")  

Проблема в том, что примерно через 20 или 30 итераций Python выдал мне эту ошибку:

ZeroDivisionError: деление с плавающей запятой на ноль.

Я подумал, что это связано с тем, что после 20-30 итераций первые 15 цифр будут одинаковыми, поэтому мне нужно, чтобы Python использовал во всех этих вычислениях более 50 десятичных знаков.

Я пытался найти в Google «как заставить Python использовать больше десятичных знаков». Я попробовал несколько решений, но ни одно из них мне не помогло (я новичок в программировании).

Вы пробовали это, geeksforgeeks.org/python-k-length-decimal-places ?

Linux 05.07.2024 13:04

В зависимости от ваших потребностей вы можете использовать fractions.Fraction, который поддерживает точные доли произвольной точности. Вы также можете использовать decimal.Decimal, но в этом случае вам нужно будет указать желаемую точность.

Tom Karzes 05.07.2024 13:06

@InSync Это не сработало, или, по крайней мере, я не понимаю, как использовать это для своего кода.

pie 05.07.2024 14:54
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

HВстроенный пакет decimal обеспечивает именно эту поддержку. Простой пример, адаптированный из документации:

>>> from decimal import Decimal
>>> import decimal
>>> decimal.getcontext().prec
28
>>> Decimal(1)/7
Decimal('0.1428571428571428571428571429')
>>> decimal.getcontext().prec = 6
>>> Decimal(1)/7
Decimal('0.142857')

Однако вам нужно будет адаптировать свою библиотеку к номерам ящиков с помощью Decimal. Для использования библиотеки также необходимо изменить операции:

math.sqrt(x)

становится

x.sqrt()

если предположить, что x было записано в десятичной системе счисления.

Если вы используете Numpy, что всегда хорошо для векторизованных реализаций, вы не можете выбирать произвольную точность, но есть более точные типы данных:

https://numpy.org/doc/stable/user/basics.types.html#relationship-between-numpy-data-types-and-c-data-data-types

например

https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.longdouble (np.float128)

Хотя это не так хорошо, как произвольная точность, здесь используется точность, поддерживаемая платформой, поэтому вычисления выполняются очень быстро.

Можете ли вы объяснить больше, как использовать десятичный пакет? Я новичок и едва могу понять ваш ответ.

pie 05.07.2024 14:18

@pie для вашего примера, просто окружающий начальный ввод, вероятно, поможет, т. е. Decimal(float(input())) , Decimal(0)`. Остальные операции должны работать естественно.

kabanus 05.07.2024 16:01

Да, и операции math.sqrt должны быть изменены на десятичную версию, которую я добавлю в ответ.

kabanus 05.07.2024 16:06

Это сработало!! но ответ напечатает [Decimal('x'), Decimal('y')] есть ли способ удалить это?

pie 05.07.2024 17:30

@pie, в этом-то и дело: Python не может использовать обычное число с плавающей запятой. Да, потому что тогда вы потеряете точность. Здесь два варианта: 1. str(result) — вы получаете полную точность, но у вас есть строка, поэтому никаких вычислений с ней больше не требуется. 2. float(result) — ваш результат обрезается, чего, я думаю, вам не хочется. Если у вас есть итерируемый объект (например, список), [str(x) for x in result] подойдет. Я рекомендую вам прочитать связанную документацию, чтобы узнать, есть ли какие-либо методы, которые могут быть вам полезны.

kabanus 05.07.2024 20:44

Другие вопросы по теме