You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双摆代码运行后瞬间消失,变量返回NaN值的原因排查求助

解决双摆瞬间消失并出现NaN值的问题

我来帮你排查这个问题,你的双摆显示一瞬间就消失,之后变量出现NaN,核心问题出在角度转弧度的错误处理,以及数值计算中的几个关键细节上,下面一步步分析并修复:

问题根源分析

  1. 错误的角度转弧度逻辑
    你在convDeg函数里把180度直接返回0,这完全违背了弧度转换的数学逻辑——180度对应的弧度是M_PI,不是0。这个错误会直接导致三角函数(sin/cos)计算出完全错误的值,进而让后续的加速度、速度计算出现异常,很快就会产生NaN。

  2. 未对角度进行模运算
    双摆的角度a1和a2会随着循环不断累加,数值会越来越大,最终超出三角函数的有效计算范围,导致计算结果异常。

  3. 分母可能为0的风险
    计算den的表达式里有cos(convDeg(2*a1-2*a2)),如果角度差对应的余弦值恰好让分母为0,除法运算就会直接产生NaN,而错误的弧度转换会更快触发这个情况。

修复后的代码及解释

下面是修改后的完整代码,我会标注关键修改点:

#undef __STRICT_ANSI__ 
#include "window.h" 
#include <SFML/Graphics.hpp> 
#include <GL/glew.h> 
#include <cmath> 
#include <iostream> 

namespace Window { 
sf::ContextSettings settings; 
sf::RenderWindow window(sf::VideoMode(600, 600), "Window", sf::Style::Close | sf::Style::Titlebar, settings); 

void init() { 
    settings.depthBits = 24; 
    settings.majorVersion = 4; 
    settings.minorVersion = 6; //OpenGL 4.6 
    glewInit(); 
    glViewport(0,0, 600, 600); 
} 

void close() { 
    window.close(); 
} 

void update() { 
    window.display(); 
} 

void checkForClose() { 
    sf::Event windowEvent; 
    while (window.pollEvent(windowEvent)) { 
        if (windowEvent.type == sf::Event::Closed) { 
            close(); 
        } 
    } 
} 

bool isOpen() { 
    return window.isOpen(); 
} 

// 修复1:正确的角度转弧度函数,移除错误的180度判断
double convDeg(double deg) { 
    return deg * M_PI / 180.0; 
} 

// 新增:将角度限制在0-360度范围内,避免数值溢出
double clampAngle(double deg) {
    double clamped = fmod(deg, 360.0);
    if (clamped < 0) clamped += 360.0;
    return clamped;
}

void runLoop() { 
    double r1 = 100; 
    double m1 = 40; 
    double a1 = 90; 
    double a1_v = 0; 
    double r2 = 100; 
    double m2 = 40; 
    double a2 = 30; 
    double a2_v = 0; 
    double x1 = 0; 
    double x2 = 0; 
    double y1 = 0; 
    double y2 = 0; 
    double g = 0.005; 
    double num1 = 0; 
    double num2 = 0; 
    double num3 = 0; 
    double num4 = 0; 
    double den = 0; 
    double a1_a = 0; 
    double a2_a = 0; 

    while (window.isOpen()) { 
        // 修复2:先对角度做模运算,避免数值过大
        a1 = clampAngle(a1);
        a2 = clampAngle(a2);

        // 所有弧度转换使用正确的convDeg函数
        num1 = -g * (2 * m1 + m2) * std::sin(convDeg(a1)); 
        num2 = -m2 * g * std::sin(convDeg(a1 - 2*a2)); 
        num3 = -2 * std::sin(convDeg(a1 - a2)) * m2; 
        num4 = a2_v*a2_v*r2 + a1_v*a1_v*r1 * std::cos(convDeg(a1 - a2)); 
        den = r1 * (2*m1 + m2 - m2 * std::cos(convDeg(2*a1 - 2*a2))); 

        // 修复3:添加分母非零判断,避免除以0产生NaN
        if (std::fabs(den) > 1e-6) {
            a1_a = (num1 + num2 + num3*num4) / den; 
        } else {
            a1_a = 0; // 分母接近0时,暂时将加速度设为0
        }

        num1 = 2 * std::sin(convDeg(a1 - a2)); 
        num2 = (a1_v*a1_v*r1*(m1 + m2)); 
        num3 = g * (m1 + m2) * std::cos(convDeg(a1)); 
        num4 = a2_v*a2_v*r2*m2 * std::cos(convDeg(a1 - a2)); 
        den = r2 * (2*m1 + m2 - m2 * std::cos(convDeg(2*a1 - 2*a2))); 

        // 同样添加分母非零判断
        if (std::fabs(den) > 1e-6) {
            a2_a = (num1*(num2 + num3 + num4)) / den; 
        } else {
            a2_a = 0;
        }

        x1 = 300 + (r1 * std::sin(convDeg(a1))); 
        y1 = 300 + (r1 * std::cos(convDeg(a1))); 
        x2 = x1 + (r2 * std::sin(convDeg(a2))); 
        y2 = y1 + (r2 * std::cos(convDeg(a2))); 

        a1_v += a1_a; 
        a2_v += a2_a; 
        a1 += a1_v; 
        a2 += a2_v; 

        sf::Vertex pOne[] = { 
            sf::Vertex(sf::Vector2f(300,300)), 
            sf::Vertex(sf::Vector2f(x1,y1)), 
        }; 
        sf::Vertex pTwo[] = { 
            sf::Vertex(sf::Vector2f(x1,y1)), 
            sf::Vertex(sf::Vector2f(x2,y2)), 
        }; 

        window.clear(); 
        window.draw(pOne, 2, sf::Lines); 
        window.draw(pTwo, 2, sf::Lines); 
        update(); 
        checkForClose(); 

        // 可以保留调试输出,观察数值变化
        // std::cout << std::sin(convDeg(a1)) << "\n"; 
    } 
} 
} 

关键修改说明

  1. 修正convDeg函数:移除了错误的180度判断,严格按照数学公式进行弧度转换,这是解决问题的核心。
  2. 新增角度模运算函数clampAngle:将角度限制在0-360度范围内,避免角度数值无限累加导致三角函数计算异常。
  3. 添加分母非零判断:在计算加速度前检查分母的绝对值是否大于一个极小值(1e-6),如果接近0则将加速度设为0,避免除以0产生NaN。
  4. 保留原有绘图逻辑:确保每次循环都重新绘制双摆,避免显示异常。

经过这些修改后,双摆应该能正常持续运动,不会再出现瞬间消失和NaN的问题了。

内容的提问来源于stack exchange,提问作者Don

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:07:39