Java中double类型研究

    这个问题的兴趣,源自我在解析TCP/UDP数据协议的时候遇到的一个问题:

    

    这个数字,我是通过当前日期的时间微秒来获取的。

    以下是c语言来将这个时间转字节数组:

long long t = 1616491310637
double x;
unsigned char buf[8];
memcpy(buf,&t,sizeof(buf));
//[0x2d, 0xee, 0x63, 0x5e, 0x78, 0x01, 0x00, 0x00]
//小端序表示的字节序

    通过计算器计算16进制表示:

    

    在java里面,byte[]直接转long类型,不会有什么问题。而且非常巧合的是,byte[]转double竟然和byte[]转long类型有很相似的地方:

package com.xxx.huali.hualitest;
public class DataTransfer {
	private static final char[] HEX_STR = "0123456789ABCDEF".toCharArray();
	public static long bytes2Long(byte[] data) {
		long value = 0;
		for(int i=7;i>=0;i--) {
			value <<= 8;
			value |= (data[i]&0xff);
		}
		return value;
	}
	
	public static double bytes2Double(byte[] data) {
		long value = 0;
		for(int i=7;i>=0;i--) {
			value <<= 8;
			value |= (data[i]&0xff);
		}
		return Double.longBitsToDouble(value);
	}
	
	public static byte[] long2Bytes(long value) {
		byte[] data = new byte[8];
		for(int i=7;i>=0;i--) {
			data[i] = (byte)((value >> i*8) & 0xff);
		}
		return data;
	}
	
	public static byte[] double2Bytes(double value) {
		long d = Double.doubleToRawLongBits(value);
		byte[] data = new byte[8];
		for(int i=7;i>=0;i--) {
			data[i] = (byte)((d >> i*8) & 0xff);
		}
		return data;
	}
	
	public static String num2Hex(byte b) {
		StringBuffer sb = new StringBuffer();
		sb.append(HEX_STR[(b&0xf0)>>4]);
		sb.append(HEX_STR[b&0x0f]);
		return sb.toString().toLowerCase();
	}
	
	public static void main(String[] args) {
		byte[] data = new byte[] {0x2d, (byte)0xee, 0x63, 0x5e, 0x78, 0x01, 0x00, 0x00};
		long time = bytes2Long(data);
		System.out.println("long->"+time);
		byte[] res = long2Bytes(time);
		for(int i=0;i<8;i++) {
			System.out.print(num2Hex(res[i])+" ");
		}
		System.out.println();
		byte[] darr = new byte[] {0x00, (byte)0xd0,(byte)0xe2, 0x3e, (byte)0xe6, (byte)0x85, 0x77, 0x42 };
		double d2 = bytes2Double(darr);
		System.out.println("double->"+d2);
		byte[] res2 = double2Bytes(d2);
		for(int i=0;i<8;i++) {
			System.out.print(num2Hex(res2[i])+" ");
		}
		System.out.println();
		
	}
}

     这段代码运行的结果如下所示:

long->1616491310637
2d ee 63 5e 78 01 00 00 
double->1.616491310637E12
00 d0 e2 3e e6 85 77 42 

    这里重点我们看转换的代码,无论是数字转字节,还是字节转数字,在java里面,double与long类型有着非常密切的关系:

     

    这里唯一不一样的地方在于最后一步返回的时候,一个直接返回,一个需要通过Double.longBitsToDouble()转换一下。

    接着看看字节转数字:

    

    double类型,在转byte[]之前,需要通过一个Double.doubleToRawLongBits()转为long类型,然后进行按位取值。

    重点

    我的问题是什么呢,就是我与嵌入式终端约定是解析double类型的字节码,但是他们给我传过来的是longlong类型的整数,java端按照double来解析,发现走到这一步:

    

    实际上,经过最后一步Double.longBitsToDouble()之后,结果就发生了翻天覆地的变化了,我又懵逼了,不知道如何解释,只能靠猜,终端是不是搞错了,明明是double的,最后传过来的却是longlong,我经过各种确认,最后发现他们确实搞错了。

    不过,从这件事情里面我感觉java里面的double应该和long有着很紧密的联系。

    我们再来看看long与double转换字节之后的结果:

    

    字面值和类型转换,他们确实有些关系,但是他们的取值范围却相差很大。

    long       -> 2^63-1     =  9223372036854775807 (19位)            最大值

    double   ->2^1024-1  =  1.7976931348623157E308(309位)      最大值

     有意思的是,double最大值只能通过Double.MAX_VALUE表示,我想着你既然是2^1024-1,那肯定也可以通过其他的数学表达式表示出来,结果Math.power(2,1024)-1直接显示Infinity。

     那就按照推导的方式:2^1024-1 = 2^1023^2 -1 = 2^1023+2^1023-1还是不行,看来要利用2^1023+2^1022+2^1021+2^1020+...-1的方式了。

     我最后用试的办法终于试出来了:

double m = 0;
for(int i = 971;i<1024;i++) {
    m+=Math.pow(2, i);
}

    令我比较惊讶的是,字面上的结果已经就是 1.7976931348623157E308 了,我以为是个近似值,结果和Double.MAX_VALUE一比较,嗨,竟然相等:

package com.xxx.huali.hualitest;

public class LongValueTest {
	public static void main(String[] args) {
		long l = Long.MAX_VALUE;
		long l2 = l-1;
		System.out.println("max(long):"+l);
		System.out.println(l==l2);
		double d = Double.MAX_VALUE;
		double e = d-1;
		System.out.println("max(double):"+d);
		System.out.println(d==e);
		System.out.println(Double.MAX_EXPONENT);
		double m = 0;
		for(int i = 971;i<1024;i++) {
			m+=Math.pow(2, i);
		}
		System.out.println("max(double):"+m);
		System.out.println(m==Double.MAX_VALUE);
	}
}

 打印结果:

max(long):9223372036854775807
false
max(double):1.7976931348623157E308
true
1023
max(double):1.7976931348623157E308
true

  有些意外,理论上2^1024-1 肯定不会只是 2^971+2^972+...+2^1023,计算机里的事情,谁说的清呢。 

  另一个有意思的事情是:long类型的整数,最大值-1 != 最大值  ,这个好理解,但是double类型 最大值-1 == 最大值,这个好奇葩啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值