Страницы

Поиск по вопросам

Показаны сообщения с ярлыком sympy. Показать все сообщения
Показаны сообщения с ярлыком sympy. Показать все сообщения

понедельник, 10 февраля 2020 г.

Упрощенное/приближённое представление чисел с плавающей точкой как дробей в SymPy

#python #sympy


Как представить в 8/9 * x или 8 * x/9 с помощью методов sympy след. выражение? Как
показывает пайтон так точнее и самому приятнее смотреть :)

0.888888888888889 * x

    


Ответы

Ответ 1



import sympy x = sympy.Symbol('x') print(sympy.nsimplify(0.888888888888889 * x)) Вывод: 8*x/9 http://docs.sympy.org/0.7.1/modules/simplify/simplify.html#nsimplify

Ответ 2



Вариант без sympy: from fractions import Fraction x = 1000 # лимит точности print(Fraction(1.0616666666666668).limit_denominator(x)) >>> 637/600 # если x == ∞ >>> 396/373 # если x == 400 >>> 241/227 # если x == 300 В sympy точность измеряется в параметре tolerance nsimplify(pi, tolerance=0.01)

воскресенье, 9 февраля 2020 г.

Вычисление кубического корня в sympy

#python_3x #sympy


Код:

a = simplify('x**(1/3)')
print(a.subs(x, -10).evalf())


Вывод:

1.07721734501594 + 1.86579517236206*I


Почему он с мнимой единицей? Есть же корень кубический из отрицательного числа? Или
я что-то забыл? В чём причина?
    


Ответы

Ответ 1



Эта проблема берётся от того, что и стандартно в python, если попытаться вычислить выражение (-10)**(1/3), то получим, как раз то, что у вас и получается. (Так как вычисляется 1/3 приближенно, а для числа 0.333333 никакого истинного корня нет. В документации к cbrt в sympy также явно указано, какой ответ она считает истинным и какой выдаёт, предупреждая что для отрицательных чисел он может отличаться от того, что вы ожидали. Но вместо возведение в степень (1/3) можно использовать функцию real_root() она как раз делает то, что вам нужно: >>> a = simplify('real_root(x, 3)') ... print(a.subs(x, -10).evalf()) −2.15443469003188 более того метод root может возвращать и другие корни. В качестве третьего параметра он берёт номер корня, который следует вернуть: >>>root(-10, 3, 0).evalf() 1.07721734501594+1.86579517236206i >>>root(-10, 3, 1).evalf() −2.15443469003188 >>>root(-10, 3, 2).evalf() 1.07721734501594−1.86579517236206i

Ответ 2



В том, что этих корней среди комплексных чисел три. И это вправду один из них. Полный список: 1.07721734501594 + 1.86579517236206*I # ваш 1.07721734501594 - 1.86579517236206*I # симметричный относительно оси вещественных -2.154434690031884 # то, что вы искали Комплексные корни из вещественных чисел целой степени 3 и более образуют на комплексной плоскости правильный многоугольник, в данном случае это равносторонний треугольник. См. формулу Муавра. Вам нужно ограничиться вещественными результатами. Чтобы получить все результаты, можно решить уравнение y = x**(1/3), если при этом ещё объявить y как вещественное, то комплексные результаты отвалятся. Но может быть решение и получше, которое я не знаю, т. к. с SymPy не работал.

среда, 29 января 2020 г.

Тест производительности “операторы Python” против SymPy и numexpr

#python #python_3x #оптимизация #sympy


Насколько расчеты встроенными операторами Python быстрее, чем расчет по формуле SymPy
и numexpr?
    


Ответы

Ответ 1



Как на счет использования анаболиков numexpr? from itertools import combinations import numpy as np import numexpr as ne lst = list(combinations(range(1, 23), 6)) X = np.array(lst) formula = """(a+b)*c-(d/e)**f""" def std_op(lst): result = [] for i in lst: result.append((i[0]+i[1])*i[2]-(i[3]/i[4])**i[5]) return result def anabolics(X, formula): d = { "a": X[:, 0], "b": X[:, 1], "c": X[:, 2], "d": X[:, 3], "e": X[:, 4], "f": X[:, 5], } return ne.evaluate(formula, d) тесты: In [17]: sum(std_op(lst)) Out[17]: 8083104.010504639 In [18]: anabolics(X, formula).sum() Out[18]: 8083104.01050503 скорость: In [19]: %timeit std_op(lst) 44.1 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) In [20]: %timeit anabolics(X, formula) 590 µs ± 14.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) вывод: numexpr + numpy в ~75 раз быстрее Vanilla Python: In [21]: 44.1*1000 / 590 Out[21]: 74.7457627118644

