RuntimeWarning: при делении обнаружено недопустимое значение

96

Мне нужно написать программу по методу Эйлера для модели "мяч в пружине".

from pylab import*
from math import*
m=0.1
Lo=1
tt=30
k=200
t=20
g=9.81
dt=0.01
n=int((ceil(t/dt)))
km=k/m
r0=[-5,5*sqrt(3)]
v0=[-5,5*sqrt(3)]
a=zeros((n,2))
r=zeros((n,2))
v=zeros((n,2))
t=zeros((n,2))
r[1,:]=r0
v[1,:]=v0
for i in range(n-1):
    rr=dot(r[i,:],r[i,:])**0.5
    a=-g+km*cos(tt)*(rr-L0)*r[i,:]/rr
    v[i+1,:]=v[i,:]+a*dt
    r[i+1,:]=r[i,:]+v[i+1,:]*dt
    t[i+1]=t[i]+dt

    #print norm(r[i,:])

plot(r[:,0],r[:,1])
xlim(-100,100)
ylim(-100,100)
xlabel('x [m]')
ylabel('y [m]')

show()

Я все время получаю эту ошибку:

a=-g+km*cos(tt)*(rr-L0)*r[i,:]/rr
RuntimeWarning: invalid value encountered in divide

Не могу понять, что не так с кодом?

Богдан Осыка
источник
напечатайте, что происходит в каждом меньшем элементе этой строки кода. Это единственный способ отладить его.
CppLearner
2
У вас есть nans for rr, которое вызывает эту ошибку. Проблема rrзаключается в том, r[i,:]что в некоторых случаях равно array([ nan, nan]). Как упоминал @CppLearner, лучший способ отладки (или написания) кода - это проверить каждую меньшую часть перед реализацией.
Cosmosis

Ответы:

161

Я думаю, ваш код пытается «разделить на ноль» или «разделить на NaN». Если вы знаете об этом и не хотите, чтобы это вас беспокоило, вы можете попробовать:

import numpy as np
np.seterr(divide='ignore', invalid='ignore')

Подробнее см .:

Ян Чжу
источник
76
Это может быть полезно, with NP.errstate(divide='ignore',invalid='ignore'):если вы хотите подавить предупреждения для блока кода.
GWW
8
Зачем игнорировать деление на ноль или NaN?
x в квадрате
7
@xsquared Когда вы сами правильно обработали значение после разделения и распространяете свой код среди пользователей (или устали видеть предупреждение). with np.errstate(...)позволяет сделать это безопасно только для обработанного случая.
Reve_etrange
2
@reve_etrange Это гораздо более приемлемо, чем игнорирование деления на ноль.
x в квадрате
1
лучше установить это перед строкой, которая вызывает ошибку, а затем сбросить после строки до нормального состояния с 'warn'помощью командыnp.seterr(divide='warn', invalid='warn')
Mohammad ElNesr
15

Индексация Python начинается с 0 (а не с 1), поэтому ваше присвоение «r [1 ,:] = r0» определяет второй (т.е. индекс 1) элемент r и оставляет первый элемент (индекс 0) в виде пары нулей. Первое значение i в вашем цикле for равно 0, поэтому rr получает квадратный корень из скалярного произведения первой записи в r с самим собой (который равен 0), а деление на rr в следующей строке вызывает ошибку.

Кинч
источник
10

Чтобы предотвратить деление на ноль, вы можете предварительно инициализировать выход out, где происходит ошибка div0, например np.where, не обрезать его, поскольку вся строка оценивается независимо от условия.

пример с предварительной инициализацией:

a = np.arange(10).reshape(2,5)
a[1,3] = 0
print(a)    #[[0 1 2 3 4], [5 6 7 0 9]]
a[0]/a[1]   # errors at 3/0
out = np.ones( (5) )  #preinit
np.divide(a[0],a[1], out=out, where=a[1]!=0) #only divide nonzeros else 1
qrtLs
источник
4

Вы делите на rrкоторое может быть 0,0. Проверьте, rrравно ли нулю, и сделайте что-нибудь разумное, кроме использования его в знаменателе.

Crayzeewulf
источник