【问题标题】:Are there any functions for truncating a double in java?java中是否有截断双精度的函数?
【发布时间】:2010-12-30 21:55:34
【问题描述】:

是否有可用于将数字截断为任意小数位数的 Java 库函数? 例如。

SomeLibrary.truncate(1.575, 2) = 1.57

谢谢

【问题讨论】:

标签: java


【解决方案1】:

只需删除小数部分

public double trunk(double value){ return value - value % 1; }

【讨论】:

    【解决方案2】:

    在公共数学中有一个。查看http://commons.apache.org/math/apidocs/org/apache/commons/math/util/MathUtils.html

    public static double round(double x,
                               int scale)
    

    它使用 BigDecimal 实现,并被重载以允许指定舍入方法,因此您可以使用它来截断,如下所示:

    org.apache.commons.math.util.MathUtils.round(1.575, 2, 
        java.math.BigDecimal.ROUND_DOWN);
    

    更新:

    在上一个版本(Math3)中,这个方法在类Precision中。 org.apache.commons.math3.util.Precision.round(double x, int scale, int roundingMethod)

    【讨论】:

      【解决方案3】:

      这是一个简短的实现,比使用 BigDecimal 或 Math.pow 快很多倍

      private static long TENS[] = new long[19];
      static {
          TENS[0] = 1;
          for (int i = 1; i < TENS.length; i++) TENS[i] = 10 * TENS[i - 1];
      }
      
      public static double round(double v, int precision) {
          assert precision >= 0 && precision < TENS.length;
          double unscaled = v * TENS[precision];
          if(unscaled < Long.MIN_VALUE || unscaled > Long.MAX_VALUE) 
             return v;
          long unscaledLong = (long) (unscaled + (v < 0 ? -0.5 : 0.5));
          return (double) unscaledLong / TENS[precision];
      }
      

      删除要品尝的断言。 ;)

      【讨论】:

      • 我看到的唯一问题是您将参数v 乘以(可能)10 的几个幂,这可能导致溢出。当然,双最大值约为 10^308,因此大多数人不会注意到这一点,但它是可能的,这是令人惊讶的行为(您不会期望舍入函数在提交有效值时会溢出)。跨度>
      • 刚刚注意到,一旦未缩放的值超过 long 类型,该方法就会失败,这要快得多。如果要求足够的精度,即使参数 v 很小,这也可能非常快。
      • @UMad 好的,更改了应该处理这两种情况的检查。
      • round(9.625, 2) 根据问题返回 9.63 是错误的。答案应该是 9.62
      • @PeterLawrey 下降 +0.5 将不适用于 round(9.62,2) 到 9.61 。问题是 double 没有实际的小数点你必须使用 BigDecimal 或者应该添加额外的条件
      【解决方案4】:

      我只想添加到 ubuntudroid 的解决方案。 我试过了,它不会四舍五入,所以我不得不添加

      df.setRoundingMode(RoundingMode.FLOOR);
      

      让它工作。

      【讨论】:

        【解决方案5】:

        难以置信的是,还没有人提出这个问题,Java API 多年来一直有 DecimalFormat 用于这个确切的目的。

        【讨论】:

        • 具体来说,对于给定的示例,代码看起来像这样: final DecimalFormat df = new DecimalFormat(); df.setMaximumFractionDigits(2); df.format(1.575);最后一个表达式返回一个必须转换回双精度的字符串。
        • 这会做圆,我认为这个问题要截断而不是圆。
        【解决方案6】:

        使用这个简单的函数

        double truncateDouble(double number, int numDigits) {
            double result = number;
            String arg = "" + number;
            int idx = arg.indexOf('.');
            if (idx!=-1) {
                if (arg.length() > idx+numDigits) {
                    arg = arg.substring(0,idx+numDigits+1);
                    result  = Double.parseDouble(arg);
                }
            }
            return result ;
        }
        

        【讨论】:

          【解决方案7】:

          像这样尝试BigDecimal的setScale:

          public static double round(double d, int decimalPlace) {
              BigDecimal bd = new BigDecimal(d);
              bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
              return bd.doubleValue();
          }
          

          【讨论】:

          • 2 cmets:BigDecimal 已经有一个构造函数采用Double。 OP 似乎也不想将其四舍五入,而只是将其截断(下限)。
          • 实际上,BalusC 是对的,我想截断值但是,你的回答让我朝着正确的方向前进,所以我接受了。
          • 您需要将 RoundingMode 设置为 BigDecimal.ROUND_DOWN 而不是 ROUND_HALF_UP 才能真正截断值
          • stackoverflow.com/questions/7747469/… 的改进版本,具有正负值且不四舍五入
          【解决方案8】:

          要做到 100% 可靠,您必须将参数作为字符串而不是浮点数传递。当以字符串形式给出时,代码很容易编写。原因在于

          double x = 1.1;
          

          并不意味着 x 实际上将计算为 1.1,仅计算为最接近的可精确表示的数字。

          【讨论】:

          • 或者使用BigDecimal,这也是BigDecimal存在的原因之一。
          • 你仍然需要从字符串初始化它,而不是从双精度。
          【解决方案9】:

          其实这种东西很容易写:

          public static double truncate(double value, int places) {
              double multiplier = Math.pow(10, places);
              return Math.floor(multiplier * value) / multiplier;
          }
          

          注意它是 Math.floor,因为 Math.round 不会被截断。

          哦,这会返回一个 double,因为这是 Math 类中的大多数函数(如 Math.pow 和 Math.floor)返回的。

          警告:双打不利于准确性。应首先考虑其中一种 BigDecimal 解决方案。

          【讨论】:

          • 注意:pow 是一个非常昂贵的函数。如果性能不是问题,请使用它。
          • 我喜欢这种简单明了的解决方案。
          • @Mani(嗯,也适用于 EJP 所说的):我会注意到警告的存在是有原因的。
          • @Powerlord 目标是将双精度数截断为任意小数位数,任何解决方案都应该做到这一点。这段代码没有也不能这样做,不是因为“准确性”,而是因为二进制分数和十进制分数是不可通约的。
          【解决方案10】:

          创建了一个方法来做到这一点。

          public double roundDouble(double d, int places) {
              return Math.round(d * Math.pow(10, (double) places)) / Math.pow(10, (double)places);
          }
          

          【讨论】:

            【解决方案11】:

            对于大多数数字,您将无法获得xxx.yyyy 的精确表示,除非您使用具有保证准确性的十进制类,例如BigDecimal

            【讨论】:

            • 更根本的是,双精度数没有位小数,因为它们被存储为二进制分数。
            猜你喜欢
            • 2019-03-13
            • 1970-01-01
            • 2012-05-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-18
            • 1970-01-01
            • 2017-10-02
            相关资源
            最近更新 更多