Ответ 2



Код теста: from itertools import combinations from sympy import symbols lst = list(combinations(range(1, 23), 6)) a, b, c, d, e, f = symbols('a b c d e f') formula = (a+b)*c-(d/e)**f print(formula) def std_op(lst): result = [] for i in lst: result.append((i[0]+i[1])*i[2]-(i[3]/i[4])**i[5]) return result def sympy(lst): result = [] for i in lst: result.append(formula.subs(zip([a, b, c, d, e, f], i)).n()) return result %timeit std_op(lst) result = std_op(lst) print(len(result), result[0], result[-1]) %timeit sympy(lst) result = sympy(lst) print(len(result), result[0], result[-1]) Результат теста: c*(a + b) - (d/e)**f 19.3 ms ± 205 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 74613 8.737856 664.6581501289133 18.4 s ± 81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 74613 8.73785600000000 664.658150128913 Итог: Операторы Python победили с результатом: 19.3 ms против 18.4 s 18 секунд! Таким образом, можно сделать вывод, что SymPy лучше не использовать в виде "калькулятора".

среда, 22 января 2020 г.

Sympy: найти только реальные корни уравнения (мнимые корни - проигнорировать)

#python #python_3x #sympy


Привет всем. Если я хочу решить уравнение с одной переменной, я делаю так:

x = sympy.symbols('x')
ans = sympy.solve(a)#Где а-строка с уравнением


Однако, часто значение такого уравнения имеют вид:

X1=-4 

X2=2 

X3=1 - sqrt(7)*I 

X4=1 + sqrt(7)*I


Но это еще нормально(На самом деле, не совсем, ближе ниже спрошу почему). 
А вот это не нормально:

X1=-1/4 - sqrt(-22/(9*(-95/108 + sqrt(3369)/36)**(1/3)) + 11/12 + 2*(-95/108 + sqrt(3369)/36)**(1/3))/2
- sqrt(-3/(4*sqrt(-22/(9*(-95/108 + sqrt(3369)/36)**(1/3)) + 11/12 + 2*(-95/108 + sqrt(3369)/36)**(1/3)))
- 2*(-95/108 + sqrt(3369)/36)**(1/3) + 11/6 + 22/(9*(-95/108 + sqrt(3369)/36)**(1/3)))/2 


А таких 4 корня...
Так вот, вопросы:
1)В первом примере, в 3 и 4-м корне есть символ I(После *). Что это за символ? Я
думал в сторону мнимой единицы(простите меня, математики). Но мне кажется, что это
не она. Что же это? 
2)Как можно избавиться от всего этого? От всяких I, всяких огромных корней... Можно
ли вывести примерное значение в sympy? 
Спасибо за время, потраченное на чтение поста
    


Ответы

Ответ 1



Попробуйте указать real=True: Все корни: In [10]: from sympy import * In [11]: x = symbols('x') In [12]: solve(Eq(x**4-(x-2)**2, 0), x) Out[12]: [-2, 1, 1/2 - sqrt(7)*I/2, 1/2 + sqrt(7)*I/2] Только реальные: In [13]: x = symbols('x', real=True) In [14]: solve(Eq(x**4-(x-2)**2, 0), x) Out[14]: [-2, 1] Альтернативное решение: # все корни In [23]: solve('x**4-(x-2)**2') Out[23]: [-2, 1, 1/2 - sqrt(7)*I/2, 1/2 + sqrt(7)*I/2] # выбираем только реальные корни In [24]: [r for r in solve('x**4-(x-2)**2') if r.is_real] Out[24]: [-2, 1] PS I - это мнимая единица, т.е. такое число, квадрат которого равен -1

воскресенье, 29 декабря 2019 г.

Упрощение многочлена (скобки без вложенности)

#математика #любой_язык #sympy #интерполяция


Нахожу многочлен Лагранжа. На выходе получаю выражение вида:

L(x) = - a0(x - x1)(x - x2)(x - x3)(x - x4)(x - x5) + a1(x - x0)(x - x2)(x - x3)(x
- x4)(x - x5) - ... - a5(x - x0)(x - x1)(x - x2)(x - x3)(x - x4)

