我有一個代碼,我在其中執行表單的許多操作
double z_sq = pow(abs(std::complex<double> z), 2);
計算復數 z 的 |z|2,其中性能和精度是我主要關注的問題。我讀到pow()C 的函式將int指數轉換為double并因此引入了數值錯誤,除了通常比 x*x 的性能更差(此處討論實數)。類似地,std::pow()方法<complex>轉換的指數為std::complex<double>不必要的。
我的第一個問題是如何以最佳性能和精度實作復方Re2 Im2或zz *。我想過做類似的事情
double complex_square1(std::complex<double> z) {
double abs_z = abs(z);
return abs_z * abs_z;
}
或(這會導致型別錯誤,但這是我能想到的最直接的方法)
double complex_square2(std::complex<double> z) {
return z * conj(z);
}
我的第二個問題是,對于許多(10^14)這樣的操作,函式呼叫是否會顯著降低性能。那么在complex_square1寫入abs(z) * abs(z).cpp 檔案而不是為其定義函式的情況下會更好嗎?有沒有其他更好的方法來做到這一點?
uj5u.com熱心網友回復:
我認為僅取虛部和實部的平方和是很難被擊敗的。
下面我測量它比實際計算幅度和平方快約 5 倍:
#include <complex>
#include <chrono>
#include <random>
#include <vector>
#include <iostream>
double square_of_magnitude_1( std::complex<double> z) {
auto magnitude = std::abs(z);
return magnitude * magnitude;
}
double square_of_magnitude_2( std::complex<double> z) {
return z.imag() * z.imag() z.real() * z.real();
}
volatile double v; // assign to volatile so calls do not get optimized away.
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<double> dist(0, 10);
int main() {
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::microseconds;
std::vector<std::complex<double>> numbers(10000000);
std::generate(numbers.begin(), numbers.end(), []() {return std::complex<double>(dist(e2), dist(e2)); });
auto t1 = high_resolution_clock::now();
for (const auto& z : numbers) {
v = square_of_magnitude_1(z);
}
auto t2 = high_resolution_clock::now();
std::cout << "square_of_magnitude_1 => " << duration_cast<microseconds>(t2 - t1).count() << "\n";
t1 = high_resolution_clock::now();
for (const auto& z : numbers) {
v = square_of_magnitude_2(z);
}
t2 = high_resolution_clock::now();
std::cout << "square_of_magnitude_2 => " << duration_cast<microseconds>(t2 - t1).count() << "\n";
}
上述收益率的典型運行
square_of_magnitude_1 => 54948
square_of_magnitude_2 => 9730
uj5u.com熱心網友回復:
根據彼得的回答(再次感謝),這是建議方法中最快的,我為感興趣的人補充了我的比較代碼:
#include <complex>
#include <chrono>
using complex = std::complex<double>;
double complex_square1(complex z) {
return z.real()*z.real() z.imag()*z.imag();
}
double complex_square2(complex z) {
double abs_z = abs(z);
return abs_z * abs_z;
}
complex z = complex(0.5, 0.5);
unsigned int N = (int)1e7;
double z_sq;
int main() {
auto start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < N; i) {
z_sq = z.real()*z.real() z.imag()*z.imag(); // fastest
// z_sq = complex_square1(z); // slower by a factor 1.6
// z_sq = complex_square2(z); // slower by a factor 5.5
// z_sq = pow(abs(z), 2); // slower by a factor 6
// z_sq = norm(z); // slower by a factor 5
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
printf("Duration: %d ms\n", duration);
printf("z_sq = %f", z_sq);
}
這也回答了我的第二個問題:在我的 Windows 機器上并使用 GCC 編譯器進行測量時,函式呼叫確實變得明顯,但計算時間僅增加了約 60%
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/333519.html
