у меня есть c++ код, который считает кубический сп...
Создано: 28 мая 2025 г.
Создано: 28 мая 2025 г.
у меня есть c++ код, который считает кубический сплайн для трех разных задач и записывает результаты в 3 разные файла. Мне надо написать питон код, который будет считывать данные из файлов spline1_output.txt,function1_values.txt и function1_derivatives.txt восстанавливать сплайн используя индексацию xi-1 и xi. Затем на первом графике должны быть график функции, x^3+3x^2 на отрезке x от -1 до 0 и -x^3+3x^2 на отрезке от 0 до 1. Для второго графика необходимо взять столбик Fj-Sj и нарисовать эту линию, это разница сплайна и функции. На третьем графике должны быть первые производные F'j и S'j. На четвертом графике F'j-S'j. На пятом должны быть вторые производные F''j и S''j. На шестом F''j-S''j.
Умести все графики в одно окно. Также я хочу в будущем изменить питон код чтобы использовать его для других функций. Напиши мне потом какие строчки надо поменять чтобы этот же код работал с другими файлами. Вот c++ код
#include <iostream>
#include <vector>
#include <fstream>
#include <cmath>
#include <iomanip>
#include <algorithm> // std::max
using namespace std;
struct SplineSegment {
double xi; // левый узел сегмента [x_{i-1}, x_i]
double a, b, c, d; // «левые» коэффициенты
};
// ─────────── функции и их производные ───────────
double f1(double x) { return (x <= 0) ? x * x * x + 3 * x * x : -x * x * x + 3 * x * x; }
double f1p(double x) { return (x <= 0) ? 3 * x * x + 6 * x : -3 * x * x + 6 * x; }
double f1pp(double x) { return (x <= 0) ? 6 * x + 6 : -6 * x + 6; }
double f2(double x) { return log(x + 1) / (x + 1); }
double f2p(double x) { return (1 - log(x + 1)) / ((x + 1) * (x + 1)); }
double f2pp(double x) { return (2 * log(x + 1) - 3) / ((x + 1) * (x + 1) * (x + 1)); }
double f3(double x) { return log(x + 1) / (x + 1) + cos(10 * x); }
double f3p(double x) { return (1 - log(x + 1)) / ((x + 1) * (x + 1)) - 10 * sin(10 * x); }
double f3pp(double x) { return (2 * log(x + 1) - 3) / ((x + 1) * (x + 1) * (x + 1)) - 100 * cos(10 * x); }
// ─────────── построение сплайна ───────────
vector<SplineSegment> cubic_spline(const vector<double>& x,
const vector<double>& y)
{
const int n = static_cast<int>(x.size()) - 1;
vector<double> h(n), alfa(n), l(n + 1), mu(n + 1), z(n + 1);
vector<double> a(y), b(n), c(n + 1), d(n);
textfor (int i = 0; i < n; ++i) h[i] = x[i + 1] - x[i]; for (int i = 1; i < n; ++i) alfa[i] = 3 / h[i] * (a[i + 1] - a[i]) - 3 / h[i - 1] * (a[i] - a[i - 1]); l[0] = 1; mu[0] = z[0] = 0; for (int i = 1; i < n; ++i) { l[i] = 2 * (x[i + 1] - x[i - 1]) - h[i - 1] * mu[i - 1]; mu[i] = h[i] / l[i]; z[i] = (alfa[i] - h[i - 1] * z[i - 1]) / l[i]; } l[n] = 1; z[n] = c[n] = 0; for (int j = n - 1; j >= 0; --j) { c[j] = z[j] - mu[j] * c[j + 1]; b[j] = (a[j + 1] - a[j]) / h[j] - h[j] * (c[j + 1] + 2 * c[j]) / 3; d[j] = (c[j + 1] - c[j]) / (3 * h[j]); } vector<SplineSegment> s(n); for (int i = 0; i < n; ++i) s[i] = { x[i], a[i], b[i], c[i], d[i] }; return s;
}
// ─────────── оценка сплайна и его производных ───────────
struct SplineEval { double S, Sp, Spp; };
SplineEval evaluate_spline(const vector<SplineSegment>& spl, const vector<double>& x_grid, double x)
{
int j = 0;
const int nSeg = static_cast<int>(spl.size());
// для узловых точек берём левый сегмент, кроме самой первой
if (x == x_grid.back()) j = nSeg - 1;
else {
while (j < nSeg - 1 && x > x_grid[j + 1]) ++j;
}
double dx = x - spl[j].xi;
const auto& seg = spl[j];
textdouble S = seg.a + seg.b * dx + seg.c * dx * dx + seg.d * dx * dx * dx; double Sp = seg.b + 2 * seg.c * dx + 3 * seg.d * dx * dx; double Spp = 2 * seg.c + 6 * seg.d * dx; return { S, Sp, Spp };
}
// ─────────── вывод значений F-S и первых производных ───────────
void write_values(const string& fname,
const vector<double>& x,
const vector<SplineSegment>& spl,
double (*f)(double),
double (*fp)(double))
{
ofstream out(fname);
out << "j xj Fj Sj Fj-Sj F'j S'j F'j-S'j\n";
out << scientific << setprecision(15);
textfor (size_t j = 0; j < x.size(); ++j) { SplineEval ev = evaluate_spline(spl, x, x[j]); double Fj = f(x[j]); double Fpj = fp(x[j]); out << j + 1 << ' ' << x[j] << ' ' << Fj << ' ' << ev.S << ' ' << Fj - ev.S << ' ' << Fpj << ' ' << ev.Sp << ' ' << Fpj - ev.Sp << '\n'; }
}
// ─────────── вывод вторых производных ───────────
void write_second_derivatives(const string& fname,
const vector<double>& x,
const vector<SplineSegment>& spl,
double (*fpp)(double))
{
ofstream out(fname);
out << "i\tx\tF''(x)\tS''(x)\t|F''-S''|\n";
out << scientific << setprecision(15);
textfor (size_t i = 0; i < x.size(); ++i) { SplineEval ev = evaluate_spline(spl, x, x[i]); double Fpp = fpp(x[i]); out << i + 1 << '\t' << x[i] << '\t' << Fpp << '\t' << ev.Spp << '\t' << fabs(Fpp - ev.Spp) << '\n'; }
}
// ─────────── вывод коэффициентов ───────────
void dump_coeffs(const string& fname,
const vector<double>& x,
const vector<SplineSegment>& s)
{
ofstream out(fname);
out << scientific << setprecision(15);
out << "i xi-1 xi aR bR cR dR\n";
textfor (int i = 1; i <= static_cast<int>(s.size()); ++i) { const auto& seg = s[i - 1]; const double h = x[i] - x[i - 1]; // преобразуем к правому узлу const double aR = seg.a + seg.b * h + seg.c * h * h + seg.d * h * h * h; const double bR = seg.b + 2 * seg.c * h + 3 * seg.d * h * h; const double cR = 2 * seg.c + 6 * seg.d * h; // вторая производная const double dR = 6 * seg.d; // третья производная out << i << ' ' << x[i - 1] << ' ' << x[i] << " " << aR << ' ' << bR << ' ' << cR << ' ' << dR << '\n'; }
}
// ─────────── проверка точности ───────────
void check(const string& tag,
const vector<SplineSegment>& spl,
double (*f)(double),
double (*fp)(double),
double (*fpp)(double),
double xmin, double xmax, int dense = 100)
{
const int m = spl.size() * dense;
double eF = 0, eFp = 0, eFpp = 0;
textfor (int k = 0; k <= m; ++k) { double x = xmin + (xmax - xmin) * k / m; int j = 0; while (j < int(spl.size()) - 1 && x > spl[j + 1].xi) ++j; double dx = x - spl[j].xi; const auto& seg = spl[j]; double S = seg.a + seg.b * dx + seg.c * dx * dx + seg.d * dx * dx * dx; double Sp = seg.b + 2 * seg.c * dx + 3 * seg.d * dx * dx; double Spp = 2 * seg.c + 6 * seg.d * dx; eF = max(eF, fabs(f(x) - S)); eFp = max(eFp, fabs(fp(x) - Sp)); eFpp = max(eFpp, fabs(fpp(x) - Spp)); } cout << tag << ":\n" << "max|S-f| =" << scientific << eF << '\n' << "max|S'-f'| =" << eFp << '\n' << "max|S''-f''|=" << eFpp << '\n';
}
int main()
{
const int task_id = 1; // 1, 2 или 3
textif (task_id == 1) { const int N = 9; const double xmin = -1, xmax = 1; vector<double> x(N + 1), y(N + 1); for (int i = 0; i <= N; ++i) { x[i] = xmin + (xmax - xmin) * i / N; y[i] = f1(x[i]); } auto spl = cubic_spline(x, y); dump_coeffs("spline1_output.txt", x, spl); write_values("function1_values.txt", x, spl, f1, f1p); write_second_derivatives("function1_derivatives.txt", x, spl, f1pp); check("f1", spl, f1, f1p, f1pp, xmin, xmax); system("python test.py"); } else if (task_id == 2) { const int N = 5; const double xmin = 0.2, xmax = 2.0; vector<double> x(N + 1), y(N + 1); for (int i = 0; i <= N; ++i) { x[i] = xmin + (xmax - xmin) * i / N; y[i] = f2(x[i]); } auto spl = cubic_spline(x, y); dump_coeffs("spline2_output.txt", x, spl); write_values("function2_values.txt", x, spl, f2, f2p); write_second_derivatives("function2_derivatives.txt", x, spl, f2pp); check("f2", spl, f2, f2p, f2pp, xmin, xmax); system("python main.py"); } else if (task_id == 3) { const int N = 11; const double xmin = 0.2, xmax = 2.0; vector<double> x(N + 1), y(N + 1); for (int i = 0; i <= N; ++i) { x[i] = xmin + (xmax - xmin) * i / N; y[i] = f3(x[i]); } auto spl = cubic_spline(x, y); dump_coeffs("spline3_output.txt", x, spl); write_values("function3_values.txt", x, spl, f3, f3p); write_second_derivatives("function3_derivatives.txt", x, spl, f3pp); check("f3", spl, f3, f3p, f3pp, xmin, xmax); system("python main2.py"); } return 0;
}
Ниже — готовый Python-скрипт plot_spline_task1.py
.
Он читает три выходных файла C++-программы, восстанавливает кубический сплайн «по сегментам» (индексация xi-1, xi
) и строит требуемые шесть графиков в одном окне (2 × 3 subplots).
python#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Отрисовка результатов задачи 1 (кусочный кубический сплайн). Графики: 1) исходная функция f(x); 2) Fj − Sj; 3) F'j и S'j; 4) F'j − S'j; 5) F''j и S''j; 6) F''j − S''j. Скрипт легко адаптируется для задач 2 и 3 – см. блок 'ПАРАМЕТРЫ ДЛЯ ЗАМЕНЫ'. """ import numpy as np import matplotlib.pyplot as plt from pathlib import Path # ──────────────────── ПАРАМЕТРЫ ДЛЯ ЗАМЕНЫ ──────────────────── # 1. Базовые имена файлов (без изменения формата строк): coeff_file = 'spline1_output.txt' values_file = 'function1_values.txt' derivatives_file = 'function1_derivatives.txt' # 2. Исходная функция (нужна только для 1-го графика): def f(x: np.ndarray) -> np.ndarray: """f1(x) = { x^3+3x^2, x≤0; −x^3+3x^2, x>0 }""" return np.where(x <= 0, x**3 + 3*x**2, -x**3 + 3*x**2) # 3. Диапазон x, на котором рисуется f(x): x_min, x_max, plot_points = -1.0, 1.0, 400 # ────────────────────────────────────────────────────────────── # ─────────── читатели выходных файлов C++ программы ─────────── def load_values(fname: str): """Файл function*_values.txt → словарь с массивами Fj, Sj, …""" data = np.loadtxt(fname, skiprows=1) return { 'x' : data[:, 1], 'F' : data[:, 2], 'S' : data[:, 3], 'F_minus_S': data[:, 4], 'Fp' : data[:, 5], 'Sp' : data[:, 6], 'Fp_minus_Sp': data[:, 7], } def load_second_derivs(fname: str): """Файл function*_derivatives.txt → словарь с F''j, S''j, …""" data = np.loadtxt(fname, skiprows=1) return { 'x' : data[:, 1], 'Fpp' : data[:, 2], 'Spp' : data[:, 3], 'Fpp_minus_Spp': data[:, 4], } def load_spline_coeffs(fname: str): """ Файл spline*_output.txt (коэффициенты в правом узле xi): i, xi-1, xi, aR, bR, cR, dR → список словарей с коэффициентами и узлами. """ data = np.loadtxt(fname, skiprows=1) segments = [] for row in data: _, x_left, x_right, aR, bR, cR, dR = row segments.append({ 'x_left' : x_left, 'x_right': x_right, 'aR' : aR, 'bR': bR, 'cR': cR, 'dR': dR }) return segments def spline_eval(x: np.ndarray, segments): """ Оценка сплайна S(x) в точках x, используя коэффициенты (aR, bR, cR, dR) в ПРАВОМ узле xi. """ # Подготовим выходной массив S = np.empty_like(x, dtype=float) # Для каждой точки ищем её сегмент (можно ускорить через np.searchsorted) for seg in segments: mask = (x >= seg['x_left']) & (x <= seg['x_right']) dx = x[mask] - seg['x_right'] # смещение от правого узла S[mask] = (seg['aR'] + seg['bR'] * dx + seg['cR'] * dx**2 + seg['dR'] * dx**3) return S # ────────────────────────────────────────────────────────────── # ────────────────────────── Загрузка ────────────────────────── vals = load_values(values_file) d2 = load_second_derivs(derivatives_file) segs = load_spline_coeffs(coeff_file) # пригодится при отладке/расширении # ────────────────────────────────────────────────────────────── # ───────────────────────── Построение ───────────────────────── fig, axes = plt.subplots(2, 3, figsize=(14, 8), dpi=110) (ax1, ax2, ax3, ax4, ax5, ax6) = axes.flat # 1. f(x) x_dense = np.linspace(x_min, x_max, plot_points) ax1.plot(x_dense, f(x_dense), label='f(x)') ax1.set_title('Функция f(x)') ax1.grid(True) # 2. Fj − Sj ax2.plot(vals['x'], vals['F_minus_S'], marker='o') ax2.set_title('Fj − Sj') ax2.grid(True) # 3. F′j и S′j ax3.plot(vals['x'], vals['Fp'], marker='o', label="F'j") ax3.plot(vals['x'], vals['Sp'], marker='s', label="S'j") ax3.set_title("Первая производная") ax3.legend() ax3.grid(True) # 4. F′j − S′j ax4.plot(vals['x'], vals['Fp_minus_Sp'], marker='o') ax4.set_title("F'j − S'j") ax4.grid(True) # 5. F″j и S″j ax5.plot(d2['x'], d2['Fpp'], marker='o', label="F''j") ax5.plot(d2['x'], d2['Spp'], marker='s', label="S''j") ax5.set_title("Вторая производная") ax5.legend() ax5.grid(True) # 6. F″j − S″j ax6.plot(d2['x'], d2['Fpp_minus_Spp'], marker='o') ax6.set_title("F''j − S''j") ax6.grid(True) fig.suptitle("Кубический сплайн: задача 1", fontsize=14) fig.tight_layout() fig.subplots_adjust(top=0.90) # оставить место для suptitle plt.show() # ──────────────────────────────────────────────────────────────
Что поменять | Где искать |
---|---|
Имена файлов spline*_output.txt , function*_values.txt , function*_derivatives.txt | блок «ПАРАМЕТРЫ ДЛЯ ЗАМЕНЫ», переменные coeff_file , values_file , derivatives_file |
Формулу функции f(x) и диапазон x_min…x_max | там же: функция f(x) и переменные x_min , x_max |
(опционально) Название окна/графиков | строка fig.suptitle(...) |
Больше ничего менять не нужно: формат файлов одинаковый для всех трёх задач, поэтому остальная логика остаётся неизменной.