【问题标题】:Java: Perform mathematical operation while ignoring signJava:在忽略符号的同时执行数学运算
【发布时间】:2014-05-07 12:42:52
【问题描述】:

我正在尝试制作一个涉及计算执行一些简单数学运算所需的力的游戏。我有一个dx 变量,它表示沿 X 轴的速度和方向。现在我想减去摩擦,但如果dx 的方向为负,则它必须是一个加法。有没有办法在返回有符号值的同时使用绝对值从dx 中减去摩擦?我正在研究按位运算符,但我不知道有什么可能性......

我能做什么(我认为):

sign = ( dx >> 31 ) << 31;
dx = (dx << 1) >> 1;
dx = ( dx - friction ) & sign;

不确定这是否可行,只是这个想法......有任何改进吗?

编辑:这就是我所做的:

dxSign = Integer.signum(dx) * -1;
dySign = Integer.signum(dy) * -1;
dy = Math.abs(dy);
dx = Math.abs(dx);

fric = body.friction * mass;

dx = ( dx > fric ) ? dx - fric : 0;
dy = ( dy > fric ) ? dy - fric : 0;

dx = dx * absorption;
dy = dy * absorption;

dx *= dxSign;
dy *= dySign;

【问题讨论】:

    标签: java math integer bit-manipulation sign


    【解决方案1】:

    最安全的选择是使用条件。你不希望分数改变方向

    dx = dx < -friction ? dx + friction : dx > friction ? dx - friction : 0
    

    【讨论】:

    • 是的,但是 dx > -friction 或 dx
    • @Val 这曾经是正确的,但是如果您查看 JIT 优化代码,它通常使用 ?: 比晦涩的数学编码做得更好。顺便说一句,我曾经使用过这样的编码,但发现它通常比较慢。
    • 它似乎表现最好,所以我将使用它,谢谢。
    • @SamuelWillems JIT 在处理常见模式方面变得越来越聪明,这意味着奇怪的技巧不再像以前那样有效,这几乎令人失望 ;)
    • @SamuelWillems 我知道你的意思。它曾经对奇怪的事情非常有用,比如在数组中添加所有奇数,但我发现在 Java 8 中使用条件更快。 :P
    【解决方案2】:

    当您想忽略该符号时,请使用Math.abs。请注意,优化可能会导致您的代码变得不可读且难以维护。因此,对于初学者来说,尽量让您的代码尽可能干净,当您遇到性能问题时,请通过基准测试确定问题的根源并仅优化代码的瓶颈。

    【讨论】:

      【解决方案3】:

      您的代码不正确,原因有两个:

      • dx = (dx &lt;&lt; 1) &gt;&gt; 1; 不会消除符号。此外,当第 31 位设置为 1 时,它可能会错误地产生“误报”(即误报负数)。即使您将&gt;&gt; 替换为&gt;&gt;&gt;,您也不会得到绝对值,因为ints 存储在二进制补码中,而不是作为符号+值表示
      • sign 将是二进制表示的 10000...0000000..00,因此 ( dx - friction ) &amp; sign 不会将符号与其他计算的结果合并。

      您可以使用Integer.signum 函数更改加法或减法,如下所示:

      dx -= Integer.signum(dx) * friction;
      

      【讨论】:

      • 或使用int mult = Integer.signum(dx)
      • @slim 很棒的评论!我在错误的地方(在java.lang.Math)寻找signum,但它不在那里。大约在 1.5 中引入此功能的同时,我停止使用 Java。非常感谢!!!
      【解决方案4】:

      按照明显的方式去做:除非有性能问题,否则不要试图变得聪明。

      if(dx >0 ) {
          dx -= friction;
      } else {
          dx += friction;
      }
      

      如果这看起来有点冗长,请将其隐藏在方法中:

      dx = applyFriction(dx,friction);
      
      int applyFriction(int pos, int friction) {
           if(pos > 0) {
                 return pos - friction;
           } else {
                 return pos + friction;
           }
      }
      

      这在abs(pos) &lt; friction 时存在问题,如果你研究你的物理学,你会发现摩擦更有可能是通过乘法模拟的——这消除了你对符号的担忧。

      【讨论】:

        【解决方案5】:

        在物理学中,你的方向符号并不重要。我建议利用动摩擦力是与运动中物体的绝对速度成正比的力这一事实。也就是说,对象在[0, 1] 范围内具有一定的摩擦系数μ<sub>F</sub>。速度的变化只是 δ<sub><b>V</b></sub> = μ<sub>F</sub>∙<b>V</b>∙δ<sub><b>t</b></sub> 其中 V 是对象的初始速度向量,δ<sub><b>t</b></sub> 是某个时间跨度。

        新速度V'

        给出
        V' = V - δV
           = V - μFV∙δt
           = V(1 - μF∙δt)

        这样,你根本不需要处理符号,它很容易扩展到更高维的情况。

        顺便说一句,确保 δt 足够小,不会在您的模型中引入振荡。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-17
          • 1970-01-01
          • 2019-07-21
          • 1970-01-01
          • 2010-12-21
          • 2017-03-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多