у меня есть c++ код, который считает кубический сп...

Создано: 28 мая 2025 г.

Отвечено с использованием O3 от Chat01

Вопрос

у меня есть 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);

text
for (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];

text
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; 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);

text
for (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);

text
for (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";

text
for (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;

text
for (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

text
if (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;

}

Мысль

Writing Python Code

I see the user wants me to write Python code to read specific files, reconstruct the spline using indices xi-1 and xi, and generate six curves in a single window with subplots (possibly in a 3 x 2 or 2 x 3 configuration). They also want future instructions on how to adapt the code to work with other tasks. They didn't ask for immediate execution, just the code and guidance on what lines to modify for other functions. I’ll provide that code and instructions.

Planning Python Code for Spline Plot

I need to write Python code to read three text files: spline1_output.txt, function1_values.txt, and function1_derivatives.txt. The goal is to reconstruct spline segments using xi-1 and xi from the spline file, and then plot continuous function curves. The user wants to plot differences between spline and function values, and display first and second derivatives. I'll parse the text data, reconstruct the spline, and create multiple graphs for the user, including derivatives. For each task, I just need to provide the code and usage instructions with clear modifications.

Clarifying Code Approach

I’m thinking about how to reconstruct the spline using xi-1 and xi, but the coefficients are provided at the right endpoint of each segment in spline1_output.txt. Since the user wants to reconstruct the spline, I'll opt to read the coefficients and adjust for left endpoints if needed.

The task is mainly for plotting discrete values, so instead of reconstructing continuously across x, I'll focus on the formulas for each plot. The key seems to be modifying files and function formulas; I’ll guide the user with comments on what parts to change for different use cases.

Thought for 1m 48s

Ответ

Ниже — готовый 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&le;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 &rarr; словарь с массивами 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 &rarr; словарь с 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 &rarr; список словарей с коэффициентами и узлами. """ 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() # ──────────────────────────────────────────────────────────────

Как адаптировать скрипт для задач 2 или 3

Что поменятьГде искать
Имена файлов 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(...)

Больше ничего менять не нужно: формат файлов одинаковый для всех трёх задач, поэтому остальная логика остаётся неизменной.

Поделиться этим Q&A