第二個任務:
對于函式 f : R^n → R,要計算點 ~x ∈ R^n 處的梯度:
- 實作一個函式
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)),在第一個引數中給出位置 ~x,在第二個引數中給出函式 f作為第二個引數中的函式指標,它通過 gi = f(x1, . . . , xi-1, xi h, xi 1 . . . ., xn 數值計算梯度 ~g = grad f(~x) ) - f(x1, . . . , xn)/h 到固定 h = 10^-8。
我目前撰寫的程式:
Header
#pragma once
#include <vector>
#include <math.h>
class CMyVektor
{
private:
/* data */
int Dimension = 0;
std::vector<double>Vector;
public:
CMyVektor();
~CMyVektor();
//Public Method
void set_Dimension(int Dimension /* Aktuelle Dim*/);
void set_specified_Value(int index, int Value);
double get_specified_Value(int key);
int get_Vector_Dimension();
int get_length_Vektor();
double& operator [](int index);
string umwandlung()
};
CMyVektor::CMyVektor(/* args */)
{
Vector.resize(0, 0);
}
CMyVektor::~CMyVektor()
{
for (size_t i = 0; i < Vector.size(); i )
{
delete Vector[i];
}
}
void CMyVektor::set_Dimension(int Dimension /* Aktuelle Dim*/)
{
Vector.resize(Dimension);
};
void CMyVektor::set_specified_Value(int index, int Value)
{
if (Vector.empty())
{
Vector.push_back(Value);
}
else {
Vector[index] = Value;
}
};
double CMyVektor::get_specified_Value(int key)
{
// vom intervall anfang - ende des Vectors
for (unsigned i = 0; i < Vector.size(); i )
{
if (Vector[i] == key) {
return Vector[i];
}
}
};
int CMyVektor::get_Vector_Dimension()
{
return Vector.size();
};
// Berechnet den Betrag "l?nge" eines Vectors.
int CMyVektor::get_length_Vektor()
{
int length = 0;
for (size_t i = 0; i < Vector.size(); i )
{
length = Vector[i]^2
}
return sqrt(length);
}
// [] Operator überladen
double& CMyVektor::operator [](int index)
{
return Vector[index];
}
main.cpp
#include <iostream>
#include "ClassVektor.h"
using namespace std;
CMyVektor operator (CMyVektor a, CMyVektor b);
CMyVektor operator*(double lambda, CMyVektor a);
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
int main() {
CMyVektor V1;
CMyVektor V2;
CMyVektor C;
C.set_Dimension(V1.get_length_Vector());
C= V1 V2;
std::cout << "Addition : "<< "(";;
for (int i = 0; i < C.get_length_Vector(); i )
{
std::cout << C[i] << " ";
}
std::cout << ")" << endl;
C = lamda * C;
std::cout << "Skalarprodukt: "<< C[0]<< " ";
}
// Vector Addition
CMyVektor operator (CMyVektor a, CMyVektor b)
{
int ai = 0, bi = 0;
int counter = 0;
CMyVektor c;
c.set_Dimension(a.get_length_Vector());
// Wenn Dimension Gleich dann addition
if (a.get_length_Vector() == b.get_length_Vector())
{
while (counter < a.get_length_Vector())
{
c[counter] = a[ai] b[bi];
counter ;
}
return c;
}
}
//Berechnet das Skalarprodukt
CMyVektor operator*(double lambda, CMyVektor a)
{
CMyVektor c;
c.set_Dimension(1);
for (unsigned i = 0; i < a.get_length_Vector(); i )
{
c[0] = lambda * a[i];
}
return c;
}
/*
* Differenzenquotient : (F(x0 h) F'(x0)) / h
* Erster Parameter die Stelle X - Zweiter Parameter die Funktion
* Bestimmt numerisch den Gradienten.
*/
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x))
{
}
我現在的問題是我不太清楚如何處理這個
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
函式,以及如何定義一個與之對應的函式。
我希望這是足夠的資訊。非常感謝。
uj5u.com熱心網友回復:
函式引數是f差分公式中的。它接受一個CMyVector引數x并回傳一個雙精度值。您需要提供函式引數名稱。我暫時假設func。
我沒有看到h. 你打算將一個小值傳遞給gradient函式還是假設一個常數?
引數x是一個向量。你會h為每個元素添加一個常量嗎?
這個功能規范是一團糟。
函式回傳一個雙精度值。你打算如何把它變成一個向量?
難怪你會感到困惑。我是。
你想做這樣的事情嗎?
uj5u.com熱心網友回復:
給你一個函式簽名
CMyVector gradient(CMyVector x, double (*function)(CMyVector x))
在不知道確切定義的情況下,我將假設至少定義了基本的數值向量運算。這意味著,以下陳述句編譯:
CMyVector x {2.,5.,7.};
CMyVector y {1.,7.,4.};
CMyVector z {0.,0.,0.};
double a = 0.;
// vector addition and assigment
z = x y;
// vector scalar multiplication and division
z = z * a;
z = x / 0.1;
我們還需要知道CMyVector類的維度。我假設并將繼續這樣做,它是三維的。
下一步是了解函式簽名。你得到兩個引數。第一個表示應該計算梯度的點。第二個是指向公式中函式f的指標。您不知道它,但可以從gradient函式定義中的向量上呼叫它。這意味著,在定義中,您可以執行類似的操作
double f_at_x = function(x);
并且f_at_x在該操作之后將保持值 f(x)。
有了這個,我們可以嘗試實作你在問題標題中提到的公式:
CMyVector gradient(CMyVector x, double (*function)(CMyVector x)) {
double h = 0.001;
// calculate first element of the gradient
CMyVector e1 {1.0, 0.0, 0.0};
double result1 = ( function(x e1*h) - function(x) )/h;
// calculate second element of the gradient
CMyVector e2 {0.0, 1.0, 0.0};
double result2 = ( function(x e2*h) - function(x) )/h;
// calculate third element of the gradient
CMyVector e3 {0.0, 0.0, 1.0};
double result3 = ( function(x e3*h) - function(x) )/h;
// return the result
return CMyVector {result1, result2, result3};
}
這段代碼中有幾件事值得一提。我選擇的第一個也是最重要的h = 0.001。這可能是一個非常隨意的選擇,但步長的選擇會極大地影響結果的精度。您可以在此處找到有關該主題的大量討論。根據該維基百科頁面,我采用了許多手持計算器內部使用的相同值。這可能不是處理器浮點精度的最佳選擇,但應該是一個公平的開始。
其次,對于高級程式員來說,代碼看起來非常難看。對于三個維度中的每一個,我們都在做幾乎相同的事情。通常,您希望在for 回圈中執行此操作。具體如何完成取決于CMyVector型別是如何定義的。
uj5u.com熱心網友回復:
由于 CMyVektor 只是重寫valarray容器,我將直接使用valarray:
#include <iostream>
#include <valarray>
using namespace std;
using CMyVektor = valarray<double>;
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x));
const double h = 0.00000001;
int main()
{
// sum(x_i^2 x_i)--> gradient: 2*x_i 1
auto fun = [](CMyVektor x) {return (x*x x).sum();};
CMyVektor d = gradient(CMyVektor{1,2,3,4,5}, fun);
for (auto i: d) cout << i<<' ';
return 0;
}
CMyVektor gradient(CMyVektor x, double (*funktion)(CMyVektor x)){
CMyVektor grads(x.size());
CMyVektor pos(x.size());
for (int i = 0; i<x.size(); i ){
pos[i] = 1;
grads[i] = (funktion(x h * pos) - funktion(x))/ h;
pos[i] = 0;
}
return grads;
}
列印出3 5 7 9 11給定函式和給定位置所期望的內容
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/464866.html
