我在java服务器(jetty)上使用websockets将值(浮点数)作为字节发送,并使用DataView.getFloat32(从ArrayBuffer创建)在我的javascript代码中提取它们。
我的问题是数字似乎不正确(但几乎等于实际值),例如:
如果我发送2.43,则在javascript中输出2.430000066757202,或者在其他情况下输出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次,至少,以及一个大的客户数量。
答案 0 :(得分:0)
它来自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
值,或使用{em> scale 或精度的integer
值其他信息,例如,而不是flat number = 2.43f
,请使用int number = 243; int scale = 100;
答案 1 :(得分:0)
问题在于浮点数的表示,而不是getFloat32()函数。在我的情况下,因为我需要以5的精度工作,我使用number.toFixed(5),我应该使用.toPrecision(5),将数字显示为字符串。
答案 2 :(得分:0)
该问题是由于DataView.getFloat32()懒惰造成的。
您所期望的是,应将ArrayBuffer中的二进制数据读取为浮点数,该尾数具有足够的尾数位以实现6〜9位精度,因此当以十进制数形式查看时,它会四舍五入,然后取该值分配给双精度变量。由于这些浮点数和双精度数在尾数中具有不同的位,以实现不同的精度,因此当您表示完全相同的十进制数字时,可以期望完全不同的尾数。 (而且我们一直在谈论十进制数字,没有人使用浮点数来表示二进制数字。另请参见IEEE 754)
例如,float中的2.43为0x401B851F
,double中的2.43为0x400370A3D70A3D71
。您可以只关注十六进制表示法,以查看尾数完全不同。
但是,在source中看到的getFloat32()的实现与T.Gournelle的回答中所描述的完全相同。 DataView.getFloat32()调用setDouble(),该方法将double用作参数,因此这将导致从float到double的隐式C ++浮点转换。 C ++转换使double值等效于float二进制值,而不是其十进制值。
因此,当您获得双倍的2.430000066757202时,即为0x400370A3E0000000
。您看到双精度尾数末尾的0000000
吗?这就是getFloat32()的懒惰,只需执行C浮点数以进行双精度转换,而不是实际获取浮点值。
这意味着,您必须在执行getFloat32()之后自己采取四舍五入为6或7位数字的额外步骤。
(注意:由于T.Gounelle的答案给出了浮点精度的背景,因此我将其作为一个单独的答案,但实际上并未回答OP的有关导致精度错误的getFloat32的问题。)