Необходимо привести к каноническому виду:

L(x) = A0 * x5 + ... + A4 * x + A5

Необходимо реализовать это программно. 

В связи с чем вопрос: есть ли где готовые реализации подобного кода? На любом языке.
Мне бы посмотреть разобраться.  

Уверен, что задача легко решаема, но буду рад любой реализации. Преподаватель внезапно
решил, что ручной вариант его не устраивает и надо программно, ещё и сроки небольшие,
а голова и без того забита вовсю курсовой. 

UPD: Пролистайте до конца - там есть моя версия готовой программы.
Или нажмите сюда.
    


Ответы

Ответ 1



Для .Net существует библиотека под названием MathNet.Symbolics. Конечно, её возможности намного меньше, чем у SymPy, но с вашей задачей тоже справится без проблем. MathNet.Symbolics написана на F#, но вы также можете её использовать на любом другом языке из семейства .Net. К слову, если вы предпочитаете платформу .NET, то вы можете работать с SymPy при помощи IronPython Мне не очень нравится идея вручную задавать выражение, поэтому для удобства я написал простую функцию для его генерации let test n = let y = sprintf "A%i" let l i n = seq { for j in 0..n - 1 do if j <> i then yield sprintf "(x - x%i)" j } let p i = let y' = y i l i n |> String.concat "*" |> sprintf "%s*%s" y' Array.init n p |> String.concat "+" open MathNet.Symbolics let n = 4 let some = test n printfn "%s" some //A0*(x - x1)*(x - x2)*(x - x3)+A1*(x - x0)*(x - x2)*(x - x3)+ //A2*(x - x0)*(x - x1)*(x - x3)+A3*(x - x0)*(x - x1)*(x - x2) let expr = some |> Infix.parseOrUndefined let exp = expr |> Algebraic.expand exp |> Infix.format |> printfn "%s" (* A0*x^3 + A1*x^3 + A2*x^3 + A3*x^3 - A1*x^2*x0 - A2*x^2*x0 - A3*x^2*x0 - A0*x^2*x1 - A2*x^2*x1 - A3*x^2*x1 + A2*x*x0*x1 + A3*x*x0*x1 - A0*x^2*x2 - A1*x^2*x2 - A3*x^2*x2 + A1*x*x0*x2 + A3*x*x0*x2 + A0*x*x1*x2 + A3*x*x1*x2 - A3*x0*x1*x2 - A0*x^2*x3 - A1*x^2*x3 - A2*x^2*x3 + A1*x*x0*x3 + A2*x*x0*x3 + A0*x*x1*x3 + A2*x*x1*x3 - A2*x0*x1*x3 + A0*x*x2*x3 + A1*x*x2*x3 - A1*x0*x2*x3 - A0*x1*x2*x3 *) Раз уж речь зашла о полиномах Лагранжа приведу пример его вычисления по заданным узлам интерполяции (x, y). В качестве тестовых значений возьмем соответствующие из статьи в вики посвященной интерполяционному многочлену Лагранжа. Функция для создания "шаблонного выражения": let generate n = let y = sprintf "y%i" let l i n = seq { for j in 0..n - 1 do if j <> i then yield sprintf "(x - x%i)/(x%i - x%i)" j i j } let p i = l i n |> String.concat "*" |> sprintf "%s*%s" <| y i Array.init n p |> String.concat "+" задаем значения в виде словаря let maps = [ "x0", -1.5; "x1", -0.75; "x2", 0.0; "x3",0.75; "x4",1.5 "y0", -14.1014; "y1",-0.931596;"y2", 0.0;"y3",0.931596; "y4",14.1014 ] |> Map.ofList Заменяем переменные на значения пробегая по словарю let poly = maps |> Map.fold (fun (acc : string) key value -> acc.Replace(key, string value)) (generate n) Преобразуем в выражение и переведем в более читабельный вид: let ex = poly |> Infix.parseOrUndefined ex |> Algebraic.expand |> Infix.format |> printfn "%s" В результате получим следующее выражение: (-1.47747377777778)*x + 4.83484760493827*x^3 Если у вас возникнут какие-либо вопросы связанные с F# или с библиотекой MathNet.Symbolics не стесняйтесь спрашивать. Для удобства можете пинговать меня в F# чате на SO.

Ответ 2



