英文:
How to reconstruct a number from its integral, fractional and exponent parts?
问题
我正在编写一个解析器,需要解析数字。
数字的格式为JSON格式,即简化形式,类似于:
[+|-] 整数 [. 小数部分] [e|E 指数]
所以这里有数字的三个部分。每个部分都是一个整数。
例如:
0.4
整数部分 = 0
小数部分 = 4
指数 = 0
2.84e+6
整数部分 = 2
小数部分 = 84
指数 = 6
我知道如何在Java中以非常粗糙的方式计算这个数字。类似于这样:
long 整数部分;
long 小数部分;
int 指数;
double 小数 = 小数部分;
while (小数 >= 1.0) {
小数 *= 0.1;
}
var 数字 = (整数部分 + 小数) * Math.pow(10, 指数);
但是这种方法具有很糟糕的特性,比如完全失去精度,溢出等,特别是对于非常大的数字(例如10e99,2.7e-23)。
是否有一种方法可以从Java的组成部分创建一个数字,以使得该数字的性质尽量接近浮点数文字?
我目前的想法是尝试创建在内存中精确表示浮点数的位,这些位表示Java(以及许多其他语言)使用的IEEE 754表示。
这篇博文帮助我理解了浮点数表示,但我仍然有些困惑。
我目前尝试使用ByteBuffer
来实现:
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(<以浮点数精确表示数字的位>);
buffer.flip();
double 数字 = buffer.getDouble();
唯一的问题是,找出正确的位,这并不是一件简单的事情(如果有人知道如何做到这一点,请分享一下)。
编辑:性能很重要,所以我试图避免创建一个字符串,然后将其传递给Double.parseDouble(str)
... 因为与将位写入内存相比,这个过程可能非常昂贵... 但我可能是错的,这确实是最"高效"的选择?此时我真的不知道,希望在有几个选项时可以进行基准测试。
英文:
I am writing a parser where I need to parse numbers.
Numbers are in the JSON format, i.e. simplified, something like:
[+|-] integral [. fractional] [e|E exponent]
So these are the 3 parts of the number I have. Each part is an integer.
For example:
0.4
Integral = 0
Fractional = 4
Exponent = 0
2.84e+6
Integral = 2
Fractional = 84
Exponent = 6
I know how to compute the number in Java in a very crude manner. Something like this:
long integral;
long fractional;
int exp;
double decimal = fractional;
while (decimal >= 1.0) {
decimal *= 0.1;
}
var n = (integral + decimal) * Math.pow(10, exp);
But this has terrible properties like losing precision completely, overflowing etc. specially for very large numbers (e.g. 10e99, 2.7e-23).
Is there a way to create a number in Java from its constituent parts such that the number keeps the properties as close as possible to the floating point literal?
My current idea is to try to create the exact bits in memory that would represent the floating point number using the IEEE 754 representation Java (and many languages) uses.
This blog post helped me understand the floating point representation, but I am still kind of stuck.
My current try to do that uses a ByteBuffer
which can do:
ByteBuffer buffer = ByteBuffer.allocate(8);
buffer.put(<bits representing the number exactly in floating point>);
buffer.flip();
double n = buffer.getDouble();
The "only" problem being, figuring out the right bits, which is not trivial (if someone knows a method to do that , please do share).
EDIT: Performance is important, so I am trying to avoid creating a String then throwing it at Double.parseDouble(str)
... as that feels pretty expensive compared to writing the bits into memory... but I might be wrong and this is indeed the most "efficient" option? Really don't know at this point, hopefully I can benchmark when I have a few options.
专注分享java语言的经验与见解,让所有开发者获益!
评论