Не из-за переполнения.Переполнение легко обнаружить, и оно генерирует предупреждение.Проблема заключается в ограничении двойной точности: значимые цифры могут быть потеряны, когда числа очень разных величин сложены, а затем вычтены.Например, (1e20 + 1) - 1e20 == 0
.
Второй результат с двумя отрицательными собственными значениями неверен, поскольку определитель вашей матрицы явно отрицателен: произведение основных диагональных элементов имеет величину 1e15 и доминирует над всеми другими членами в определителе с большойполе.Таким образом, знак детерминанта является знаком этого продукта, который является отрицательным.
Проблема в том, что mat.T
имеет все крошечные записи в первом столбце, намного меньше, чем в других столбцах.При поиске пивота алгоритм может сканировать этот столбец и согласиться с тем, что там найдено.Это не обязательно, как работает .eigvals
, но тот же принцип - алгоритмы числовой линейной алгебры имеют тенденцию исходить из верхнего левого угла, и поэтому лучше избегать небольших записей там.Вот один из способов:
mat1 = np.roll(mat, 1, axis=[0, 1])
print(np.linalg.eigvals(mat1))
print(np.linalg.eigvals(mat1.T))
печать
[-7.00616288e-08 -2.32851854e+07 -1.58978291e+15]
[-2.32851854e+07 -1.58978291e+15 -7.00616288e-08]
, которые являются последовательными.Свертывание обеих осей означает сопряжение mat
матрицей перестановок, которая не меняет собственных значений.Свернутая матрица -
[[-2.32851854e+07 0.00000000e+00 1.80156232e-02]
[ 1.67598654e-10 -7.00616288e-08 -2.79704289e-09]
[ 0.00000000e+00 -3.23676574e+07 -1.58978291e+15]]
, что дает NumPy довольно большое число для начала.
В идеале он бы делал что-то подобное, но никакой (практический) алгоритм не идеален для любой ситуации.