【问题标题】:Finding absolute value of a number without using Math.abs()在不使用 Math.abs() 的情况下查找数字的绝对值
【发布时间】:2012-06-16 07:27:42
【问题描述】:

有没有什么方法可以不使用java中的Math.abs()方法来求一个数的绝对值。

【问题讨论】:

  • 而不想用那个方法的原因是……
  • 是指定为 Integral 类型的数字,int,byte,short,long 还是浮点数(float,double)或装箱类(Integer,Double,...)或 BigDecimal, BigInteger 还是别的什么?未指定?
  • 我需要循环使用它。所以我正在寻找任何其他最好的方法。
  • 您可以在循环中使用 Math.abs。不要微优化。 JVM 通常会使其足够快。如果你真的认为它太慢了,那就测量它。
  • @Thilo 我查过了。工作得很好,我正在尝试找到不同的方法,以便我可以根据需要使用最佳方法。

标签: java number-formatting absolute-value


【解决方案1】:

如果您查看 Math.abs,您可能会找到最佳答案:

例如,对于浮动:

    /*
     * Returns the absolute value of a {@code float} value.
     * If the argument is not negative, the argument is returned.
     * If the argument is negative, the negation of the argument is returned.
     * Special cases:
     * <ul><li>If the argument is positive zero or negative zero, the
     * result is positive zero.
     * <li>If the argument is infinite, the result is positive infinity.
     * <li>If the argument is NaN, the result is NaN.</ul>
     * In other words, the result is the same as the value of the expression:
     * <p>{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))}
     *
     * @param   a   the argument whose absolute value is to be determined
     * @return  the absolute value of the argument.
     */
    public static float abs(float a) {
        return (a <= 0.0F) ? 0.0F - a : a;
    }

【讨论】:

    【解决方案2】:

    是的:

    abs_number = (number < 0) ? -number : number;
    

    对于整数,这很好用(Integer.MIN_VALUE 除外,其绝对值不能表示为 int)。

    对于浮点数,事情就更微妙了。例如,此方法(以及迄今为止发布的所有其他方法)无法正确处理 negative zero

    为了避免自己处理这些微妙的问题,我的建议是坚持使用Math.abs()

    【讨论】:

    • 关于浮点的好点。不过还不错,这里是来自 java.lang.Math 的双 abs 的来源:return (a &lt;= 0.0D) ? 0.0D - a : a;,float 版本看起来很相似。
    • @Thilo:这里的重点是浮点数学充满了微妙之处。除非有真正令人信服的论据,否则应该坚持使用标准函数。
    • 我知道一个测试用例,其中 Int、Long、Byte 和 Short 也失败了。
    • @userunknown:当然,但这是整数的二进制补码表示的属性,而不是计算 abs() 的方法。
    • @aix: ?所以这是忽略它的理由吗? 2-补码有罪吗?
    【解决方案3】:

    像这样:

    if (number < 0) {
        number *= -1;
    }
    

    【讨论】:

    【解决方案4】:

    由于 Java 是一种静态类型语言,我希望采用 int 的 abs 方法返回一个 int,如果它期望一个 float 返回一个 float,对于 Double,返回一个 Double。也许它可以总是为双打和双打等返回装箱或未装箱的类型。

    所以你需要每个类型一个方法,但现在你有一个新问题:对于 byte、short、int、long,负值的范围比正值的范围大 1。

    那么该方法应该返回什么

    byte abs (byte in) {
       // @todo
    }
    

    如果用户在 -128 上调用 abs?您总是可以返回下一个更大的类型,以保证范围适合所有可能的输入值。这将导致长期存在的问题,其中不存在正常的较大类型,并使用户在测试后总是降低值 - 可能会很麻烦。

    第二个选项是抛出一个算术异常。这将防止在已知输入受限的情况下强制转换和检查返回类型,这样 X.MIN_VALUE 就不会发生。想想 MONTH,表示为 int。

    byte abs (byte in) throws ArithmeticException {
       if (in == Byte.MIN_VALUE) throw new ArithmeticException ("abs called on Byte.MIN_VALUE"); 
       return (in < 0) ? (byte) -in : in; 
    }
    

    “让我们忽略 MIN_VALUE 的罕见情况”的习惯不是一种选择。首先使代码工作 - 然后使其快速。如果用户需要一个更快但有问题的解决方案,他应该自己编写。 可能可行的最简单解决方案意味着:简单,但不要太简单。

    由于代码不依赖于状态,因此可以并且应该将方法设为静态。这样可以进行快速测试:

    public static void main (String args []) {
        System.out.println (abs(new Byte ( "7")));
        System.out.println (abs(new Byte ("-7")));
        System.out.println (abs((byte)  7));
        System.out.println (abs((byte) -7));
        System.out.println (abs(new Byte ( "127")));
        try
        {
            System.out.println (abs(new Byte ("-128")));
        }
        catch (ArithmeticException ae)
        {
            System.out.println ("Integer: " + Math.abs (new Integer ("-128")));
        }
        System.out.println (abs((byte)  127));
        System.out.println (abs((byte) -128));
    }
    

    我捕获第一个异常并让它运行到第二个,只是为了演示。

    编程中有一个坏习惯,那就是程序员更关心快速而不是正确的代码。太可惜了!


    如果您想知道为什么负值比正值多一个,我有一个diagram for you

    【讨论】:

      【解决方案5】:

      虽然这不应该是一个瓶颈,因为现代处理器上的分支问题通常不是问题,但对于整数,您可以采用此处概述的无分支解决方案:http://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs

      (x + (x >> 31)) ^ (x >> 31);
      

      然而,在明显的 Integer.MIN_VALUE 情况下,这确实会失败,因此这是一种使用风险自负的解决方案。

      【讨论】:

      • 是的,如果你想把很多人搞糊涂,这非常好,特别是如果你将函数命名为 a() 或类似的模糊名称
      【解决方案6】:

      如果整数 x 的绝对值不使用 Math.abs()、条件或按位运算,以下可能是 Java 中的可能解决方案。

      (int)(((long)x*x - 1)%(double)x + 1);
      

      由于Java将a%b视为a - a/b * b,因此无论“b”是什么符号,结果的符号都将与“a”相同; (x*x-1)%x 将等于 abs(x)-1; “long”的类型转换是为了防止溢出,double 允许除以零。

      同样,x = Integer.MIN_VALUE 会因为减 1 导致溢出。

      【讨论】:

        【解决方案7】:

        你可以使用:

        abs_num = (num < 0) ? -num : num;
        

        【讨论】:

          【解决方案8】:

          这是一个返回数字绝对值的单行解决方案:

          abs_number = (num < 0) ? -num : num;
          

          【讨论】:

            【解决方案9】:

            -num 将等于 Integer.MIN_VALUE 的 num

             Integer.MIN_VALUE =  Integer.MIN_VALUE * -1
            

            【讨论】:

              【解决方案10】:

              使用数学类

              Math.abs(num);
              

              【讨论】:

              • 该问题明确表示“不使用 Math.abs()”。
              猜你喜欢
              • 2015-07-27
              • 1970-01-01
              • 2015-01-21
              • 1970-01-01
              • 2012-04-04
              • 1970-01-01
              • 2020-02-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多