我正在尝试使用校园库(CUDA多个精度算术库)。我已经下载了代码,并将其包含在我的项目中。由于它支持CPU和GPU,因此我从CPU开始,以了解其工作原理,并确保它可以完成我的需求。但目的是将其与Cuda一起使用。
我能够实例化实例并分配一个值,但是我不知道如何恢复物品。考虑:
#include <time.h>
#include "c:\vss\CAMPARY\Doubles\src_cpu\multi_prec.h"
int main()
{
const char *value = "123456789012345678901234567";
multi_prec<2> a(value);
a.prettyPrint();
a.prettyPrintBin();
a.prettyPrintBin_UnevalSum();
char *cc = a.prettyPrintBF();
printf("n%sn", cc);
free(cc);
}
编译,链接,运行(vs 2017)。但是输出是无助的:
Prec = 2
Data[0] = 1.234568e+26
Data[1] = 7.486371e+08
Prec = 2
Data[0] = 0x1.987bf7c563caap+86;
Data[1] = 0x1.64fa5c3800000p+29;
0x1.987bf7c563caap+86 + 0x1.64fa5c3800000p+29;
1.234568e+26 7.486371e+08
打印这样的双打可能很容易做到,但是它并没有太多告诉您要存储的128号码的值。如果无法输出结果,则执行高度精确的计算是有限的。
除了打印价值外,最终我还需要将这些数字转换为INT(如果有一种打印的方法,我愿意在浮标中尝试所有,但我担心准确性和速度会受到影响)。与Mpir(不支持CUDA)不同,校园没有任何相关的多精确INT类型,而只有漂浮。我可能可以将我需要的东西拼凑在一起(主要是添加/减去/比较),但是前提是我可以将校园价值的整数部分恢复出来,而我看不到这一点。
校园似乎没有任何文档,因此可以想象这些功能就在那里,我只是忽略了它们。我宁愿在校园讨论论坛/邮件列表中询问,但似乎没有一个。这就是为什么我在这里问。
总结:
- 有什么方法可以从校园输出128位(
multi_prec<2>
)值? - 有什么方法可以从校园多_PREC中提取整数部分?也许我不理解的库中(许多)数学功能之一计算了?
实际上只有2个可能的答案:
- 有另一个在CUDA上有效的(更好的)多精确库,可以实现您需要的工作。
- 这是修改此库的方法以完成您需要的工作。
唯一可以给出第一个答案的人是CUDA程序员。不幸的是,如果有这样的图书馆,我会感到自信会知道并提到它。
至于#2,如果不是CUDA程序员,为什么有人会更新此库?还有其他更好的多次库库。唯一的好处是校园支持CUDA。这意味着唯一具有与图书馆合作或修改的真正动机的人是CUDA程序员。
,作为解决此问题最既得利益的CUDA程序员,我确实找出了一个解决方案(尽管是一个丑陋的解决方案)。我在这里发布它,希望这些信息对未来的校园程序员有价值。该库的信息不多,所以这是一个开始。
您需要了解的第一件事是校园如何存储其数据。而且,虽然并不复杂,但这并不是我所期望的。来自麦普尔
但是,不,校园的发展方式不同。查看代码,我们看到:
private:
double data[prec];
现在,我以为这只是保留所需位数的任意方式。但是不,他们确实确实使用了prec
双打。喜欢:
multi_prec<8> a("2633716138033644471646729489243748530829179225072491799768019505671233074369063908765111461703117249");
// Looking at a in the VS debugger:
[0] 2.6337161380336443e+99 const double
[1] 1.8496577979210756e+83 const double
[2] 1.2618399223120249e+67 const double
[3] -3.5978270144026257e+48 const double
[4] -1.1764513205926450e+32 const double
[5] -2479038053160511.0 const double
[6] 0.00000000000000000 const double
[7] 0.00000000000000000 const double
因此,他们正在做的是将最大精度存储在第一个双人双重上,然后使用其余的来计算下一个双重,依此类推,依此最不重要的位)。请注意,其中一些是负的,这意味着前面值的总和比实际值大一些,它们正在向下校正。
考虑到这一点,我们回到了如何打印它的问题。
从理论上讲,您只需将所有这些添加在一起即可获得正确的答案。但是从定义上讲,我们已经知道C没有数据类型可以保持此大小的值。但是其他图书馆确实(例如Miper)。现在,Mpir在CUDA上不起作用,但不需要。您不想让您的CUDA代码打印出数据。无论如何,这都是您应该从主机那里做的事情。因此,使用CUDA的全部功能,cudamemcpy的计算也是如此,然后使用MPIR将其打印出来:
#define MPREC 8
void ShowP(const multi_prec<MPREC> value)
{
multi_prec<MPREC> temp(value), temp2;
// from mpir at mpir.org
mpf_t mp, mp2;
mpf_init2(mp, value.getPrec() * 64); // Make sure we reserve enough room
mpf_init(mp2); // Only needs to hold one double.
const double *ptr = value.getData();
mpf_set_d(mp, ptr[0]);
for (int x = 1; x < value.getPrec(); x++)
{
// MPIR doesn't have a mpf_add_d, so we need to load the value into
// an mpf_t.
mpf_set_d(mp2, ptr[x]);
mpf_add(mp, mp, mp2);
}
// Using base 10, write the full precision (0) of mp, to stdout.
mpf_out_str(stdout, 10, 0, mp);
mpf_clears(mp, mp2, NULL);
}
与上面的Multi_prec中存储的数字一起使用,这将输出完全相同的值。是的。
这不是一个特别优雅的解决方案。必须添加第二个库来打印第一个值,这显然是最佳的。而且这种转换也不是那么快。但是打印通常比计算频率少。如果您进行一个小时的计算价值和少量印刷品,则性能并不重要。而且它完全无法打印出来。
校园有很多缺点(不在意,不支持,未受欢迎)。但是对于在CUDA上需要MP号码的人(尤其是如果您需要SQRT),这是我找到的最好的选择。