質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

227閲覧

フーリエ級数展開の精度について(C++)

hamua

総合スコア2

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2024/11/12 20:11

編集2024/11/12 20:16

実現したいこと

フーリエ級数展開を行うプログラムをシンプソン積分法により求めましたが、以下のような結果になりました。そのため、パラメータは変えずに誤差を小さくしたいです。

対象関数:y=x*x, x=-10~+10までの周期=20と仮定してます。
(出力:for(double x=0; x<1; x+=0.1))
偶関数なため、sinの計算は0になるので、実装していません。

error(%):-inf error(%):20.0615 error(%):-5.01533 error(%):2.22901 error(%):-1.2538 error(%):0.802411 error(%):-0.557214 error(%):0.409369 error(%):-0.313411 error(%):0.247623 error(%):-0.200564

発生している問題・分からないこと

プログラムに間違いがあるか、誤差はこの程度になるか分からないため、知見がある方に教えて頂きたいです。

該当のソースコード

c++

1#include <iostream> 2#include <cmath> 3#include <math.h> 4 5const int MaxNumOfSeries = 100; // フーリエ級数展開を行う数 6const int HalfPeriod = 10; // 周期の半分 7 8// フーリエ級数展開を行う関数:x*x 9double TargetFunc(double x){ 10 return x*x; 11} 12 13double Fouriercoefficient(double x, int numOfSeries) { 14 return TargetFunc(x) * std::cos(numOfSeries * M_PI* x/ HalfPeriod); 15} 16 17double Simpson(double lowerBound, double upperBound, int divisions, int numOfSeries) { 18 if (divisions % 2 != 0) { 19 divisions++; // nを偶数にする(シンプソンの公式の要件) 20 } 21 22 double h = (upperBound - lowerBound) / divisions; 23 double integral = 0; 24 25 // 積分の開始と終了点を加算 26 integral += Fouriercoefficient(lowerBound, numOfSeries) + Fouriercoefficient(upperBound, numOfSeries); 27 28 // 各小区間においてシンプソンの公式を適用 29 for (int i = 1; i < divisions; i += 2) { 30 integral += 4 * Fouriercoefficient(lowerBound + i * h, numOfSeries); // 奇数インデックスの項 31 } 32 33 for (int i = 2; i < divisions; i += 2) { 34 integral += 2 * Fouriercoefficient(lowerBound + i * h, numOfSeries); // 偶数インデックスの項 35 } 36 37 // 最後に h / 3 を掛けて積分結果を計算 38 integral *= h / 3; 39 return integral; 40} 41 42double FourierSeries(double x){ 43 double lowerBound = -HalfPeriod; // 積分の下限 44 double upperBound = HalfPeriod; // 積分の上限 45 int divisions = 5000; // 分割数 46 47 double sum = Simpson(lowerBound, upperBound, divisions,0)/(2* HalfPeriod); // 級数=0を加算 48 49 // 0以外の級数展開を計算 50 for(int i= 1; i<= MaxNumOfSeries; i++){ 51 sum+= Simpson(lowerBound, upperBound, divisions, i)/HalfPeriod * std::cos(i *M_PI *x/ HalfPeriod); 52 } 53 54 return sum; 55} 56 57int main() { 58 59 for(double x=0; x<1; x+=0.1){ 60 // std::cout << "x= " << x << " x*x= " << TargetFunc(x) << " FourierSeries= " << FourierSeries(x) << std::endl; 61 std::cout <<"error(%):" << (TargetFunc(x) - FourierSeries(x))/TargetFunc(x) *100 << std::endl; 62 } 63 64 return 0; 65} 66

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

シンプソン積分法の誤差は以下のサイトに書いてあり、そうすると今回の誤差は0.1%以上もあるのは大きいように感じています。

リンク内容

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

目的であったガウス関数のフーリエ級数展開の誤差は少なかったので、プログラムに問題がないことが分かりました。また、計算ライブラリで確認しても誤差はありませんでした。

投稿2024/11/17 23:50

hamua

総合スコア2

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問