【问题标题】:How can I get the exact result of 10**20 + 10**-20 in Python? It gives me 1e+20如何在 Python 中获得 10**20 + 10**-20 的确切结果?它给了我 1e+20
【发布时间】:2019-10-01 17:15:13
【问题描述】:

我正在编写一个代码来解决二年级方程,它运行得很好。 但是,当我输入以下等式时:

x^2 + (10^(20) + 10^(-20)) + 1 = 0

(是的,我的输入是 10**20 + 10**(-20)
我明白了:

x1 = 0
x2 = -1e+20

但是,如果您进行数学运算,则将 (10^(20) + 10^(-20) 视为 10e+20:

这是 LaTeX 格式的公式:

几乎是 10^20 但不是 10^20。
如何获得该操作的确切结果,以便获得 x2 中方程的确切值?

我的代码如下:

#===============================Función para obtener los coeficientes===============================

#Se van a anidar dos funciones. Primero la de coeficientes, luego la de la solución de la ecuación.
#Se define una función recursiva para obtener los coeficientes de la ecuación del usuario
def cof():
  #Se determina si el coeficiente a introducir es un número o una cadena de operaciones
  op = input("Si tu coeficiente es un número introduce 1, si es una cadena de operaciones introduce 2")
  #Se compara la entrada del usuario con la opción.
  if op == str(1):
    #Se le solicita el número
    num = input("¿Cuál es tu número?")
    #Se comprueba que efectívamente sea un número
    try:
      #Si la entrada se puede convertir a flotante
      float(num)
      #Se establece el coeficiente como el valor flotante de la entrada
      coef = float(num)
      #Se retorna el valor del coeficiente
      return coef
    #Si no se pudo convertir a flotante...
    except ValueError:
      #Se le informa al usuario del error
      print("No introdujiste un número. Inténtalo de nuevo")
      #Se llama a la función de nuevo
      return cofa()
  #Si el coeficiente es una cadena (como en 10**20 + 10**-20)
  elif op == str(2):
    #La entrada se establece como la entrada del usuario
    entrada = input("Input")
    #Se intenta...
    try:
      #Evaluar la entrada. Si se puede...
      eval(entrada)
      #El coeficiente se establece como la evaluación de la entrada
      coef = eval(entrada)
      #Se regresa el coeficiente
      return coef
    #Si no se pudo establecer como tal...
    except:
      #Se le informa al usuario
      print("No introdujiste una cadena de operaciones válida. Inténtalo de nuevo")
      #Se llama a la función de nuevo
      return cofa()
  #Si no se introdujo ni 1 ni 2 se le informa al usuario
  else:
    #Se imprime el mensaje
    print("No introdujiste n ni c, inténtalo de nuevo")
    #Se llama a la función de nuevo
    return cof()

#===============================Función para resolver la ecuación===============================
#Resuelve la ecuación
def sol_cuadratica():

  #Se pide el valor de a
  print("Introduce el coeficiente para a")
  #Se llama a cof y se guarda el valor para a
  a = cof()
  #Se pide b
  print("Introduce el coeficiente para b")
  #Se llama cof y se guarda b
  b = cof()
  #Se pide c
  print("Introduce el coeficiente para c")
  #Se llama cof y se guarda c
  c = cof()
  #Se le informa al usuario de la ecuación a resolver
  print("Vamos a encontrar las raices de la ecuación {}x² + {}x + {} = 0".format(a, b, c))
  #Se analiza el discriminante
  discriminante = (b**2 - 4*a*c)
  #Si el discriminante es menor que cero, las raices son complejas
  if discriminante < 0:
    #Se le informa al usuario
    print("Las raices son imaginarias. Prueba con otros coeficientes.")
    #Se llama a la función de nuevo
    return sol_cuadratica()
  #Si el discriminante es 0, o mayor que cero, se procede a resolver
  else:   
    #Ecuación para x1
    x1 = (-b + discriminante**(1/2))/(2*a)
    #Ecuación para x2
    x2 = (-b - discriminante**(1/2))/(2*a)
    #Se imprimen los resultados
    print("X1 = " + str(x1))
    print("X2 = " + str(x2))

sol_cuadratica()

忽略cmets,我来自西班牙语国家。

【问题讨论】:

  • 你的python实现显示多少位有效数字(不是小数位)?
  • 浮点数吸收/取消是原因。
  • 这很可能是由于在计算机上进行浮点运算的固有限制。我建议你安装mpmath 模块来解决这个问题。您可以通过pypi 获取它。
  • @Igor:我建议你把代码放到Google Translate——它通常做得很好(即使是在代码上)。

标签: python math equation exponent largenumber


【解决方案1】:

机器浮点类型的限制是为什么在将一个非常小的数字添加到一个非常大的数字时,小数字会被忽略。

这种现象称为吸收或抵消。

使用自定义浮点对象(如 decimal 模块),您可以实现任何精度(计算速度较慢,因为浮点现在已模拟,并且不再依赖机器 FPU 功能)

来自decimal module docs

与基于硬件的二进制浮点不同,十进制模块具有用户可更改的精度(默认为 28 位),可以根据给定问题的需要进行调整

这可以通过更改以下全局参数decimal.getcontext().prec来实现

import decimal
decimal.getcontext().prec = 41  # min value for the required range

d = decimal.Decimal(10**20)
d2 = decimal.Decimal(10**-20)

现在

>>> d+d2
Decimal('100000000000000000000.00000000000000000001')

正如 cmets 中所建议的,对于少数人来说,让decimal 模块通过对已经存在的Decimal 对象使用幂运算符来处理除法会更安全(即使在这里,结果也是一样的):

d2 = decimal.Decimal(10)**-20

因此,您可以使用 decimal.Decimal 对象代替原生浮点数进行计算。

【讨论】:

  • 另一个选项是 fraction.Fraction 对象,尽管这些对象在保持精度的同时不能平方根
  • 还有其他选择,真的。我只提出了我知道的选项。还有其他答案的空间。
  • 非常感谢您的回答!
  • 小心decimal.Decimal(10**-20),它有可能通过中间浮点数丢失精度。 decimal.Decimal(10)**-20 会更安全。
猜你喜欢
  • 2023-01-13
  • 2013-11-21
  • 2019-02-14
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 2019-06-15
  • 1970-01-01
相关资源
最近更新 更多