Python + sympy import sympy x = sympy.Symbol('x') xn = sympy.symarray('x', 3) # от x_0 до x_2 an = sympy.symarray('a', 3) # от a_0 до a_2 F = an[0]*(x-xn[0])*(x-xn[1])*(x-xn[2])+an[1]*(x-xn[0])*(x-xn[1])*(x-xn[2])+an[2]*(x-xn[0])*(x-xn[1])*(x-xn[2]) print(F.as_poly()) Результат: Poly(x**3*a_0 + x**3*a_1 + x**3*a_2 - x**2*a_0*x_0 - x**2*a_0*x_1 - x**2*a_0*x_2 - x**2*a_1*x_0 - x**2*a_1*x_1 - x**2*a_1*x_2 - x**2*a_2*x_0 - x**2*a_2*x_1 - x**2*a_2*x_2 + x*a_0*x_0*x_1 + x*a_0*x_0*x_2 + x*a_0*x_1*x_2 + x*a_1*x_0*x_1 + x*a_1*x_0*x_2 + x*a_1*x_1*x_2 + x*a_2*x_0*x_1 + x*a_2*x_0*x_2 + x*a_2*x_1*x_2 - a_0*x_0*x_1*x_2 - a_1*x_0*x_1*x_2 - a_2*x_0*x_1*x_2, x, a_0, a_1, a_2, x_0, x_1, x_2, domain='ZZ')

Ответ 3



