当前位置: 首页 > 面试题库 >

双原始类型数据的意外行为

欧阳乐生
2023-03-14
问题内容

我想了解Java double类型如何将其值存储在Java的内存中。当我运行以下代码时,我得到意外的输出:

public static void main(String[] args)  {

    float a = 1.5f;
    float b= 0.5f;
    double c= 1.5;
    double d = 0.5;

    float a1 = 1.4f;
    float b1= 0.5f;
    double c1= 1.4;
    double d1 = 0.5;

    System.out.println(" a- b is " + (a-b));
    System.out.println(" c- d is " + (c-d));
    System.out.println("a1-b1 is " + (a1-b1));
    System.out.println("c1-d1 is " + (c1-d1));

}

输出:

 a- b为1.0
 c-d为1.0
a1-b1为0.9
c1-d1为0.8999999999999999

为什么c1-d1不等于0.9

我也尝试了其他不同的值,但有时会返回预期结果,而有时则不会。


问题答案:

尽管您可能听说过舍入错误,但您可能想知道为什么这里有舍入错误。

float a1 = 1.4f;
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;

System.out.println(new BigDecimal(a1) + " - " + new BigDecimal(b1) + " is " +
        new BigDecimal(a1).subtract(new BigDecimal(b1)) + " or as a float is " + (a1 - b1));
System.out.println(new BigDecimal(c1) + " - " + new BigDecimal(d1) + " is " +
        new BigDecimal(c1).subtract(new BigDecimal(d1)) + " or as a double is " + (c1 - d1));

版画

1.39999997615814208984375 - 0.5 is 0.89999997615814208984375 or as a float is 0.9
1.399999999999999911182158029987476766109466552734375 - 0.5 is
     0.899999999999999911182158029987476766109466552734375 
     or as a double is 0.8999999999999999

如您所见,这两个值都float不能double精确表示,并且在打印float或double时,会发生一些舍入操作以将其隐藏起来。在float的情况下,四舍五入到小数点后7位会产生您期望的数字。对于精度为16位的double值,可以看到舍入误差。

作为@Eric Postpischil,请注意floator
double运算是否具有舍入误差,这完全取决于所使用的值。在这种情况下,即使所表示的值比双精度值离0.9更远,浮点数还是显得更准确。

简而言之:如果您要使用floatdouble应该使用明智的舍入策略。如果无法执行此操作,请使用BigDecimal。

System.out.printf("a1 - b1 is %.2f%n", (a1 - b1));
System.out.printf("c1 - d1 is %.2f%n", (c1 - d1));

版画

a1 - b1 is 0.90
c1 - d1 is 0.90

当您打印浮点数或双精度数时,它假定最接近的十进制短数值是您真正想要的数值。即在0.5 ulp以内。

例如

double d = 1.4 - 0.5;
float f = d;
System.out.println("d = " + d + " f = " + f);

版画

d = 0.8999999999999999 f = 0.9


 类似资料:
  • 问题内容: 我是Kotlin的新手,正在玩数据类型。我选择了一个类型,然后尝试通过说来将其强制转换为a ,这在Java中是有效的(从语法上讲,但这是正确的)。但是,此操作失败,表示无法将Int强制转换为Double。我假设这是因为它是基于Integer类而不是原始的int数据类型构建的。我是正确的,最有价值的方法是什么?有一个功能,但这似乎效率低下且笨拙。 问题答案: 我花了一个类型,然后试图将它

  • 问题:我无法存储号码“600851475143”。我意识到这个数字比int所能容纳的要大,比最大long值要小。然而,我的程序没有把变量“number”注册成一个long,而是注册成一个int。有人能解释一下这个问题吗? **-问题线 } 解决方案:正如吉姆在下面所说,为了长型,必须在数字末尾加上“L”或“L”。“如果整数文字以字母L或L结尾,则为long类型;否则为int类型。建议使用大写字母L

  • 我是科特林的新手,我在玩数据类型。我取了一个<code>Int</code>类型,然后尝试将其转换为<code>Double</code>,将<code>num表示为Double>/code,这是一个在java中有效的调用(非语法上,但你明白了)。然而,这失败了,表示Int不能强制转换为Double。我假设这是因为它是基于Integer类而不是原始int数据类型构建的。我说得对吗?什么是最有效的价

  • 是否可以只使用一行代码就将输入变量的数据类型(可以是任何基元类型,int、bool、float、double)作为字符串返回?我知道对于字符串类型,使用和可以很容易地做到这一点,但我不确定如何使用这些方法返回基元类型的类型。我还想保持我的代码非常简短,最好只用一行。 我到处找了找,找不到任何地方,这个问题已经以我要求的方式得到了回答。

  • 我正在学习Java我有一些不清楚的事情,如果有人能帮忙,我将非常高兴。 第一个问题 int的近似值为:2.147.483647 long的近似值为:9223372036854775807 这个网站说: “如果整型文字以字母L或L结尾,则为long类型;否则为int类型” 这意味着如果我没有在变量名的末尾添加字母L/l 例如: 所以变量被认为是类型而不是长类型。 所以我做了这个节目: 这是输出: i

  • 问题内容: 即使我们有一个整数对象(例如Integer),为什么整数(int)仍具有原始类型?但是对于String类型则不一样。String没有这种原始类型。始终使用String处理对象引用吗? 问题答案: 速度。对于机器代码而言,使用本机CPU指令添加两个int的速度要快得多,而不是必须获取两个Integer对象,从它们中提取int值然后相加的结果,从而创建一个新的结果Integer对象以包含结