加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

解决浮点问题C

发布时间:2020-12-16 05:36:59 所属栏目:百科 来源:网络整理
导读:我开发了一个科学应用(模拟染色体在细胞核中移动).染色体被划分成使用4×4旋转矩阵围绕随机轴旋转的小碎片. 问题是仿真执行了数百亿次旋转,因此浮点舍入误差叠加并呈指数增长,因此随着时间的流逝,碎片往往会“浮起”并脱离染色体的其余部分. 我用C双精度.软
我开发了一个科学应用(模拟染色体在细胞核中移动).染色体被划分成使用4×4旋转矩阵围绕随机轴旋转的小碎片.

问题是仿真执行了数百亿次旋转,因此浮点舍入误差叠加并呈指数增长,因此随着时间的流逝,碎片往往会“浮起”并脱离染色体的其余部分.

我用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;
    }
}

解决方法

您需要为您的系统找到一些约束,并努力将其保持在一定的合理范围内.我做了一系列的分子碰撞模拟,在这些系统中,总能量是保守的,所以每一步我都仔细检查系统的总能量,如果它变化一些阈值,那么我知道我的时间步长很差(太大或太小),我选择一个新的时间步骤并重新运行.这样我就可以实时跟踪系统发生了什么.

对于这种模拟,我不知道你有多少保存的数量,但是如果你有一个,你可以尝试保持这个常数.记住,让你的时间步长更小,并不总是提高精度,你需要用你所拥有的精度来优化步长.我已经进行了数周模拟运行了几个星期的CPU时间,保存的数量总是在10分之1的1分之内,所以有可能,你只需要玩一些.

另外,正如Tomalak所说,也许试图总是将您的系统引用到开始时间,而不是上一步.所以,而不是总是移动你的染色体,保持染色体在他们的起始位置,并与他们存储一个转换矩阵,使您到当前位置.当您计算新的旋转时,只需修改转换矩阵.这可能看起来很愚蠢,但有时这样做很好,因为错误平均为0.

例如,让我说我有一个位于(x,y)和我计算的每一步(dx,dy)并移动粒子的粒子.逐步的方式会这样做

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,你可以这样做

t0 (x0,y0) (0,0)
t1 (x0,0) + (dx,dy) -> (x0,y0) (dx1,dy1)
t2 (x0,dy1) + (dx,y0) (dx2,dy2)
t3 (x0,dy2) + (dx,y0) (dx3,dy3)

所以在任何时候,要获得你真正的职位,你必须做(x0,y0)(dxn,dyn)

现在简单的翻译像我的例子,你可能不会赢得很多.但是为了旋转,这可以是一个救命.只需保留与每个染色体相关联的欧拉角度的矩阵,并更新而不是染色体的实际位置.至少这样他们不会漂浮.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读