Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中针对特定库进行链接时,在运行时丢失精度_C_Precision - Fatal编程技术网

在C中针对特定库进行链接时,在运行时丢失精度

在C中针对特定库进行链接时,在运行时丢失精度,c,precision,C,Precision,我有一个有点奇怪的问题,我不知道如何解决 我有一个程序,它使用长双打来完成目前大部分的数学运算,到目前为止,它运行良好。最近我想使用MLAPACK,它是lapack的一个高精度版本,使用双双精度和四双精度类型来进行矩阵求解。不幸的是,当我链接到MLAPACK的库时,我在原始程序中失去了精度 例如,如果我只做两个数字的简单求和: long double a = 50000.55964442486829568679 long double b = 0.006514624142341807720

我有一个有点奇怪的问题,我不知道如何解决

我有一个程序,它使用长双打来完成目前大部分的数学运算,到目前为止,它运行良好。最近我想使用MLAPACK,它是lapack的一个高精度版本,使用双双精度和四双精度类型来进行矩阵求解。不幸的是,当我链接到MLAPACK的库时,我在原始程序中失去了精度

例如,如果我只做两个数字的简单求和:

long double a =  50000.55964442486829568679 
long double b =  0.006514624142341807720713032
当我没有链接到MLAPACK时,我得到了正确的长双

long double a + b = 50000.5661590490106374945
当我链接此库时,我得到:

long double a + b = 50000.56615904901264002547
也就是说,它们在双精度而不是长双精度方面有所不同

问题是,我不知道该如何着手找出导致这种变化的原因。我假设MLAPACK中一定有一个函数,它也是在原始程序中定义的,它调用了错误的函数,但是原始程序很大,不是我写的

代码是在linux系统上编译的,MLAPACK库与.so文件相链接,所有内容都使用相同版本的gcc/gfortran等进行编译

我肯定这不是最恰当的问题,但我真的不明白为什么会发生这种情况。。有什么想法可以从哪里开始寻找解决方案吗


干杯

我假设您是为Windows编译程序,是32位,而不是64位。如果您使用的是Microsoft Visual C,请在开始计算之前添加以下行:

_control87( _PC_64, _MCW_PC );    /* requires: #include <float.h> */
如果使用不同的编译器,则可能需要使用不同的函数

我有点怀疑你使用的是MSVC,因为它没有长双精度浮点类型。你到底在用什么

详细说明:

发生的情况是,CPU中的浮点单元的精度级别被MLAPACK库中的启动代码更改

x87 FPU可以在三种模式中运行:单精度24位精度、双精度53位精度和扩展精度64位精度,a/k/a长双精度。在Microsoft Visual C中,精度模式由_control_87内置函数设置;在编译器中可能会有所不同

通常,在C运行时库的启动代码中设置精度模式,无论何时构建C程序,都会包含该库。您的程序实际上不是从main开始的,而是从C运行时库中的其他入口点开始的。该入口点的代码将所有内容设置为C程序可以运行,然后调用主函数。如果您的程序通常具有长双精度,这意味着入口点函数必须调用_control87_PC_64,_MCW_PC来设置64位长双精度控制

那么,当您链接到MLAPACK时,为什么会发生变化呢?我猜MLAPACK是一个动态链接的DLL库,或者在某个时候它碰巧加载了一个DLL。DLL也有自己的C运行时库——它们比普通静态库更像是单独的可执行文件——特别是如果MLAPACK是用不同的编译器构建的,它将有一个不同的C运行时库,并有自己的启动代码。启动代码将x87 FPU设置为53位双精度

所以答案是:在开始计算之前,您需要确保调用_control87_PC_64、_MCW_PC或编译器上的任何等效程序,在程序中设置为长双精度。作为你做的第一件事之一,大体上做这件事是可以的。或者可能有必要先做一些涉及MLAPACK的事情,以确保MLAPACK完全启动。就像你可能会反转一个1x1矩阵,有点愚蠢,然后设置为64位精度-基本上你是在消除MLAPACK的C运行时库启动所造成的损害


注意:在Windows上,64位程序根本不使用x87浮点单元,因此它们从来没有长双精度。这就是为什么我假设您正在构建一个32位程序。如果这是Linux或Mac,我不知道发生了什么

你说的拉帕克使用双双和四双类型。为什么用“长双”而不是“双双”或“四双”?在MLAPACK中如何处理“long double”?您的文本类型为double。使用L后缀使它们成为长双精度-例如0.006514624142341807720713032LOh,因此这只是一个示例,实际情况是:长双精度batCheck=psr[p].obsn[i].sat;long double corrCheck=getCorrectionTTpsr[p].obsn+i/SECDAY+psr[p].obsn[i].correctionTT\U TB-psr[p].obsn[i].对流层延迟+psr[p].obsn[i];longdouble AddCorr=batCheck+corrCheck;这些只是与这3个术语相对应的数字。什么
对于这两种情况,LDBL_DIG in是否都设置为仅打印到标准输出?这是一样的吗?在这两种情况下,LDBL_DIG都是18,这听起来是对的?我相信使用MinGW-w64 GCC编译的64位程序确实具有扩展的长双精度计算精度,并且可以独立使用fp87 math。我相信你的说明只适用于MSVC编译器,我猜英特尔编译器也有扩展fp计算精度的选项。不幸的是,这是在linux系统上的抱歉应该这么说。所有的东西都是用gcc/g++/gfortran编译的,但是它是针对文件进行链接的。让我们假设发生了与我讨论的相同的事情-您只需要使用不同的函数。在Linux上读写精度控制有点困难,因为没有很好的宏来访问x87控制字的字段,但这是可以做到的。Read:首先,您需要编写代码来读取精度控件并使用_FPU_GETCW显示它。然后将该代码放入一个未与MLAPACK链接的普通程序中,并放入一个与MLAPACK链接的程序中。如果我的理论是正确的,你会看到第一个是扩展精度,第二个是双精度。如果问题是精度控制发生了变化,那么解决方法是使用_FPU_SETCW将精度控制显式设置为扩展精度。这与我在评论中描述的相同,只是我使用了_control87。