C++程序的奇怪行为

ckocjqey  于 2024-01-09  发布在  其他
关注(0)|答案(2)|浏览(163)

回调函数有一个奇怪的行为,我想用二分法计算一个函数的根,要解决的系统涉及到一个函数的积分,其中上限是另一个函数的函数,这不是什么大不了的事情,当我把数值放进去的时候,程序结束得很好,但是如果我做函数的回调,终端杀死了进程,程序运行得更慢。顺便说一下,这些是我用c++写的第一段代码。
代码块是下一个;

  1. #include <gsl/gsl_integration.h>
  2. #include <functional>
  3. #include <iostream>
  4. #include <cmath>
  5. struct Ninj_Params{
  6. double p;
  7. double Q0;
  8. double gamma_m;
  9. };
  10. double c = 1;
  11. double eV = 1.0;
  12. double MeV = pow(10,6) * eV;
  13. double me = 0.510998902 * MeV;
  14. double e = 8.542 * pow(10,-2);
  15. double fm = 1/197.3269602 * 1/MeV;
  16. double cm = pow(10,13) * fm;
  17. double Gauss = 5.788381749 * pow(10,-15) * MeV * 2 * me/e;
  18. double meter = pow(10,2) * cm;
  19. double sec = 299792458*meter;
  20. // Function to find the root using the bisection method
  21. double bisection(const std::function<double(double)> &func, double a, double b, double tolerance){
  22. if (func(a) * func(b) >= 0){
  23. printf("Bisection method cannot guarantee convergence in this interval.\n");
  24. return NAN; // Not a Number to indicate failure
  25. }
  26. double c = a;
  27. while ((b - a) >= tolerance) {
  28. // Find middle point
  29. c = (a + b) / 2;
  30. // Check if the root is found
  31. if (func(c) == 0.0)
  32. break;
  33. // Update the interval based on the sign of the function at the middle point
  34. if (func(c) * func(a) < 0)
  35. b = c;
  36. else
  37. a = c;
  38. }
  39. return c;
  40. }
  41. double beta(double Gamma){
  42. return sqrt(1. - pow(Gamma, -2.));
  43. }
  44. double R(double t, double Rs, double Gamma){
  45. return (Rs + beta(Gamma)*c*Gamma*t)*1./cm;
  46. }
  47. double B(double t, double Rs, double R0, double Gamma, double B0, double a){
  48. return B0*pow((R(t, Rs, Gamma)*cm)/R0, -a)*1./Gauss;
  49. }
  50. double Q(double gammae, void * args){
  51. Ninj_Params& params = *(Ninj_Params*)args;
  52. if(params.gamma_m <= gammae){
  53. return params.Q0*pow(gammae/params.gamma_m, -params.p)*sec;
  54. }else{
  55. return 0.0;
  56. }
  57. }
  58. double Ninj(double Q0, double p, double gamma_min, double gamma_max){
  59. struct Ninj_Params params = {
  60. .p = 2.5,
  61. .Q0 = Q0,
  62. .gamma_m = gamma_min,
  63. };
  64. gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000);
  65. double result, error;
  66. gsl_function F;
  67. F.function = &Q;
  68. F.params = &params;
  69. gsl_integration_qags (&F, gamma_min, gamma_max, 0, 1e-7, 1000, w, &result, &error);
  70. return result;
  71. }
  72. double Q0rate(double Ninj_Gest, double t, double Rs, double R0, double Gamma, double B0, double a){
  73. //double gamma_max = 1e8*pow(B(t, Rs, R0, Gamma, B0, a), -0.5);
  74. double gamma_max = 7.957e+06;
  75. printf("**** %.3e\n", gamma_max);
  76. double p = 2.5;
  77. auto root2solve = [Ninj_Gest, p, &gamma_max](double Q0) -> double{
  78. return Ninj_Gest - Ninj(Q0*1/sec, p, 1e5, gamma_max);
  79. };
  80. double root = bisection(root2solve, 1e40*1./sec, 1e53*1./sec, 1e-7);
  81. return root*sec;
  82. }
  83. void TEST_ROOT(double t, double Rs, double R0, double Gamma, double gamma_m, double B0, double a){
  84. double Nj = 1e47*1/sec;
  85. printf("%.5e\n",Q0rate(Nj, t, Rs, R0, Gamma, B0, a));
  86. }
  87. int main(){
  88. double t = 10*sec;
  89. double Rs = 1e14*cm;
  90. double R0 = 1e15*cm;
  91. double B0 = 0.3*1e2*Gauss;
  92. double Gamma = 300;
  93. double gamma_m = 1e5;
  94. double a = 1.0;
  95. TEST_ROOT(t, Rs, R0, Gamma, gamma_m, B0, a);
  96. }

字符串
有问题的行是105(和注解的106)。When设置为:

  1. double gamma_max = 1e8*pow(B(t, Rs, R0, Gamma, B0, a), -0.5);


输出是(具有缓慢的行为):

  • 7.957e+06 zsh:killed ./Main

如果更改为:

  1. double gamma_max = 7.957e+06;


程序以期望的根值结束:
% ./主要 * 7.957e+06 1.50212e+42

svujldwt

svujldwt1#

你不能指望用double数学找到精确的值.即使是简单的方程3x=1也不能用浮点数学精确求解(数字1/3不能用double精确表示)。
您的退出条件需要基于某个值。
IEEE 754双精度浮点数(通常是C++ double的精度)只有53位尾数;因此应该考虑所涉及的值的大小来计算尾数值。
如果说你的函数输出的值可以是“大”的(例如1 E50),那么一个单位顺序的整数是不够的(1 E50 +1 == 1 E50)。
还要注意的是,即使在中间计算中,浮点数的不准确也会造成问题,特别是当执行大的取消时(例如,当你减去两个非常大的数字时)。
正如Ted Lyngmo指出的那样,原始代码中也存在内存泄漏。

o4hqfura

o4hqfura2#

你分配了太多的内存,它很可能会变得越来越慢,以寻找新的内存。如果你释放它时,完成它,它运行良好,并结束:

  1. **** 7.957e+06
  2. 1.50212e+42

字符串
这是我对你的程序所做的唯一更改:

  1. double Ninj(double Q0, double p, double gamma_min, double gamma_max) {
  2. struct Ninj_Params params = {
  3. .p = 2.5,
  4. .Q0 = Q0,
  5. .gamma_m = gamma_min,
  6. };
  7. gsl_integration_workspace* w = gsl_integration_workspace_alloc(1000);
  8. double result, error;
  9. gsl_function F;
  10. F.function = &Q;
  11. F.params = &params;
  12. gsl_integration_qags(&F, gamma_min, gamma_max, 0, 1e-7, 1000, w, &result,
  13. &error);
  14. gsl_integration_workspace_free(w); // <- Add this
  15. return result;
  16. }

展开查看全部

相关问题