VC++中的Runge Kutta方法
Runge Kutta method in VC++
我正在开发一种使用Runge Kutta方法计算新数据点的算法。以下是实现此方法的参考 - http://calculuslab.deltacollege.edu/ODE/7-C-3/7-C-3-h.html。这是我的代码:
#include<iostream>
#include<math.h>
class Runge_Kutta
{
public:
float x[100];
float y[200];
float h; // step size
float K_1,K_2,K_3,K_4;
float compute(); // function to compute data point
float data(); //function to generate data signal
Runge_Kutta();
~Runge_Kutaa();
}
Runge_Kutta::Runge_Kutta()
{
x[100] = 0; // input signal
y[200] = 0; // output accumulator
h = 0.2;
K_1 = K_2 = K_3 = K_4 = 0;
}
~Runge_Kutta::Runga_Kutta(){}
float Runge_Kutta::data()
{
int i = 0;
for(i=0 ; i<100 ; i++)
{
x[i] = 5*sin((2*3.14*5*i)*0.01); /*x[i] = A*sin(2*Pi*f*i*Ts)
} Ts-sampling period, A-amplitude,
return x[i]; f-frequency*/
}
float Runge_Kutta::compute()
{
int j = 0;
int i = 0;
for(i = 0 ; i<100 ; i++) // indexing through the input samples
{
for(j = 0 ; j<i+1 ; j++) // compute data points btw i and i+1
{
K_1 = h*x[i];
K_2 = h*((x[i]+(h/2) + K_1/2);
K_3 = h*((x[i]+(h/2) + K_2/2);
K_4 = h* ((x[i] + h) + K_3);
}
y[i] = (1/6)*(K_1 + 2*K_2 + 2*K_3 + K_4); //new data value
}
return y[i];
}
int main()
{
Runga_Kutta Interpolate;
Interpolate.data();
Interpolate.compute();
return 0;
}
问题是:y[i] 没有存储新的数据值,而是显示"0"或一些垃圾值。第二个问题是,在这种情况下,我不可能将浮点的循环索引值(x 轴)递增为"h = 0.2"。我使用断点来查找问题,但我无法弄清楚,需要一些帮助或指导才能解决这个问题。我有一种感觉,这是由于我的逻辑和实现中的一些问题。请查看我的代码和有关如何修复它的建议将有很大帮助。提前谢谢。
你的代码中有几个问题...我会指出我所看到的。
class Runge_Kutta
{
public:
float x[100];
float y[200];
float h; // step size
float K_1, K_2, K_3, K_4;
float compute(); // function to compute data point
float data(); //function to generate data signal
Runge_Kutta();
~Runge_Kutaa();
};
到目前为止,好吧...
Runge_Kutta::Runge_Kutta()
{
x[100] = 0; // input signal
这是你的第一个问题。x
数组是 100 个浮点数,您正在尝试设置 101 个浮点数。请记住,C++使用从零开始的索引,因此唯一有效的索引是 0 到 99(包括 0 到 99)。通过写入x[100]
你在数组之外写入...可能进入y
,但你当然不应该这样做。
更有可能的是,您希望对整个数组进行零初始化。有不同的方法可以创建/初始化一系列值(例如向量、动态分配),但正如你所做的那样,最简单的方法可能是:
for (int i = 0; i < 100; ++i) { x[i] = 0.0f; }
您最好创建一个命名常量来替换"幻数"100。 继续使用您的代码:
y[200] = 0; // output accumulator
上述x
类似的问题。同样,我怀疑您正在尝试将整个数组零初始化;替换为:
for (int i = 0; i < 200; ++i) { y[i] = 0.0f; }
然后:
h = 0.2;
这将起作用;您可能会收到有关双精度到浮点数转换的警告,因为 2.0 被认为是双精度数,但您正在存储浮点数。您可以通过追加f
来强制浮点文本。
h = 0.2f;
继续:
K_1 = K_2 = K_3 = K_4 = 0;
}
~Runge_Kutta::Runga_Kutta(){}
float Runge_Kutta::data()
{
int i = 0;
for(i=0 ; i<100 ; i++)
{
x[i] = 5*sin((2*3.14*5*i)*0.01); /*x[i] = A*sin(2*Pi*f*i*Ts)
} Ts-sampling period, A-amplitude,
return x[i]; f-frequency*/
}
也许您实际上并没有使用多行注释(例如/* 和 */),但您实际上在这里注释掉了一些代码......足以使其不应编译。如果要在代码右侧创建块注释,请确保使用每行注释(例如//)。
假设你真的做对了,你在这里有一个更大的问题。首先声明 i
,将其设置为零,然后将其用作循环索引。就其本身而言,这不是问题,尽管在for
内循环
for (int i = 0; i < 100; ++i)
最大的问题是在循环后访问x[i]
。 此时i
为 100,和以前一样,x[i]
在 x
数组之外,该数组只能从 0 到 99 进行索引。你的意思是要x[0]
返回吗?你想要哪个 x?返回该特定值。
float Runge_Kutta::compute()
{
int j = 0;
int i = 0;
for(i = 0 ; i<100 ; i++) // indexing through the input samples
{
for(j = 0 ; j<i+1 ; j++) // compute data points btw i and i+1
{
K_1 = h*x[i];
K_2 = h*((x[i]+(h/2) + K_1/2);
K_3 = h*((x[i]+(h/2) + K_2/2);
K_4 = h* ((x[i] + h) + K_3);
}
y[i] = (1/6)*(K_1 + 2*K_2 + 2*K_3 + K_4); //new data value
}
return y[i];
}
您可能在本节中混淆了循环指示。(但我对龙格-库塔不够熟悉,不知道。 i
应该是x
和y
的索引吗? j
在哪里习惯,应该在哪里?
最后,返回y[i]
似乎会遇到与上一个循环类似的问题......实际上,您只是将y
从 0 初始化为 99,然后返回y[100]
(因为该函数末尾的 i == 100)。
如果你对我提出的任何观点感到困惑,我会尽量澄清;只是问。
编辑:如前所述,(1/6)将计算(使用整数除法)为零。将一个或两个常量替换为浮点数以确保浮点除法...例如 1.0/6
因此,您希望在调用data()
或compute()
后访问所有数据...但是现在您返回的是单个float
而不是整个数组。 以下是一些选项。
首先,您已x
可公开访问。通常不推荐,但如果这是学习或实验,因为它是 public
,您可以直接访问该数据。
Runge_Kutta Interpolate;
Interpolate.data();
Interpolate.compute();
for (int i = 0; i < 100; ++i) {
printf("Data point x[%d] = %fn", i, Interpolate.x[i]);
}
您可以更改data()
和compute()
以返回指向数组的指针,但通常也不建议这样做:
float* Runge_Kutta::data()
{
// the bulk of the function...
return &x[0];
}
// Use:
float* pData = Interpolate.data();
printf("First data signal: %fn", pData[0]);
另一种选择是提供索引数据访问器:
class Runge_Kutta {
public:
// everything else you already have...
float getDataSignal(size_t i) const {
return x[i];
}
float getDataPoint(size_t i) const {
return y[i];
}
};
甚至另一种选择是使用C++标准库中的容器,例如 vector
,其中包含许多方便的操作作为库的一部分。
您不应通过引入其他约束(例如必须插值数据集以获取系统函数)来使情况复杂化。
RK::dydx(x,y)
{
return 5*sin(2*M_PI*5*x);
}
并使用 RK4 食谱的正确转录
RK::step(x,y,h)
{
double K1 = h*dydx(x,y);
double K2 = h*dydx(x+h/2, y+K1/2);
double K3 = h*dydx(x+h/2, y+K2/2);
double K4 = h*dydx(x+h , y+K3 );
return y+(K1+2*(K2+K3)+K4)/6
}
然后你可以循环
for(i=0;i<100-1; i++)
{
y[i+1] = step(x,y[i],h);
x +=h;
}
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- VC++中的Runge Kutta方法