6

更新:谢谢凯文,我的意思是标题中的<=,而不是<。

这个对吗?这是我在这个问题上经历了一段令人尴尬的时间后所取得的最好成绩:

public int candidate_answer(double f, float g) {
    int test = (int)Math.floor(f / g);
    if ((test + 1) * g <= f) {
        test++;
    }
    return test;
}

背景:

该应用程序是一个简单的游戏,我从以前的程序员那里接管了它的所有权。奇怪的是,他选择在成员变量和参数变量中任意混合浮点数和双精度数,因此上下有很多不必要的隐式和显式转换。

玩家坐标在双 x, y 处(假设玩家是一个点)。有一个浮动 TILE_SIZE,世界是一些行和列的瓦片,加上一些通用的越界处理。假设 (x,y) 坐标在界限内,我试图根据 x(获取列)或 y(获取行)来确定用户在哪个图块中。这就像程序员 101。

WLOG,起初我只是在做col = (int)(x/TILE_SIZE). 但正如我发现的那样,例如 .5/.1f < 5,因此(int)(.5/.1f) == 4是错误的答案。这导致了上述if语句和问题的表述。

然后我发现,例如,(int)(-9.999999747378752E-5 / .1f) == 0这导致我先打电话Math.floor

但现在我不确定这种方法中还有哪些其他错误,或者最好的方法是什么。

(如果用户正处于某一排或另一排的风口浪尖,而我们不小心四舍五入到错误的那一排,这似乎没什么大不了的;但真正的问题是在代码中,我们看到意外的符号变化(+, -, 0)。例如,一些代码假设如果用户在 (r,c) 处的图块上,那么它的点实际上包含在该图块几何体中。如果不是,我们会得到类似当只预期非负数时的负距离等等,它会导致断言触发和 while 循环中断等等。)

4

3 回答 3

3

我认为您应该尝试解决根本问题(.1f 离 .1 太远),即将 TILE_SIZE 变成双精度,或者在任何地方始终使用浮点数。否则,您可能会遇到由整个代码中的最小舍入错误引起的类似问题。Candidate_answer 函数是一种解决原本不应该存在的问题的技巧。

附言

对于这个特定问题,您可能只想找到一个更稳健的公式,即仅对一个方向的最小舍入误差不敏感。尝试将玩家放在其场地的中心而不是瓷砖边缘,因为它很容易陷入四舍五入错误:

col = (int)((x + MINIMAL_STEP_SIZE / 2.0) / TILE_SIZE)

(理想情况下,MINIMAL_STEP_SIZE/2 部分已经是 x 的一部分,而不是在此处添加)

于 2013-07-07T19:26:34.113 回答
1

一直使用双精度似乎是要走的路。然而,这并不能解决根本问题:使用浮点运算总是会产生舍入误差。

使用浮点运算时,使用 Epsilon (e) 精度总是好的:

如果要检查 x 是否等于 y(其中一个变量是浮点类型),请使用以下模式:

if(x-y < e){
  ...
}

必须根据您的要求定义 Epsilon(全局或根据您的意见针对某个域)。例如:

e = 0.00001d;
于 2013-07-07T19:38:39.103 回答
0

如果fg都是正数(它们似乎是),您的方法可能会简化为一个简单的计算:

public static int candidate_answer(double f, float g) {
    return (int)(g/f);
}

这是正确的,因为如果

i*f <= g

然后将两边除以f收益率

i <= g/f

转换为 int 会自动为您提供“小于或等于结果的最大 int”,因为在转换所有非整数部分时都会丢弃 - 这就像执行 floor() 调用一样。


如果f或被g允许为负数,这种方法仍然有效,但必须添加处理标志(代码不多,但我怀疑它是必需的,因为他们用了问题的措辞方式。

于 2013-07-07T21:19:10.583 回答