稍微翻了一下 Java spec
理论上你的数 (0x1.0p-1022) 应该 .toString() 的结果
必须至少要到 "2.2250738585072014e-308" 这么多位才行
(Java API 有规定转换结果的精确度必须足以在转换回来时唯一决定为原数
http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#toString-double-
可以看上述连结里有提到)
不过 0x1.0p-1022 这其实是个很特别的 double 浮点数:
它是所谓“正常表示”的 double 里最小的一个, 也就是 Double.MIN_NORMAL 这数
比它小的浮点数其储存方式跟一般的浮点数是不一样的
也因为这样, 有些手机架构里为了硬件设计和计算方便
有一个系统层的开关可以控制计算时要不要出现这种数
不要的话比 MIN_NORMAL 小的正数就会全部变成 0
这跟我们的问题的关连就在于
和 0x1.0p-1022 接近的两个浮点数
比它大的是 0x1.0000000000001p-1022
比它小的是 0x0.fffffffffffffp-1022 (←这个是非标准表示)
它们转换成十进制是: (多写几位以资比较)
0x1.0000000000001p-1022 = 2.22507385807201877...e-308
0x1.0p-1022 = 2.22507385807201383...e-308
0x0.fffffffffffffp-1022 = 2.22507385807200889...e-308
因此在一般的系统里, 单写 2.22507385807201 是会错误的辨认为最后一个的
所以 Java API 规定必须多输出一位以资判断
但在没有这种小小数的系统里
它只要能跟比它大的 0x1.0000000000001p-1022 分别就好
最接近 2.22507385807201e-308 的普通浮点数是 0x1p-1022 这就足够了
====
不过!以上讲了这么半天, 有一个很重要的事实上面没有提到:
Java 语言定义里的 double 一直都是有这种小小数的标准 IEEE754 浮点数
所以照理来说只要照着 Java 的规定来的话
不管在哪里都应该得要能够使用小小数所以必须做这种分别才对
问题来了: 我们都知道 Android 的 Java 不是标准 Java
它只是拿了 Java 的 API 来自己定义著用而已 (那件官司相信大家记忆犹新)
所以如果 Android 那边并没有这种细节规定的话, 那就有可能产生不同结果
而事实上正是这样:
http://developer.android.com/reference/java/lang/Double.html#toString(double)
Android 官方的 Double.toString(double) 的说明里只有简短一行
Returns a string containing a concise, human-readable description of the
specified double value.
跟 Java 官方的 Double.toString(double) (上面的连结) 那么落落长完全不同
所以根本原因其实并不是硬件结构的关系, 而是 API 规定上根本就不一样
因此所产生的结果也就有可能不一样了
(我有点怀疑 Android 版的 toString() 该不会是那种
在科学记号的小数点后面固定取 15 位的懒人但错误的实作法...
这样是并不足以使得转换回来的所有浮点数都是正确了的)