Рассмотрим (на примере PHP), как можно добиться результата без подключения внешних библиотек. Полином Лагранжа представляет собой сумму частичных полиномов Lk(x), каждый из которых обращается в нуль во всех узлах, кроме узла с индексом k. Коэффициенты ak при частичных полиномах принято записывать в виде отношения yk / Pk(xk), причём yk - значение полинома в этом узле. Коэффициентами каждого из частичных полиномов Лагранжа являются значения симметрических полиномов в узлах, для вычисления которых можно написать короткую рекурсивную функцию get_symm($ar, $k). В дальнейшей работе можно опираться на функцию poly($ar, $factor), в которой обработка одномерного массива $ar зависит от типа параметра $factor: Если это число с плавающей точкой, то массив $ar на него умножается. Если это такой же одномерный массив, то элементы этих массивов перемножаются. Если $factor - это двумерный массив с той же "внешней" размерностью, что и массив $ar, то вычисляется линейная комбинация его одномерных массивов, коэффициенты которой берутся из массива $ar. Если $factor - это целое число, то вычисляются коэффициенты частичного полинома Лагранжа с таким индексом. А если $factor - строка, то она задаёт функцию над массивом $ar. Реализованы следующие функции: 'symmetric'. Вычисление массива значений всех возможных симметрических полиномов, образуемых числами массива $ar. 'denominators'. Вычисление массива из всех знаменателей Pk(xk). 'degrees'. Вычисление квадратной матрицы, образованной степенями точек массива. 'reduced'. Вычисление коэффициентов полинома по его корням. Пользовательская функция над массивом $ar, заданная вне функции poly(). Перечень опций с примерами выводится в начале работы программы. Такой подход, помимо решения и тестирования поставленной задачи, даёт удобный инструмент для расширения функциональности (интегрирование и дифференцирование полиномов, представление данных и т.д.). Программа на PHP: $points = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]; $coeffs = [-8.68, 83.44, -291.93, 398.63, -196.79, 26.04]; function print_m($text, $arr, $level=0){ $space = str_repeat(" ", $level++); echo "$space$text"; if(gettype($arr)!="array"){ var_dump($arr); return; } $flag = false; foreach($arr as $value) $flag = $flag || (gettype($value)=="array"); foreach($arr as $key => $value) { if(gettype($value) != "array") { echo $flag ? "
$key => $value" : " $value"; } else { print_m("
$space$key => [", $value, $level); echo " ]"; } } $level--; } function get_symm($arr, $k){ // $k-th symmetric polynomial of $arr if($k==1) return array_sum($arr); $el = array_shift($arr); // Shifting of the first value from array $cnt = count($arr); return ($cnt == 1) ? ($el*end($arr)): ($cnt == $k-1) ? ($el*get_symm($arr, $k-1)): $el * get_symm($arr, $k-1) + (get_symm($arr, $k)); } function squares($a){ return $a * $a; } function round8($a){ return round($a, 8); } function poly($ar, $factor = ""){ switch (gettype($factor)) { case 'float': case 'double': // factoring return array_map(function($val)use($factor){ return $val * $factor;}, $ar); case 'array': if(!is_array(end($factor))){ // arrays factoring return array_map(function($a, $b){return $a * $b;}, $ar, $factor); } else { // weighted sum of $factor $sum = array_fill(0, count($ar), 0.0); // sum initialization array_map(function($a, $ff)use(&$sum){ $f = poly($ff, $a); // array factoring array_walk($f, function($val, $key)use(&$sum){$sum[$key] += $val;}); // summation }, $ar, $factor); return $sum; } case 'integer': // k-th Lagrange polynomial by roots unset($ar[$factor]); return poly($ar, 'reduced'); case 'string': switch ($factor) { case 'symmetric': // all symmetric polynomials's values return array_map(function($a)use($ar){return get_symm($ar, $a);}, range(1,count($ar))); case 'denominators': $prod = []; // prod initialization array_walk($ar, function($value, $key)use($ar, &$prod){ $p = 1; array_walk($ar, function($val, $k)use($value, $key, &$p){ if($k != $key) $p *= $value - $val; }); $prod[] = $p; }); return $prod; case 'degrees': // degrees in accordance with the point quantity $cnt = count($ar); $degree = array_fill(0, $cnt, 1.0); $degrees = [$degree]; while(count($degrees) < $cnt) $degrees[] = ($degree = poly($degree, $ar)); return $degrees; case 'reduced': // all reduced polynomial's coefficients by roots return array_merge(array_reverse(poly(poly($ar, -1.0),"symmetric")),[1.0]); default: return array_map($factor, $ar); } default: return $arr; } } $test = [1.0, 2.0, 3.0, 4.0]; $results[] = ["Testing points (in float point form) are: \$test " => $test]; $results[] = ["Array's factoring: poly(\$test, 5.0) " => poly($test, 5.0)]; $results[] = ["Multiplying to 1d array:  poly(\$test, array_reverse(\$test)) " => poly($test, array_reverse($test))]; $results[] = ["Symmetric polynomials calculation:  poly(\$test, 'symmetric') " => poly($test, 'symmetric')]; $results[] = ["Lagrange denominators calculation:  poly(\$test, 'denominators') " => poly($test, 'denominators')]; $results[] = ["Square matrix of degrees:   \$degrees = poly(\$test, 'degrees')
" => $degrees = poly($test, 'degrees')]; $results[] = ["2d array weighting via scalar production:   poly(\$test, \$degrees)" => poly($test, $degrees)]; $results[] = ["Reduced polynomials via its roots:  poly(\$test, 'reduced') " => poly($test, 'reduced')]; $results[] = ["User function appying:  poly(\$test, 'squares') " => poly($test, 'squares')]; foreach ($test as $key => $value) { $results[] = ["Lagrange partial polynomials:  poly(\$test, $key) " => poly($test, $key)]; } print_m("Poly Functions Description:
", $results); $symp[] = ["Lagrange Polynomial's Nodes " => $points]; $symp[] = ["Lagrange Partial Polynomials' Coefficients " => $coeffs]; $parts = []; foreach ($points as $key =>$value){ $part = poly($points, $key); $parts[] = $part; $symp[] = ["Lagrange Partial Polynomial \#$key " => $part]; } $lagrange = poly($coeffs, $parts); $symp[] = ["Lagrange Polynomial's Coefficients " => poly($lagrange, 'round8')]; print_m("

Lagrange Polynomial Symplifying:
", $symp); $denoms = poly($points, 'denominators'); $checking[] = ["Lagrange Denominators " => $denoms]; $values = poly(poly($coeffs, $denoms), 'round8'); $checking[] = ["Polynomial's Values In The Nodes Via Denominators" => $values]; $degrees = poly($points, 'degrees'); $checking[] = ["Degrees of issue Points " => $degrees]; $values2 = poly(poly($lagrange, $degrees), 'round8'); $checking[] = ["Polynomial's Values In The Nodes Via Symplified Polinomial" => $values2]; print_m("

Checking:
", $checking); Результаты: Poly Functions Description:   0 => [    Testing points (in float point form) are: $test => [ 1 2 3 4 ] ]  1 => [    Array's factoring: poly($test, 5.0) => [ 5 10 15 20 ] ]  2 => [    Multiplying to 1d array:  poly($test, array_reverse($test)) => [ 4 6 6 4 ] ]  3 => [    Symmetric polynomials calculation:  poly($test, 'symmetric') => [ 10 35 50 24 ] ]  4 => [    Lagrange denominators calculation:  poly($test, 'denominators') => [ -6 2 -2 6 ] ]  5 => [    Square matrix of degrees:   $degrees = poly($test, 'degrees') => [      0 => [ 1 1 1 1 ]      1 => [ 1 2 3 4 ]      2 => [ 1 4 9 16 ]      3 => [ 1 8 27 64 ] ] ]  6 => [    2d array weighting via scalar production:   poly($test, $degrees) => [ 10 49 142 313 ] ]  7 => [    Reduced polynomials via its roots:  poly($test, 'reduced') => [ 24 -50 35 -10 1 ] ]  8 => [    User function appying:  poly($test, 'squares') => [ 1 4 9 16 ] ]  9 => [    Lagrange partial polynomials:  poly($test, 0) => [ -24 26 -9 1 ] ]  10 => [    Lagrange partial polynomials:  poly($test, 1) => [ -12 19 -8 1 ] ]  11 => [    Lagrange partial polynomials:  poly($test, 2) => [ -8 14 -7 1 ] ]  12 => [    Lagrange partial polynomials:  poly($test, 3) => [ -6 11 -6 1 ] ] Lagrange Polynomial Symplifying:   0 => [    Lagrange Polynomial's Nodes => [ 0 0.2 0.4 0.6 0.8 1 ] ]  1 => [    Lagrange Partial Polynomials' Coefficients => [ -8.68 83.44 -291.93 398.63 -196.79 26.04 ] ]  2 => [    Lagrange Partial Polynomial \#0 => [ -0.0384 0.4384 -1.8 3.4 -3 1 ] ]  3 => [    Lagrange Partial Polynomial \#1 => [ -0 0.192 -1.232 2.84 -2.8 1 ] ]  4 => [    Lagrange Partial Polynomial \#2 => [ -0 0.096 -0.856 2.36 -2.6 1 ] ]  5 => [    Lagrange Partial Polynomial \#3 => [ -0 0.064 -0.624 1.96 -2.4 1 ] ]  6 => [    Lagrange Partial Polynomial \#4 => [ -0 0.048 -0.488 1.64 -2.2 1 ] ]  7 => [    Lagrange Partial Polynomial \#5 => [ -0 0.0384 -0.4 1.4 -2 1 ] ]  8 => [    Lagrange Polynomial's Coefficients => [ 0.333312 1.256224 -0.4096 13.538 -24.428 10.71 ] ] Checking:   0 => [    Lagrange Denominators => [ -0.0384 0.00768 -0.00384 0.00384 -0.00768 0.0384 ] ]  1 => [    Polynomial's Values In The Nodes Via Denominators => [ 0.333312 0.6408192 1.1210112 1.5307392 1.5113472 0.999936 ] ]  2 => [    Degrees of issue Points => [      0 => [ 1 1 1 1 1 1 ]      1 => [ 0 0.2 0.4 0.6 0.8 1 ]      2 => [ 0 0.04 0.16 0.36 0.64 1 ]      3 => [ 0 0.008 0.064 0.216 0.512 1 ]      4 => [ 0 0.0016 0.0256 0.1296 0.4096 1 ]      5 => [ 0 0.00032 0.01024 0.07776 0.32768 1 ] ] ]  3 => [    Polynomial's Values In The Nodes Via Symplified Polinomial => [ 0.333312 0.6408192 1.1210112 1.5307392 1.5113472 0.999936 ] ]

Ответ 4



Спасибо всем за помощь. Особенно @FoggyFinder и @insolor. Выкладываю завершённый и рабочий вариант. Программа по узлам и заданной функции (double f(double x){}) составляет многочлен Лагранжа, приводит его к каноническому виду и вычисляет определённый интеграл (работает, только для числовых значений). using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MathNet.Symbolics; namespace Polynom { class Program { static void Main(string[] args) { double[] x = { 0, 0.2, 0.4, 0.6, 0.8, 1.0 }; // n - определяется как количество узлов минус один. //double[] x = { -1.5, -0.75, 0, 0.75, 1.5 }; double[] coef = GetCoefLagrange(x); string exp = GetPolynom(coef, x); string simpExp = SimplifyPolynom(exp); var defInt = GetDefInt(GetSimplifyCoef(simpExp), 0, 1); Console.WriteLine("Многочлен Лагранжа:"); Console.WriteLine(exp); Console.WriteLine("---------------------"); Console.WriteLine("Канонический вид:"); Console.WriteLine(simpExp); Console.WriteLine("---------------------"); Console.WriteLine("Определённый интеграл от 0 до 1:"); Console.WriteLine(defInt); Console.ReadLine(); } static double f(double x) { //return x * x * x * x; //return Math.Tan(x); return Math.Exp(Math.Pow(x, 1 / 3) * Math.Sin(Math.PI * x)) / (2 + Math.Cos(Math.PI * x)); } static double[] GetCoefLagrange(double[] x) { int n = x.Length - 1; double[] a = new double[n + 1]; for (int i = 0; i < n + 1; i++) { double den = 1; for (int j = 0; j < n + 1; j++) { if (i != j) { den *= (x[i] - x[j]); } } a[i] = f(x[i]) / den; } return a; } static string GetPolynom(double[] a, double[] x) { string exp = ""; int n = x.Length - 1; var culture = System.Globalization.CultureInfo.InvariantCulture; for (int i = 0; i < n + 1; i++) { if (a[i] < 0) { exp += "("; } exp += a[i].ToString(culture); if (a[i] < 0) { exp += ")"; } for (int j = 0; j < n + 1; j++) { if (j != i) { exp += "*(x - "; if (x[j] < 0) { exp += "("; } exp += x[j].ToString(culture); if (x[j] < 0) { exp += ")"; } exp += ")"; } } if (i != n) { exp += " + "; } } return exp; } static string SimplifyPolynom(string exp) { return Infix.Format(Algebraic.Expand(Infix.ParseOrUndefined(exp))); } static double[] GetSimplifyCoef(string exp) { string[] membr = exp.Split(" + ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); double[] coef = new double[membr.Count() + 1]; for (int i = 0; i < membr.Count(); i++) { string str = membr[i].Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[0].Replace('.', ','); string xPow = (membr[i].Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Length > 1)? membr[i].Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)[1] : ""; int pow = 0; if (!xPow.Contains('x')) { pow = 0; } if (xPow == "x") { pow = 1; } if (xPow.Contains('x') && xPow != "x") { pow = int.Parse(xPow[xPow.Length - 1].ToString()); } if (str.Contains("(")) { str = str.Substring(1, str.Length - 2); coef[pow] = Math.Round(double.Parse(str), 2); } else { coef[pow] = Math.Round(double.Parse(str), 2); } pow++; } return coef; } static double GetDefInt(double[] A, double from, double to) { string str = ""; var culture = System.Globalization.CultureInfo.InvariantCulture; for (int i = 0; i < A.Count(); i++) { str += (A[i] / (i + 1)).ToString(culture) + "*x^" + (i + 1); if (i != A.Count() - 1) { str += " + "; } } var exp = Infix.ParseOrUndefined(str); var x = new Dictionary { { "x", 0.0 } }; var resFrom = Evaluate.Evaluate(x, exp); x = new Dictionary { { "x", 1.0 } }; var resTo = Evaluate.Evaluate(x, exp).RealValue; return resTo - resFrom.RealValue; } } } Вывод консоли: Многочлен Лагранжа: (-8.68055555555555)*(x - 0.2)*(x - 0.4)*(x - 0.6)*(x - 0.8)*(x - 1) + 83.4365435984129*(x - 0)*(x - 0.4)*(x - 0.6)*(x - 0.8)*(x - 1) + (-291.931019062828)*(x - 0)*(x - 0.2)*(x - 0.6)*(x - 0.8)*(x - 1) + 398.628301975219*(x - 0)*(x - 0.2)*(x - 0.4)*(x - 0.8)*(x - 1) + (-196.79094312252)*(x - 0)*(x - 0.2)*(x - 0.4)*(x - 0.6)*(x - 1) + 26.0416666666667*(x - 0)*(x - 0.2)*(x - 0.4)*(x - 0.6)*(x - 0.8) --------------------- Канонический вид: 0.333333333333333 + 1.2551290418413*x + (-0.40261625087755)*x^2 + 13.5213484261595*x^3 + (-24.4111890498517)*x^4 + 10.7039944993951*x^5 --------------------- Определённый интеграл от 0 до 1: 1,108

пятница, 19 апреля 2019 г.

Упрощенное/приближённое представление чисел с плавающей точкой как дробей в SymPy

Как представить в 8/9 * x или 8 * x/9 с помощью методов sympy след. выражение? Как показывает пайтон так точнее и самому приятнее смотреть :)
0.888888888888889 * x


Ответ

import sympy x = sympy.Symbol('x') print(sympy.nsimplify(0.888888888888889 * x))
Вывод: 8*x/9
http://docs.sympy.org/0.7.1/modules/simplify/simplify.html#nsimplify

Вычисление кубического корня в sympy

Код:
a = simplify('x**(1/3)') print(a.subs(x, -10).evalf())
Вывод:
1.07721734501594 + 1.86579517236206*I
Почему он с мнимой единицей? Есть же корень кубический из отрицательного числа? Или я что-то забыл? В чём причина?


Ответ

Эта проблема берётся от того, что и стандартно в python, если попытаться вычислить выражение (-10)**(1/3), то получим, как раз то, что у вас и получается. (Так как вычисляется 1/3 приближенно, а для числа 0.333333 никакого истинного корня нет. В документации к cbrt в sympy также явно указано, какой ответ она считает истинным и какой выдаёт, предупреждая что для отрицательных чисел он может отличаться от того, что вы ожидали.
Но вместо возведение в степень (1/3) можно использовать функцию real_root() она как раз делает то, что вам нужно:
>>> a = simplify('real_root(x, 3)') ... print(a.subs(x, -10).evalf())
−2.15443469003188
более того метод root может возвращать и другие корни. В качестве третьего параметра он берёт номер корня, который следует вернуть:
>>>root(-10, 3, 0).evalf() 1.07721734501594+1.86579517236206i >>>root(-10, 3, 1).evalf() −2.15443469003188 >>>root(-10, 3, 2).evalf() 1.07721734501594−1.86579517236206i

среда, 13 марта 2019 г.

Sympy: найти только реальные корни уравнения (мнимые корни - проигнорировать)

Привет всем. Если я хочу решить уравнение с одной переменной, я делаю так:
x = sympy.symbols('x') ans = sympy.solve(a)#Где а-строка с уравнением
Однако, часто значение такого уравнения имеют вид:
X1=-4
X2=2
X3=1 - sqrt(7)*I
X4=1 + sqrt(7)*I
Но это еще нормально(На самом деле, не совсем, ближе ниже спрошу почему). А вот это не нормально:
X1=-1/4 - sqrt(-22/(9*(-95/108 + sqrt(3369)/36)**(1/3)) + 11/12 + 2*(-95/108 + sqrt(3369)/36)**(1/3))/2 - sqrt(-3/(4*sqrt(-22/(9*(-95/108 + sqrt(3369)/36)**(1/3)) + 11/12 + 2*(-95/108 + sqrt(3369)/36)**(1/3))) - 2*(-95/108 + sqrt(3369)/36)**(1/3) + 11/6 + 22/(9*(-95/108 + sqrt(3369)/36)**(1/3)))/2
А таких 4 корня... Так вот, вопросы: 1)В первом примере, в 3 и 4-м корне есть символ I(После *). Что это за символ? Я думал в сторону мнимой единицы(простите меня, математики). Но мне кажется, что это не она. Что же это? 2)Как можно избавиться от всего этого? От всяких I, всяких огромных корней... Можно ли вывести примерное значение в sympy? Спасибо за время, потраченное на чтение поста


Ответ

Попробуйте указать real=True
Все корни:
In [10]: from sympy import *
In [11]: x = symbols('x')
In [12]: solve(Eq(x**4-(x-2)**2, 0), x) Out[12]: [-2, 1, 1/2 - sqrt(7)*I/2, 1/2 + sqrt(7)*I/2]
Только реальные:
In [13]: x = symbols('x', real=True)
In [14]: solve(Eq(x**4-(x-2)**2, 0), x) Out[14]: [-2, 1]
Альтернативное решение:
# все корни In [23]: solve('x**4-(x-2)**2') Out[23]: [-2, 1, 1/2 - sqrt(7)*I/2, 1/2 + sqrt(7)*I/2]
# выбираем только реальные корни In [24]: [r for r in solve('x**4-(x-2)**2') if r.is_real] Out[24]: [-2, 1]
PS I - это мнимая единица, т.е. такое число, квадрат которого равен -1