C++ 解决浮点舍入问题C++;
我开发了一个科学应用程序(模拟染色体在细胞核中移动)。染色体分成小片段,使用4x4旋转矩阵绕随机轴旋转 问题是,模拟执行了数千亿次旋转,因此浮点舍入错误累积并呈指数增长,因此随着时间的推移,片段往往会“浮动”并与染色体的其余部分分离C++ 解决浮点舍入问题C++;,c++,scientific-computing,matrix-multiplication,floating-point-precision,C++,Scientific Computing,Matrix Multiplication,Floating Point Precision,我开发了一个科学应用程序(模拟染色体在细胞核中移动)。染色体分成小片段,使用4x4旋转矩阵绕随机轴旋转 问题是,模拟执行了数千亿次旋转,因此浮点舍入错误累积并呈指数增长,因此随着时间的推移,片段往往会“浮动”并与染色体的其余部分分离 我使用双精度C++。该软件目前在CPU上运行,但将为CUDA移植,模拟最多可以持续1个月 我不知道我如何能以某种方式重新规范化染色体,因为所有片段都链接在一起(你可以把它看作一个双链表),但我认为如果可能的话,这将是最好的主意 你有什么建议吗?我觉得有点失落 多谢各
我使用双精度C++。该软件目前在CPU上运行,但将为CUDA移植,模拟最多可以持续1个月
我不知道我如何能以某种方式重新规范化染色体,因为所有片段都链接在一起(你可以把它看作一个双链表),但我认为如果可能的话,这将是最好的主意 你有什么建议吗?我觉得有点失落 多谢各位 H 编辑: 添加了一个简化的示例代码。 您可以假设所有矩阵数学都是经典的实现// Rotate 1000000 times
for (int i = 0; i < 1000000; ++i)
{
// Pick a random section start
int istart = rand() % chromosome->length;
// Pick the end 20 segments further (cyclic)
int iend = (istart + 20) % chromosome->length;
// Build rotation axis
Vector4 axis = chromosome->segments[istart].position - chromosome->segments[iend].position;
axis.normalize();
// Build rotation matrix and translation vector
Matrix4 rotm(axis, rand() / float(RAND_MAX));
Vector4 oldpos = chromosome->segments[istart].position;
// Rotate each segment between istart and iend using rotm
for (int j = (istart + 1) % chromosome->length; j != iend; ++j, j %= chromosome->length)
{
chromosome->segments[j].position -= oldpos;
chromosome->segments[j].position.transform(rotm);
chromosome->segments[j].position += oldpos;
}
}
//旋转1000000次
对于(int i=0;i<1000000;++i)
{
//选择一个随机段开始
int istart=rand()%染色体->长度;
//进一步拾取末端20段(循环)
int iend=(istart+20)%染色体->长度;
//构建旋转轴
向量4轴=染色体->片段[istart]。位置-染色体->片段[iend]。位置;
axis.normalize();
//建立旋转矩阵和平移向量
矩阵4旋转(轴,rand()/浮动(rand_MAX));
Vector4 oldpos=染色体->片段[istart]。位置;
//使用rotm在istart和iend之间旋转每个段
对于(int j=(istart+1)%chromose->length;j!=iend;++j,j%=chromose->length)
{
染色体->片段[j].位置-=oldpos;
染色体->片段[j].位置.变换(rotm);
染色体->片段[j].位置+=oldpos;
}
}
编写公式,使timestepT
的数据不完全来自timestepT-1
中的浮点数据。尽量确保浮点错误的产生仅限于一个时间步
如果没有更具体的问题要解决,很难说得更具体。我认为这取决于您使用的编译器 VisualStudio编译器支持/fp开关,该开关指示浮点操作的行为
你可以。基本上,/fp:strict是最苛刻的模式我想这取决于所需的精度,但您可以使用基于“整数”的浮点数。使用这种方法,您可以使用整数并为小数位数提供自己的偏移量 例如,如果精度为4个小数点,则 浮点值->整数值 1.0000 -> 10000 1.0001 -> 10001 0.9999->09999 在进行乘法和除法运算时必须小心,在应用精度偏移时也必须小心。另一方面,您可以快速获得溢出错误
1.0001*1.0001变为10001*10001/10000问题描述相当模糊,因此这里有一些相当模糊的建议 备选案文1: 找到一些约束集,以便(1)它们应该始终保持不变,(2)如果它们失败,但只是,很容易调整系统,使其保持不变,(3)如果它们都保持不变,则您的模拟不会变得非常疯狂,(4)当系统开始疯狂时,约束开始失败,但只是略微失败。例如,也许染色体相邻位之间的距离最多应该是d,对于某些d,如果其中一些距离略大于d,那么你可以(例如)从染色体的一端沿着染色体走,通过将下一个片段移向它的前一个片段来修复过大的距离,以及它的所有继任者。或者别的什么 然后经常检查约束条件,以确保任何违规行为在被抓获时仍然很小;当你发现违规行为时,就把事情解决。(您可能应该安排,当您解决问题时,您“完全满足”了约束。) 如果一直检查约束比较便宜,那么当然可以这样做。(这样做还可以使您以更低廉的成本进行修复,例如,如果这意味着任何违规行为总是很小的话。) 备选案文2: 找到一种描述系统状态的新方法,使问题不可能出现。例如,也许(我对此表示怀疑)您可以为每对相邻的片段存储一个旋转矩阵,并强制它始终为正交矩阵,然后让片段的位置由这些旋转矩阵隐式确定 备选案文3:
不要将约束视为约束,而是提供一些小的“恢复力”,这样当某件事情偏离了方向时,它就会朝着它应该的方向拉回。注意,当没有任何错误时,恢复力为零或至少可以忽略不计,以便它们不会比原始数值错误更严重地干扰结果。您需要为系统找到一些约束条件,并努力将其保持在合理的范围内。我做了一系列的分子碰撞模拟,在这些系统中,总能量是守恒的,所以每一步我都会仔细检查系统的总能量,如果它变化了一些阈值,那么我知道我的时间步长选择不当(太大或太小),我选择一个新的时间步长并重新运行它。这样我就可以实时跟踪系统发生的情况 对于这个模拟,我不知道你们有什么守恒量,但若你们有一个守恒量,你们可以试着保持不变。请记住,减小时间步长并不一定能提高精度,您需要根据您的精度优化步长。我已经进行了数周的数值模拟
t0 (x0,y0)
t1 (x0,y0) + (dx,dy) -> (x1, y1)
t2 (x1,y1) + (dx,dy) -> (x2, y2)
t3 (x2,y2) + (dx,dy) -> (x3, y3)
t4 (x3,30) + (dx,dy) -> (x4, y4)
...
t0 (x0, y0) (0, 0)
t1 (x0, y0) (0, 0) + (dx, dy) -> (x0, y0) (dx1, dy1)
t2 (x0, y0) (dx1, dy1) + (dx, dy) -> (x0, y0) (dx2, dy2)
t3 (x0, y0) (dx2, dy2) + (dx, dy) -> (x0, y0) (dx3, dy3)