C-双精度指针与双精度数组之间的细微差别。将一个转换为另一个?
|
我一直在为物理研究项目开发程序。该程序是用C语言编写的,但是使用了fortran函数(它称为\“ zgesv \”,它来自LAPACK和BLAS库)。
这个想法是要解决一个方程组。 LHS.X =向量“ X”的RHS。 int INFO传递给zgesv。如果这些方程无法求解(即LHS是奇异的),则info应该返回值= 0;否则返回0。
通过将double *传递给Solve函数(以下代码中的解决方案1),尝试以“正常”的方式运行程序,即使LHS是单数,INFO也返回0。不仅如此,而且如果我打印出解决方案,那将是数字的灾难-有些小,有些零,有些大。
如果我通过手动创建LHS和RHS
LHS [] = {值1,值2,...};
RHS [] = {值1,值2,...};
然后将INFO作为预期值返回3,并且解决方案等于RHS(这也是我所期望的)。
如果我声明数组
LHS2 [] = {值1,值2,...};
RHS2 [] = {值1,值2,...};
并将它们逐个复制到LHS和RHS中,然后将INFO返回为8(对我来说,这与以前的情况不同是很奇怪的。),解决方案等于RHS。
我觉得这肯定是声明数组的两种方式之间的根本区别。我真的无法使用zgesv函数来使muck成为我想要的类型,因为A)它是科学界的标准,并且B)它是用fortran编写的-我还没有从来没有学过。
谁能解释这是怎么回事?是否有一个简单的(最好是计算便宜的)修复程序?我是否应该将我的double *复制到array []中?
这是我的程序(为测试而修改):
包括
#include <stdlib.h>
#include <math.h>
#define PI 3.1415926535897932384626433832795029L
#define ERROR_VALUE 911.911
int* getA(int N, char* argv[])
{
int i;
int* AMatrix;
AMatrix = malloc(N * N * sizeof(int));
if (AMatrix == NULL)
{
printf(\"Failed to allocate memory for AMatrix. Exiting.\");
exit (EXIT_FAILURE);
}
for (i = 0; i < N * N; i++)
{
AMatrix[i] = atoi(argv[i + 1]);
}
return AMatrix;
}
double* generateLHS(int N, int* AMatrix, int TAPs[], long double kal)
{
double S, C;
S = sinl(kal);
C = cosl(kal);
printf(\"According to C, Sin(Pi/2) = %.25lf and Cos(Pi/2) = %.25lf\", S, C);
// S = 1;
// C = 0;
double* LHS;
LHS = malloc(N * N * 2 * sizeof(double));
if (LHS == NULL)
{
printf(\"Failed to allocate memory for LHS. Exiting.\");
exit (EXIT_FAILURE);
}
int i;
for (i = 0; i < N * N; i++)
{
LHS[2 * i] = -1 * AMatrix[i];
LHS[(2 * i) + 1] = 0;
}
for (i = 0; i <= 2 * N * N - 2; i = i + (2 * N) + 2)
{
LHS[i] = LHS[i] + (2 * C);
}
int j;
for (i = 0; i <= 3; i++)
{
j = 2 * N * TAPs[i] + 2 * TAPs[i];
LHS[j] = LHS[j] - C;
LHS[j + 1] = LHS[j + 1] - S;
}
return LHS;
}
double* generateRHS(int N, int inputTailAttachmentPoint, long double kal)
{
double* RHS;
RHS = malloc(2 * N * sizeof(double));
int i;
for (i = 0; i < 2 * N; i++)
{
RHS[i] = 0.0;
}
RHS[2 * inputTailAttachmentPoint + 1] = - 2 * sin(kal);
return RHS;
}
double* solveUsingLUD(int N, double* LHS, double* RHS)
{
int INFO; /*Info is changed by ZGELSD to 0 if the computation was carried out successfully. Else it changes to some none-zero integer. */
int ione = 1;
int LDA = N;
int LDB = N;
int n = N;
int* IPV = malloc(N * sizeof(int));
if (IPV == NULL)
{
printf(\"Failed to allocate memory for IPV. Exiting.\");
exit (EXIT_FAILURE);
}
zgesv_(&n, &ione, LHS, &LDA, IPV, RHS, &LDB, &INFO);
free(IPV);
if (INFO != 0)
{
printf(\"\\n ERROR: info = %d\\n\", INFO);
}
return RHS;
}
void printComplexVectors(int numberOfRows, double* matrix)
{
int i;
for (i = 0; i < 2 * numberOfRows - 1; i = i + 2)
{
printf(\"%f + %f*i \\n\", matrix[i], matrix[i + 1]);
}
printf(\"\\n\");
}
int main(int argc, char* argv[])
{
int N = 8;
int* AMatrix;
AMatrix = getA(N, argv);
int TAPs[]={4,4,4,3};
long double kal = PI/2;
double *LHS, *RHS;
LHS = generateLHS(N, AMatrix, TAPs,kal);
int i;
RHS = generateRHS(N, TAPs[0],kal);
printf(\"\\n LHS = \\n{{\");
for (i = 0; i < 2 * N * N - 1;)
{
printf(\"%lf + \", LHS[i]);
i = i + 1;
printf(\"%lfI\", LHS[i]);
i = i + 1;
if ((int)(.5 * i) % N == 0)
{
printf(\"},\\n{\");
}
else
{
printf(\",\");
}
}
printf(\"}\");
double LHS2[] = {0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-0.000000,-3.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.00000};
double RHS2[] ={0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-2.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000};
printf(\"comparing LHS and LHS2\\n\");
for (i = 0; i < 2 * N * N;)
{
if (LHS[i] != LHS2[i]) {
printf( \"LHS difference at index %d\\n\", i);
printf(\"LHS[%d] = %.16lf\\n\", i, LHS[i]);
printf(\"LHS2[%d] = %.16lf\\n\", i, LHS2[i]);
printf(\"The difference is %.16lf\\n\", LHS[i] - LHS2[i]);
}
i = i + 1;
}
printf(\"\\n\");
printf(\"comparing RHS and RHS2\\n\");
for (i = 0; i < 2 * N;)
{
if (RHS[i] != RHS2[i]) {
printf( \"RHS difference at index %d\\n\", i);
printf(\"RHS[%d] = %.16lf\\n\", i, RHS[i]);
printf(\"RHS2[%d] = %.16lf\\n\", i, RHS2[i]);
printf(\"The difference is %.16lf\", RHS[i] - RHS2[i]);
}
i = i + 1;
}
printf(\"\\n\");
double *solution;
solution = solveUsingLUD(N,LHS,RHS);
printf(\"\\n Solution = \\n{\");
for (i = 0; i < 2 * N - 1;)
{
printf(\"{%.16lf + \", solution[i]);
i = i + 1;
printf(\"%.16lfI},\", solution[i]);
i = i + 1;
printf(\"\\n\");
}
solution = solveUsingLUD(N,LHS2,RHS2);
printf(\"Solution2 = \\n{\");
for (i = 0; i < 2 * N - 1;)
{
printf(\"{%lf + \", solution[i]);
i = i + 1;
printf(\"%lfI},\", solution[i]);
i = i + 1;
printf(\"\\n\");
}
for (i = 0; i < 2 * N * N;)
{
LHS[i] = LHS2[i];
i = i + 1;
}
for (i = 0; i < 2 * N;)
{
RHS[i] = RHS2[i];
i = i + 1;
}
solution = solveUsingLUD(N,LHS,RHS);
printf(\"Solution3 = \\n{\");
for (i = 0; i < 2 * N - 1;)
{
printf(\"{%lf + \", solution[i]);
i = i + 1;
printf(\"%lfI},\", solution[i]);
i = i + 1;
printf(\"\\n\");
}
return 0;
}
我用编译行
gcc -lm -llapack -lblas PiecesOfCprogarm.c -Wall -g
我执行:
./a.out 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0
给出输出
According to C, Sin(Pi/2) = 1.0000000000000000000000000 and Cos(Pi/2) = -0.0000000000000000000271051
LHS =
{{-0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I},
{0.000000 + 0.000000I,-0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I},
{0.000000 + 0.000000I,0.000000 + 0.000000I,-0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I},
{0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-0.000000 + -1.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I},
{-1.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + -3.000000I,0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I},
{-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-0.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I},
{0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,0.000000 + 0.000000I,-0.000000 + 0.000000I,0.000000 + 0.000000I},
{0.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,-1.000000 + 0.000000I,0.000000 + 0.000000I,0.000000 + 0.000000I,-0.000000 + 0.000000I},
{}comparing LHS and LHS2
LHS difference at index 0
LHS[0] = -0.0000000000000000
LHS2[0] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 18
LHS[18] = -0.0000000000000000
LHS2[18] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 36
LHS[36] = -0.0000000000000000
LHS2[36] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 54
LHS[54] = -0.0000000000000000
LHS2[54] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 72
LHS[72] = 0.0000000000000000
LHS2[72] = -0.0000000000000000
The difference is 0.0000000000000000
LHS difference at index 90
LHS[90] = -0.0000000000000000
LHS2[90] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 108
LHS[108] = -0.0000000000000000
LHS2[108] = 0.0000000000000000
The difference is -0.0000000000000000
LHS difference at index 126
LHS[126] = -0.0000000000000000
LHS2[126] = 0.0000000000000000
The difference is -0.0000000000000000
comparing RHS and RHS2
Solution =
{{1.0000000000000000 + -0.0000000000000000I},
{-1.0000000000000000 + -0.0000000000000000I},
{-0.0000000000000000 + 0.0000000000000000I},
{-0.0000000000000000 + 0.0000000000000000I},
{0.6000000000000000 + 0.2000000000000000I},
{-0.0000000000000000 + -0.0000000000000000I},
{-6854258945071195.0000000000000000 + 4042255275298396.0000000000000000I},
{6854258945071195.0000000000000000 + -4042255275298396.0000000000000000I},
ERROR: info = 3
Solution2 =
{{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + -2.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
ERROR: info = 8
Solution3 =
{{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + -2.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
{0.000000 + 0.000000I},
没有找到相关结果
已邀请:
4 个回复
师埠女
不能精确地表示为
。因此ѭ6都不是。 因此,
和
不必分别等于1或0。 (如果要通过将它们分配给\“ int \”来解决此问题,请记住,进行这种转换时C通常会四舍五入。) [编辑] 其实我有一个更好的建议... 使用GCC编译Fortran代码时,您可能要使用
。 Fortran代码通常在编写时非常注意双精度数字的量化...但是默认情况下,x86上的中间值可以具有更高的精度(因为浮点单元内部使用80位)。通常,额外的精度只会有所帮助,但是对于某些数字敏感的代码(例如sin(PI / 2)),它可能会导致意外结果。
避免了这种额外的精度。 [编辑2,回应评论] 为了获得更好的正弦和余弦精度,我建议以下几点。 首先,在
和其他函数的参数列表中,将
声明为
。 其次,调用
和
而不是
和
。 第三,像这样定义PI:
将其他所有内容(尤其是
和
)保留为
。看看是否有帮助...
砷竣阿
这声明了一个返回
的函数,但您正在返回
。添加返回类型,看看是否有任何变化。 编辑: 在澄清之后,仍然存在一些缺陷-由于这一行,代码仍无法编译:
缺少开头评论。 另外,您还要将sin()和cos()的结果分配给整数变量(默认情况下C和S为整数):
从您的代码来看,这不是您想要的。 最后要注意的是,在
中缺少最后一个元素(
为127,而不是
= 128)。这意味着您正在读取和写入超出数组末尾的数组,这将导致不确定的行为并可能导致您看到的问题。 编辑2: 还有一件事:您正在读取函数getA()中的
,该函数始终是可执行文件的路径。您应该从
开始阅读。为了安全起见,应检查用户是否提供了足够的参数(
)。
稍惮
存储矩阵,并使用
调用LAPACK调用(其中A是
),它可以工作。我的理解(也许太天真了)是标准库向量是“有点像” C数组,因此,我想可以将其直接转换为C。 另外,您使用的是复杂的例程,这些例程可能以微妙的方式更改,也可能不会更改。我猜想Fortran的COMPLEX * 16等于
最后,可以从netlib处获得LAPACK例程的参考实现,请参见http://www.netlib.org/lapack/complex16/zgesv.f。
翱抹村
和/或
内生成的
值具有很小的误差,当用
显示它们时显示为零(或小数部分至少为零),但是差异会影响
的计算。 您可以在
和
的声明之后尝试将这些循环添加到测试运行中吗: