C#:使用大于 30 亿的数字进行计算将返回 NaN



总的来说,我对C#和编程很陌生。我正在尝试计算直线和椭圆的交点。 当椭圆的半径大于 1f 时,代码按预期工作。

当半径(近似(小于 1f 时,"t" 返回 NaN。

我手动计算了这些数字,我注意到当半径下降到1f以下时,B * B = 30亿+。

我试图将"t"变成双精度,并且尝试使用System.Math而不是Mathf。 当半径<1f 时,"t" 仍返回 NaN。

任何反馈都非常感谢!

public static Vector2 GetEllipseOuterIntersection(Vector2 ellipseCentre, float radius, Vector2 lightDot, Vector2 objectDot) {
lightDot.x -= ellipseCentre.x;
lightDot.y -= ellipseCentre.y;
objectDot.x -= ellipseCentre.x;
objectDot.y -= ellipseCentre.y;
// Get the semiminor axis.
float vertRadius = radius/2;
// Calculate the quadratic parameters.
float A = (objectDot.x - lightDot.x) * (objectDot.x - lightDot.x) / radius / radius + (objectDot.y - lightDot.y) * (objectDot.y - lightDot.y) / vertRadius / vertRadius;
float B = 2 * lightDot.x * (objectDot.x - lightDot.x) / radius / radius + 2 * lightDot.y * (objectDot.y - lightDot.y) / vertRadius / vertRadius;
float C = lightDot.x * lightDot.x / radius / radius + lightDot.y * lightDot.y / vertRadius / vertRadius - 1;
double t = (-B + System.Math.Sqrt(B*B - (4*A*C))) / 2 / A;
print(t);
float x = (float) (lightDot.x + (objectDot.x - lightDot.x) * t + ellipseCentre.x);
float y = (float) (lightDot.y + (objectDot.y - lightDot.y) * t + ellipseCentre.y);
Vector2 outerIntersection = new Vector2(x, y);
return outerIntersection;
}

只要您的任何计算的任何组件都是NaN那么整个结果也将是一个NaN

NaN与数字增长到大无关(这会引发异常或行为意外 - 例如翻转到负值(。相反,它暗示在计算的某个点上,您正在创建一个数学上未定义的值。

当操作的结果未定义时,方法或运算符返回 NaN。例如,将零除以零的结果是 NaN,如以下示例所示。(但请注意,将非零数除以零返回正无穷大或负无穷大,具体取决于除数的符号。

除此之外,3 Billion * 3 Billion9E+24float的最大值是3.40282347E+38所以无论如何这都不是问题。

您可能在某处除以/ 0

例如,可能发生这种情况的地方是

  • 当你通过radius = 0

    因为在很多情况下,您都在

    除以/ radius
  • 当你通过radius = 2

    因为那时你以后在做

    vertRadius = radius / 2; 
    

    => 是 1,然后你做/ vertRadius - 1例如C

    所以vertRadius - 10

  • 如果A = 0

  • 如果objectDot.x - lightDot.x = 0

    因为那时ABC都是0

  • 如果B*B - 4*A*C = 0

    因为负数的平方根也是未定义的,而您确实

    System.Math.Sqrt(B*B - 4*A*C)
    

您应该拆分计算并添加检查,以使调试,读取和维护更容易,例如有点像

public static Vector2 GetEllipseOuterIntersection(Vector2 ellipseCentre, float radius, Vector2 lightDot, Vector2 objectDot) 
{
if(Mathf.Approximately(radius, 0))
{
Debug.LogError("radius may not be 0");
return default;
}
if(Mathf.Approximately(radius, 2))
{
Debug.LogError("radius may not be 2");
return default;
}
lightDot.x -= ellipseCentre.x;
lightDot.y -= ellipseCentre.y;
objectDot.x -= ellipseCentre.x;
objectDot.y -= ellipseCentre.y;
// Get the semiminor axis.
float vertRadius = radius/2;
var difX = objectDot.x - lightDot.x;
var difY = objectDot.y - lightDot.y;
if(Mathf.Approximately(difX, 0))
{
Debug.LogError("objectDot.x - lightDot.x may not be 0!");
return default;
}
if(Mathf.Approximately(difY, 0))
{
Debug.LogError("objectDot.y - lightDot.y may not be 0!");
return default;
}
var difXSqr = difX * difX;
var difYSqr = difY * difY;
var radiusSqr = radius * radius;
var vertRadiusSqr = vertRadius * vertRadius;
var lightDotXSqr = lightDot.x * lightDot.x;
var lightDotYSqr = lightDot.y * lightDot.y;
// Calculate the quadratic parameters.
float A = difXSqr / radiusSqrInverse + difYSqr / vertRadiusSqr;
float B = 2 * lightDot.x * difX / radiusSqr + 2 * lightDot.y * difY / vertRadiusSqr;
float C = lightDotXSqr / radiusSqr + lightDotYSqr / vertRadiusSqr - 1;
if(Mathf.Approximately(A, 0))
{
Debug.LogError("A may not be 0!");
return default;
}
double BSquare = B*B;
double AC4 = 4*A*C;
double DIF = BSquare - AC4;
if(DIF < 0)
{
Debug.LogError("DIF may not be negative!");
return default;
}
double t = (-B + System.Math.Sqrt(DIF)) / 2 / A;
print(t);
float x = (float) (lightDot.x + difX * t + ellipseCentre.x);
float y = (float) (lightDot.y + difY * t + ellipseCentre.y);
return new Vector2(x, y);
}

尝试改用长整型。

长值远高于整数。

// first number
long myLongNumber = 2345608830;
// second number
long secondLong = myLongNumber * 3;

第二长的结果:7036826490

编辑:我没有看到你需要小数。如果四舍五入到整数是一个问题,那么您可能需要其他解决方案。

最新更新