最近,由于数字的 15 位有效数字显示限制,我一直在与 Excel 进行斗争。我一直在寻找一种方法来显示 Excel 单元格中包含的值的 IEEE 754 格式(因为它们已记录可以以这种方式工作)。
我更喜欢不在这个项目中依赖VBA(尽管如果可能有类似
memcpy
的解决方案,我可能会受到诱惑)。
有关我当前的实现,请参阅下面的答案。任何意见或替代方案表示赞赏。我选择相信我错过了一个更简单、经过充分测试的解决方案。
以下序列允许我使用 Excel 公式将数字转换为其 IEEE 754 十六进制表示形式。 除了 0 之外,我没有尝试处理任何异常。从单元格 A1 到 G1:
A1:
0.123456
B1:
=INT(LOG(ABS(A1),2))
指数
C1:
=ABS(A1)/(2^B1)
尾数
D1:
=(C1-1)*(2^52)
将尾数转换为小数
E1:
=DEC2HEX(1023+B1+IF(A1<0,2^11,0),3)
将符号和指数转换为十六进制
F1:
=CONCATENATE(DEC2HEX(D1/2^32,5),DEC2HEX(MOD(D1,2^32),8))
将十进制转换为十六进制。
G1:
="0x"&IF(A1=0,0,E1&F1)
我的一些结果:
=1.35632902954101*2^14
> 0x40D5B3861187E7A7编辑:chux 评论的后续行动。
我们可以看到,由于舍入误差,以下值给出了错误的结果:
=255+0.9999999999999
> 0x40700000FFFFFFFE在这种情况下,步骤D1给出的值为负数。如果我使用此信息来更新我的指数,我的结果似乎是一致的:
=255+0.9999999999999
> 0x406FFFFFFFFFFFFFC这是更新后的B1公式:
=IF((ABS(A1)/(2^INT(LOG(ABS(A1),2)))-1)*(2^52)<0,INT(LOG(ABS(A1),2))-1,INT(LOG(ABS(A1),2)))
EDIT2:使用 LET 的单个函数中的上述步骤(在 Microsoft 365 中可用)
=LET(num,A1,
exp,INT(LOG(ABS(num),2)),
exponent,IF((ABS(num)/(2^exp)-1)*(2^52)<0,exp-1,exp),
mantissa,(ABS(num)/(2^exponent)-1)*(2^52),
part_a,DEC2HEX(1023+exponent+IF(num<0,2^11,0),3),
part_b,CONCATENATE(DEC2HEX(mantissa/2^32,5),DEC2HEX(MOD(mantissa,2^32),8)),
"0x"&IF(num=0,0,part_a&part_b))
*EDIT3:由于这一点已经提出两次,我在我的答案中添加了 32 位浮点格式的“最有可能正确”的答案。
=LET(num,A1,
exp,INT(LOG(ABS(num),2)),
exponent,IF((ABS(num)/(2^exp)-1)*(2^23)<0,exp-1,exp),
base_mantissa,(ABS(num)/(2^exponent)-1)*(2^23),
round_nearest_tie_even,IF(base_mantissa-INT(base_mantissa)=0.5,EVEN(base_mantissa),ROUND(base_mantissa,0)),
"0x"&IF(num=0,0,DEC2HEX((127+exponent+IF(num<0,2^8,0))*(2^23)+round_nearest_tie_even,8)))
这没有预期的那么简单:
请使用以下表达式转换为小端格式的 32 位十六进制。将浮点值放入单元格 A1 或更改以下表达式
=( (右("00"&BIN2HEX((IF(IF(A1<0,-1,1)=1,0,1))&LEFT((RIGHT("00000000"&DEC2BIN(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127),8)),7)),2)) & (RIGHT("00"&BIN2HEX(RIGHT((RIGHT("00000000"&DEC2BIN(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127),8)),1)&(RIGHT("0000000"&DEC2BIN(INT(INT((IF(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127=0,ROUND((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))4194304,0)),ROUND(((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))-1)(8388608),0)))/256)/256) ),7))),2)) & (右("00"&BIN2HEX(右("00000000"&DEC2BIN(((INT((IF(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127=0,ROUND((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))4194304,0),ROUND(((A1/2^(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))-1)) (8388608),0)))/256)/256)-INT(INT((IF(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127=0,ROUND((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))4194304,0),ROUND(((A1/2^(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))-1) (8388608),0)))/256)/256))*256),8)),2)) & (右("00"&BIN2HEX(右("00000000"&DEC2BIN(((IF(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127=0,ROUND((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))4194304,0),ROUND(((A1/2^(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))-1)(8388608) ),0)))/256)-(INT((IF(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2)))+127=0,ROUND((A1/2^(IF(ABS(A1)<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))4194304,0),ROUND(((A1/2^(IF(ABS(A1))<1.1754943E-38,-127,INT(LOG(ABS(A1))/LOG(2))))/(IF(A1<0,-1,1)))-1)(8388608),0) ))/256)))*256),8)),2)) )
已测试并工作