将数字从 Excel 单元格转换为 IEEE 754 十六进制格式

问题描述 投票:0回答:2

最近,由于数字的 15 位有效数字显示限制,我一直在与 Excel 进行斗争。我一直在寻找一种方法来显示 Excel 单元格中包含的值的 IEEE 754 格式(因为它们已记录可以以这种方式工作)。

我更喜欢在这个项目中依赖VBA(尽管如果可能有类似

memcpy
的解决方案,我可能会受到诱惑)。

有关我当前的实现,请参阅下面的答案。任何意见或替代方案表示赞赏。我选择相信我错过了一个更简单、经过充分测试的解决方案。

excel floating-point ieee-754 floating-point-conversion
2个回答
3
投票

以下序列允许我使用 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)

我的一些结果:

  • 22222.0948199999 > 0x40D5B3861187E7A5
  • =1.35632902954101*2^14
    > 0x40D5B3861187E7A7
  • 22222.09482 > 0x40D5B3861187E7C0
  • 0.000123456 > 0x3F202E7EF70994DD
  • 1E+307 > 0x7FAC7B1F3CAC7433
  • -35.3 > 0xC041A66666666666
  • 1 > 0x3FF0000000000000

编辑:chux 评论的后续行动。

我们可以看到,由于舍入误差,以下值给出了错误的结果:

  • =255+0.9999999999999
    > 0x40700000FFFFFFFE

在这种情况下,步骤D1给出的值为负数。如果我使用此信息来更新我的指数,我的结果似乎是一致的:

  • =255+0.9999999999999
    > 0x406FFFFFFFFFFFFFC

这是更新后的B1公式:

  • 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)))

这没有预期的那么简单:

  • 我的 64 位答案依赖于使用 DEC2HEX 40 位限制的技巧。对于 32 位来说这是不必要的(并且不起作用)。
  • 尾数必须四舍五入,我必须对照 Excel 的 ROUND 检查 documentation我的方程的圆形部分尚未经过彻底测试:测试用例存在,但我不知道需要多少时间才能找到它们。

-1
投票

请使用以下表达式转换为小端格式的 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)) )

已测试并工作

© www.soinside.com 2019 - 2024. All rights reserved.