Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的数学-不同对象的不同结果_Java_Math - Fatal编程技术网

Java中的数学-不同对象的不同结果

Java中的数学-不同对象的不同结果,java,math,Java,Math,我在为我正在开发的应用程序计算时得到了一些奇怪的结果,我想这里的人可能能够帮助我弄清楚到底发生了什么 此特定计算的要求规定,计算应如下所示: A和B是已知的 A * B = C 对于这个特殊的计算 A = 0.0410 B = 123456789010 以下是我看到的结果: 计算器: 0.0410 * 123456789010 = 5061728349.41 爪哇: B是双重的: 0.0410f * 123456789010d = 5.061728489223363E9 = 5061728

我在为我正在开发的应用程序计算时得到了一些奇怪的结果,我想这里的人可能能够帮助我弄清楚到底发生了什么

此特定计算的要求规定,计算应如下所示:

A和B是已知的

A * B = C
对于这个特殊的计算

A = 0.0410
B = 123456789010
以下是我看到的结果:

计算器:

0.0410 * 123456789010 = 5061728349.41
爪哇:

B是双重的:

0.0410f * 123456789010d = 5.061728489223363E9 = 5061728489.223363
B是一个长的:

0.0410f * 123456789010l = 5.0617288E9 
对我来说,精度的损失不如10s和1s点的差异重要(反正我只需要9位精度)。为什么使用double进行计算会得出“错误”的结果


顺便说一句,我尝试使用
BigDecimal
进行计算,得到了与使用double时相同的结果

第一个计算使用双精度(64位),第二个浮点(32位)。你看到的是“舍入误差”

在这两种情况下,它都是浮点计算,但在第二种情况下,不涉及“双”参数,因此它只使用32位算术

引述:

如果二进制运算符的操作数中至少有一个是浮点类型的,则该运算是浮点运算,即使另一个是整数

如果数值运算符的操作数中至少有一个为double类型,则使用64位浮点运算执行该运算,数值运算符的结果为double类型的值。如果另一个操作数不是double,则首先通过数字提升(§5.1.5)将其加宽为double

否则,使用32位浮点算法执行该运算,数值运算符的结果为float类型的值。(如果另一个操作数不是浮点,则首先通过数字提升将其加宽为类型浮点。)


发生的各种类型转换由指定。就您的情况(摘录):

  • 如果其中一个操作数的类型为double,则另一个操作数将转换为double
  • 否则,如果其中一个操作数的类型为float,则另一个操作数将转换为float
0.0410f*12345678910d=506172848.9223363
中,
0.0410f
首先转换为不一定等于
0.0410d
的双精度。事实上,你可以试试看,这不是:

    double d1 = 0.041d;
    double d2 = 0.041f;
    System.out.println(new BigDecimal(d1));
    System.out.println(new BigDecimal(d2));
产出:

0.0410000000000001720845688168992637656629085540771484375
0.0410000132488250732421875

在下一个示例中:

0.0410f * 123456789010L = 506172832
long被转换为float,您可以通过以下示例进行验证:

    float f1 = 0.0410f;
    float f2 = 123456789010L;
    System.out.println(new BigDecimal(f1)); // 0.041000001132488250732421875
    System.out.println(new BigDecimal(f2)); // 123456790528
    System.out.println(new BigDecimal(0.0410f * 123456789010L)); // 5061728768
    System.out.println(new BigDecimal(f1 * f2)); // 5061728768
对于浮点数/双精度运算的精度,一般检查

最后,如果使用BigDecimal,则会得到正确答案:

    BigDecimal a = new BigDecimal("0.041");
    BigDecimal b = new BigDecimal("123456789010");
    System.out.println(a.multiply(b)); // outputs 5061728349.410

您的问题的答案可能在Java语言规范和中。由于正在进行的隐式转换,您可能遇到舍入错误

适用于您的情况的报价是

第三次行动:

如果二进制运算符的至少一个操作数为 浮点类型,则该操作为浮点操作, 即使另一个是积分

第二次操作:

如果数值运算符的至少一个操作数为 double,则使用64位浮点执行该操作 算术运算,数值运算符的结果为 键入double。如果另一个操作数不是双精度数,则首先将其加宽 (§5.1.5)通过数字升级(§5.6)键入双精度字符

第一次手术

否则,操作将使用32位浮点执行 算术运算,数值运算符的结果为 输入float。(如果另一个操作数不是浮点,则首先加宽它 通过数字提升键入浮点。)


因此,您不必担心,只要确定所需的精度,并在必要时使用适当的铸件。

TLDR答案:浮点数不能更准确地表示“正确”答案。改用双人床。此外,在没有显式强制转换的情况下,乘法也将不精确地进行

我使用的答案

问题是,浮点的精度远低于双精度,因此当乘以一个较大的数字(例如,您的10^10值)时,在乘法过程中会丢失此精度。如果我们为乘法显式地将A转换为double:

double C = ((double)A)*B; //=5061728489.223363
然后我们得到额外的精度。如果我们将双重答案转换回浮点数:

float C = (float)((double)((double)A)*B); //=5061728256.000000 

你看答案又不同了。使用乘法的结果类型,因此在本例中为
double
,但向后转换为
float
会降低精度。如果没有显式的double(
double C=A*B
),则使用
float
类型。对于两种类型转换,乘法都是以双精度进行的,乘法后精度会丢失。

32位IEEE浮点数有七位精度;64位允许16位。这就是你能得到的。如果这两个都不够,则必须使用BigDecimal


这在实现IEE标准的每种语言中都是正确的,不仅仅是Java。

计算器显示:
5061728349.41
两个浮点数可以得到什么?@JigarJoshi:是的,“long”版本的答案也是一个数量级。BigDecimal按预期返回5061728349.41(如果使用字符串构造函数).也许你可以写你用来计算的代码。那么编译器是如何解释变量类型的就很明显了;我认为转换是在乘法之后发生的。在乘法之前显式转换为double可以更正它。@PhilH我添加了一个引用。当你将一个浮点数乘以一个double时,浮点数首先被转换成double。谢谢你对这个问题的精彩描述!
float C = (float)((double)((double)A)*B); //=5061728256.000000