有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java DataView getFloat32返回不正确但近似的数字

我在java服务器(jetty)上使用WebSocket以字节和数据视图的形式发送值(浮点数)。getFloat32(从ArrayBuffer创建)在我的javascript代码中提取它们

我的问题是数字似乎不正确(但几乎等于实际值),例如:

如果我发送2.43,在javascript中它输出2.4300000667522,或者在其他情况下,类似于2.439999340243

在java中,我使用ByteBuffer:

byte[] numberBytes = ByteBuffer.allocate(4).putFloat(number).array();

getFloat方法的输出是正确的:

number = ByteBuffer.wrap(numberBytes).getFloat(); //returns 2.43

有人知道为什么会这样吗

编辑: 关于浮点精度,我的问题是,如果我使用double,这将意味着我的应用程序的流量将增加一倍-我需要发送50-100个数字的包,至少每秒10-15次,对于大量客户机也是如此


共 (3) 个答案

  1. # 1 楼答案

    它来自64位的Javascript浮点数。参见the accepted answer to this question,它不在Javascript/Java主题中,但解释了为什么浮点数不精确。 在您的情况下,如果执行简单的Java测试:

    float f = 2.43f;
    double d = (double)f;
    System.out.println("as float: "+f+", as double: "+ d);
    

    您将获得:

    as float: 2.43, as double: 2.430000066757202
    

    如果精度对您的应用程序很重要,请尝试与两侧的double值保持兼容,或使用integer值和刻度精度附加信息,例如,使用int number = 243; int scale = 100;而不是flat number = 2.43f

  2. # 2 楼答案

    问题是由DataView引起的。getFloat32()是懒惰的

    您所期望的是,ArrayBuffer中的二进制数据应该以浮点形式读取,它有足够的尾数位来满足6~9位的精度,因此当它被视为十进制数时,它会被舍入,然后该值被分配给一个双精度变量。因为这些浮点数和双精度数在尾数中具有不同的位以获得不同的精度,所以在表示完全相同的十进制数时,可以预期完全不同的尾数。(我们一直在谈论十进制数,没有人用浮点数来表示二进制数。另请参见IEEE 754

    例如,float中的2.43是0x401B851F,double中的2.43是0x400370A3D70A3D71。您只需观察十六进制表示,就可以看到它有完全不同的尾数

    然而,在source中看到的getFloat32()的实现与T.Gournelle的答案中描述的完全相同。数据视图。GETFROAT32()调用StUnDouple(),它将双参数作为参数,因此,将一个隐式C++浮点转换从浮点转换为双。C++转换使双值等价于浮点二进制值,而不是其十进制值。p>

    所以当你得到2.4300000066757202的双精度时,那就是0x400370A3E0000000。你看到双精度尾数后面的0000000了吗?这就是getFloat32()的懒惰,它只需执行一个C float来进行双重转换,而不是实际获取浮点值

    所有这一切意味着,在执行getFloat32()之后,您必须自己采取额外的步骤,舍入到6或7位数

    (注意:我将此作为一个单独的答案,因为T.Gounelle的答案给出了浮点精度的背景,但实际上没有回答OP关于getFloat32导致精度错误的问题。)

  3. # 3 楼答案

    问题在于浮点数的表示,而不是getFloat32()函数。在我的例子中,因为我需要以5的精度工作,所以我使用了数字。toFixed(5),我应该使用。toPrecision(5),将数字显示为字符串时