基本的小乌龟MoveTo错误“对于小数,值太大或太小。”

时间:2018-10-07 22:08:25

标签: turtle-graphics smallbasic

此代码似乎引发异常“值对于小数而言太大或太小。”

以某种方式更改变量y1,y2,x可消除错误。 例如,y2从41到38。

我该如何解决?

Turtle.Speed = 10
x = 10
y1 = 42
y2 = 41
Turtle.Angle = 180
Turtle.MoveTo(x, y2)
Turtle.MoveTo(x, y1)

错误跟踪:

in System.Decimal..ctor(Double value)
in System.Decimal.op_Explicit(Double value)
in Microsoft.SmallBasic.Library.Primitive.op_Implicit(Double value)
in Microsoft.SmallBasic.Library.Turtle.MoveTo(Primitive x, Primitive y)
in _SmallBasicProgram._Main()

在1.0和1.2版本中都是相同的。

1 个答案:

答案 0 :(得分:1)

问题在于SmallBasic(在1.2版中)从双精度的原始实现存在缺陷。这是将double转换为Primitive的方法。

new Primitive((Decimal) primitiveDouble);

但是,这是一个 unsafe 操作,因为并非(精确)表示double的所有值。在这些情况下,强制转换为小数将引发异常。

这是在C#中重现此类异常的简单方法:

double x = double.MinValue; // [smallest] denormalized value
decimal f = (decimal)x;

这发生在MoveTo(x,y)操作中,该操作执行三角数学运算将MoveTo转换为Turn + Move的组合。对于某些输入(以及乌龟所在的位置),这将导致无法(安全地)转换为十进制值的双精度数。

明确使用Turn + Move 将避免出现问题的数学运算,因此至少在这种情况下应避免出现该问题。

作为参考,这是MoveTo的反编译源:

/// <summary>
/// Turns and moves the turtle to the specified location.  If the pen is down, it will draw a line as it moves.
/// </summary>
/// <param name="x">The x co-ordinate of the destination point.</param>
/// <param name="y">The y co-ordinate of the destination point.</param>
public static void MoveTo(Primitive x, Primitive y)
{
  double d = (double) ((x - Turtle.X) * (x - Turtle.X) + (y - Turtle.Y) * (y - Turtle.Y));
  if (d == 0.0)
    return;
  double num1 = System.Math.Sqrt(d);
  double num2 = System.Math.Acos((double) (Turtle.Y - y) / num1) * 180.0 / System.Math.PI;
  if ((bool) (x < Turtle.X))
    num2 = 360.0 - num2;
  double num3 = num2 - (double) ((int) Turtle.Angle % 360);
  if (num3 > 180.0)
    num3 -= 360.0;
  Turtle.Turn((Primitive) num3); // goes boom here..
  Turtle.Move((Primitive) num1); // ..or here
}