【问题标题】:C floats : how to go around them for 2d geometry (lines)C 浮动:如何绕过它们以获取 2d 几何(线)
【发布时间】:2017-03-16 13:50:33
【问题描述】:

我目前正在用 C 语言做一些 2D 几何,主要是线相交。这些线有各种各样的斜率:从 0.001 到 1000(例子,我什至不知道)。

到目前为止,我一直在使用浮点数,不必担心值是非常小(然后浮点会将 0,0011 存储为 1e-3 且不进行四舍五入)还是非常高(然后将存储 1001如 1e3),在这两种情况下,相关的精度损失都很少。

但现在我想尝试不使用浮点数,使用整数。如何在我的计算中保持精度?我可以有一个标志告诉我斜坡是大还是小,然后考虑十分之一的大斜坡和十倍的小斜坡,这样对于小斜坡来说四舍五入是没有问题的,在大斜坡的情况下也没有溢出.但这感觉很头疼。

基本上,我仍然需要能够区分 0.2 和 0.4 的斜率,并且在事物的溢出侧还有 1000 和 2000 的斜率(假设整数在 1000 处溢出 - 这里问题较少)。

还有其他想法吗?

【问题讨论】:

  • 除了存储上升和运行之外?
  • 使用double 并忍受不精确?为什么需要超过 15 位小数有效数字的准确度?这样的精度足以测量从这里到冥王星的距离(以厘米为单位)。
  • 在做计算几何时,总会有不精确的情况,因为总会有无理数。
  • @DavidBowling 注意:所有整数和有限浮点值都是有理数。确实,许多 int/float 计算与数学结果不同。
  • @chux——当然。我的观点是,通常(在 R^n 中)进行计算几何必须涉及无理数。例如,斜率 m = √2 的线不能以斜率截距形式或使用没有无理数的方向向量(即参数形式)表示。使用理性点的子集是避免这些困难的一种方法,但代价是限制了调查对象。我认为在这里管理不精确是不可避免的。虽然我认为这最终是一个目标问题。

标签: c floating-point integer precision computational-geometry


【解决方案1】:

斜率存储为一对整数

struct slope {
  int delta_y;
  int delta_x;
};

这允许像0+/- 1/INT_MAX ... +/- INT_MAX 这样的大范围斜坡,甚至是垂直的。通过仔细编码,可以进行精确的计算。

迟到的信用:这很像@Ignacio Vazquez-Abrams comment

【讨论】:

  • 这是个好主意,特别是如果您可以使用slope 实例而无需计算梯度。我可能会考虑让成员之一unsigned,但是说我猜你可以在构造上解决那种事情,因为你可能想要“规范化”输入(例如 {-2, -4} 是同 {1, 2})。
  • @Bathsheba 同意在unsignedint numerator; unsigned denominator; 中创建一个字段。虽然它使一些计算有点棘手。 int delta_y, delta_x; 似乎是将这个想法介绍给 OP 的好方法。
  • 您也可能会因将已签名参数不必要地提升为未签名参数的类型而陷入困境。
  • OP 正在制作线交叉点,使用叉积是避免在计算斜率时被零除陷阱的简单方法。有一种使用叉积的相交算法,其中除以零只能发生在直线平行的情况下,当没有相交时,这是一种可以测试的特殊情况。
【解决方案2】:

一般来说,对于任意方向的线,不建议使用斜率/截距表示y = mx + p,而是使用隐式方程a x + b y + c = 0。后者更各向同性,支持垂直线,并为您提供更大的灵活性来缩放系数。

遇到@chux 的回答,系数可以是增量,Dy x - Dx y + c = 0(假设线条由两个点定义,DxDy 可能不会溢出)。在c 上仍然可能发生溢出,您可以使用变体Dy (x - x0) - Dx (y - y0) = 0

无论如何,交叉点等中间计算可能需要更大的范围,即双倍长度整数。

标记大/低值的想法有点适得其反:它实际上是一种处理浮点的原始方式,即将小数位数与尾数分开。以这种方式工作,你会以某种方式重新设计一个浮点系统,它不如内置类型强大,而且会让你付出汗水和泪水。


不幸的是,高范围算术无法避免。事实上,两条直线的交点是由克莱默公式给出的

x = (c b' - c' b) / (a b' - a' b),
y = (a c' - a' c) / (a b' - a' b)

其中要评估的产品比初始系数大一个数量级。这是因为准平行线有很远的交点。

【讨论】:

    【解决方案3】:

    如果您想以一般方式使用 int,请查找 fixed point arithmetic

    您还可以设计算法,以便以不需要亚整数精度的方式进行每次计算(例如查找Bresenham's linecircle 绘图算法)。

    对于您的特定问题,您可以尝试分别保留商和分数,换句话说,使用有理数。或者换句话说,将 delta X 和 delta Y 作为两个数字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多