【问题标题】:Only return a decimal if it's not a whole number. JAVA如果不是整数,则仅返回小数。 JAVA
【发布时间】:2014-01-21 16:49:22
【问题描述】:

我一直在尝试编写一个函数isWhole,它被赋予一个双精度,并查看它是否是一个整数,如果它返回不带小数的值(作为 int?),否则返回 3 个小数地方(我可以用数字格式来做这部分。

我的问题是如何检查双精度数是整数还是递归小数?

【问题讨论】:

  • 十进制数与其四舍五入的值有什么区别?
  • 小数点。如何将双精度拆分为一个数组,遍历并检查是否有任何值是“。”
  • 我不知道什么是“递归小数”,但如果你的意思是“重复小数”,比如 1/3 = 0.333333... 或 1/27 = 0.037037037... - - 你不能。 double 无法准确表示像 1/3 这样的数字。计算机以二进制表示数字,double 准确表示的每个数字都将采用 N/(2^M) 的形式,其中 N 和 M 是整数。并且任何这样的数字,如果它不是一个整数,将有一个十进制表示,终止。
  • @ajb 当然,“重复小数”是 IIRC,总是可以表示为整数的比率。然而,不幸的是,一旦数字被转换为 float/double,它就失去了它的重复字符。

标签: java if-statement double calculator


【解决方案1】:

[UPDATE] 返回值 - 小数点后 3 位

public boolean isWhole(double value) {
    return Math.floor(value) == value;
}
  • 您不能有一个返回intdouble 的函数
  • double转换为int;只是 typecast :- int valueInt = (int) valueDouble;

【讨论】:

  • 这相当于return Math.floor(value) == value
  • 呜呜呜。除了不必要的 if 之外,您的第一个解决方案很好而且很干净。现在您将格式化混合到 isWhole() 测试中,从而它会做一些名称没有宣传的事情(违反干净代码原则)。此外,它将打破二进制和十进制表示之间的转换不精确的各种极端情况。
  • @MiteshPathak:是的,好吧,但是我们不能返回一个双精度数,因为由于二进制和十进制之间的转换问题,双精度数不能正确四舍五入到小数位(零除外)。然后我们必须在格式化后返回一个字符串。
【解决方案2】:

我的第一个建议是:保持简单。 Java 具有使这种事情变得简单的函数:

import java.Math;
public class MyFunctionsLibrary {
    public static boolean isWhole(double x) {
        if(x - Math.floor(x) == 0)
            return true;
        else
            return false;
    }
    public static void testIt() {
        double a = 123.456;
        Integer whole = null;
        Double nonWhole = null;
        if(isWhole(a))
            whole = new Integer(Math.floor(a));
        else
            nonWhole = new Double(a);
    }
}

【讨论】:

    【解决方案3】:
    if(Math.abs(in-Math.floor(in)) < 0.001){
        /* is whole number */
    } else {
        /* is not whole number */
    }
    

    整数并没有真正定义为双精度数,因此可以将整数视为不会导致n.000 的数字。 0.001 是专门选择的,因为它是预期的输出精度。

    【讨论】:

    • 我觉得定义很明确。 OP 想要检查数学整数的值。对于像 1e300 这样的大双精度值,转换为 int 会中断。
    • 正确的答案(使用floor而不是(int))更好。但是比较应该是0.0005而不是0.001。原因:四舍五入为整数(保留 3 位小数时)的值应被视为整数。如果值 rounds 为非整数,则不应将其视为整数。例如,输入 1.00099 将四舍五入为 1.001,这就是它应该显示的方式。
    • 次要点:Math.abs 不需要。请参阅docs.oracle.com/javase/7/docs/api/java/lang/Math.html 中的floor。地板总是小于或等于输入值。最终更正答案:if (in - Math.floor(in) &lt; 0.0005)
    • OP 的另一种解释,是在一些较小的公差范围内寻找整数。所以也许1.00000035 应该显示为1,但1.0004 应该显示为1.000(零似乎不必要,但它们是发生“显着”舍入的线索)。要实现这一点,也许可以使用(in - Math.floor(in) &lt; 0.00001),尽管使用的值相当随意。
    • 顺便说一句,答案并没有说明如何获取whole value。在整数分支中,执行Math.round(in)。结果是一个双精度值,包含一个整数值。也就是说,它没有十进制数字。对于没有数字的字符串表示,请执行String.format("%.0f", in)。例如:String.format("%.0f", new Double(5.0/6)) 结果为 1,因为这种格式会四舍五入。
    【解决方案4】:

    这是我原来的答案:

    怎么样

    Math.floor(x)==x
    

    如果 x 是一个数学整数(比如文档),则地板将逐位保持不变,因此当没有什么要舍入时,等式应该完全成立。

    经过一番思考,我认为使用精确比较可能会导致不需要的结果。问题是,OP 的真正要求是什么。是吗

    1. 如果是数学整数,则显示不带数字的数字 小数点后,如果不是,在小数点后显示3位 小数点。或者是吗

    2. 如果使用三位数格式化导致小数点后为 000,则仅显示整数。

    上面和其他答案中显示的解决方案仅在要求 (1) 时才有效,因为数字 2.000001 会变成 2.000,因为它不是数学整数。

    如果 Locale 固定为默认值,endsWith() 模式的 1.0 格式当然可以优化为固定字符串,如“.000”或“,000”。

    如果实际请求了 (2),我的直觉是,没有办法先将数字格式化为字符串,然后再去除零,如下所示:

    String format(Locale l, double d) {
      String zeros = String.format(l, "%.3f", 1.0d);
      String s = String.format(l, "%.3f", d); 
      if (s.endsWith(zeros.substring(1))) {
        return s.substring(0, s.length()-4);
      }
      return s;
    }
    

    【讨论】:

      【解决方案5】:

      要查看双精度数是否为整数,请使用

          double d;        
          int whole = (int) d;
          if(whole == d){
              return whole;
          }
          else{
              (your formatting here)
              return formattedDouble;
          }
      

      你可以通过创建来检查它是否是递归的:

        String s = d + "";
        for(int i = 1; i < s.length(); i++){
            if(s.charAt(i) == s.charAt(i-1)){
                continue;
            }
            else{
               return false;
            }
        }
      

      【讨论】:

      • (1) 第一部分 - 转换为 int 打破了大型双打,不能用 int 表示。它也有轻微的代码气味,因为它依赖于(int) 进行截断而不是舍入。最好使用@user60561 的修订答案。也就是说,请改用Math.floor
      • (2)。重复小数的错误测试。首先,用户必须了解双精度并不完全代表rational value,因此该小数的任何表示都不会完全是重复小数。其次,重复小数可能在重复部分的左侧有非重复数字。例如。 1/6 变为 0.1666..。因为双精度数不能准确地表示重复的小数,所以您必须任意决定最后有多少相同的数字意味着“它重复”...
      • ... 第三,字符串表示将四舍五入,因此1/6 变为0.1666667。因此,如果重复数字为 5 或更大,则允许最后一位数字大 1。但是不要要求它更大 - 由于双重表示的不精确性,您可能会碰巧得到0.1666666。不是 1/6,而是在少数情况下。第四,这是转换为字符串的一种丑陋方式。此外,您可能想指定有多少重要的地方。除非您知道自己的数字很小,否则您将不得不使用指数(科学记数法),并跳过指数部分。代码留给读者。 ...
      • ... 情况变得更糟。考虑(new Double(123456788.0/6)).toString() => 2.0576131333333332E7。跳过指数E7,我们看到最后一个数字是2而不是3。再次,双重的不精确性。但是,如果您说“我将跳过最后一位并检查前面的内容”,那么如果您看到 2.05761333335 会发生什么。那是重复的小数吗?不。另一方面,它可能最初是一个重复的小数,但后来你做了一些(不精确的)数学运算,比如向它添加另一个数字,它稍微偏离了。这对你来说是不精确的数学。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      • 2017-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多