【问题标题】:Print decimal fixed-point/float formats as hexadecimal [closed]将十进制定点/浮点格式打印为十六进制 [关闭]
【发布时间】:2020-02-10 05:37:41
【问题描述】:

在我的通用库中添加将十进制定点数打印为十六进制的功能,并意识到我不是 %100 确定我应该如何表示数字的小数部分。快速谷歌搜索表明我应该:

  1. 乘以 16
  2. 将整数部分转换为十六进制并添加到缓冲区中
  3. 去掉整数部分
  4. 重复

这里建议https://bytes.com/topic/c/answers/219928-how-convert-float-hex

此方法适用于浮点数(ieee 754 二进制格式),并且可以正常工作。但是,我尝试将其应用于我的十进制定点(按 8 缩放)格式,并且在纸上测试这种方法后,我注意到一些分数(即 .7),这会导致重复模式.B3333...等等。 对我来说,这看起来很不受欢迎。我还想知道如果我尝试将它从字符串读取到我的定点格式中,这是否会导致精度损失。

有什么理由为什么有人不会像任何其他 2s 补码十六进制数一样打印小数部分?即 17535.564453 打印为 447F.89CE5

虽然这是针对十进制定点的,但我正在寻找一种也可用于其他实数格式(例如 ieee 754 二进制)的解决方案。

也许这两种方法还有另一种选择。有什么想法吗?

【问题讨论】:

  • 为什么不直接使用%a 格式?见这里:cplusplus.com/reference/cstdio/printf 它的设计目的是精确地表示浮点数,而不会损失精度。
  • @alias 2 原因。问题中提到的#1,这是我不支持的定点格式。尽管我可能也会将此处找到的任何解决方案应用于 IEEE 754 格式。 #2 不能使用任何标准库。这真的不是如何做的问题,而是为什么以及是否有更好的方法的问题。
  • “其中 17535.564453 打印为 447F.89CE5”令人困惑。 17535.53830432891845703125(基数 10)是 447F.89CE5(基数 16)和 17535.564453(基数 10)是 447F.907FFDE...(基数 16)。解释 17535.564453 如何转换为 447F.89CE5。这不符合上面的步骤 1-4。
  • “我还想知道,如果我尝试将它从字符串读取到我的定点格式中,这是否会导致精度损失。” --> 如果代码读入.B3333...,它将永远不会完成,因为这是一个无限长的输入。如果代码读入_足够的_.B3333...,那么精度损失可以最小化。到现在为止,需要公布多少“十进制定点数”的编码细节。
  • 当它是关于定点格式时,为什么用浮点标准 IEEE-754 标记?为什么用浮点标记?

标签: c math floating-point ieee-754 fixed-point


【解决方案1】:

尽管问题涉及定点,但 C 标准在其信息中提供了一些有用的信息,用于浮点的 %a 格式。 C 2018 7.21.6.1 8 说:

...如果 [user-requested] 精度缺失且 FLT_RADIX 不是 2 的幂,则精度足以区分 double 类型的285) 值,除了尾随零可以省略;…

脚注 285 说:

p 的精度足以区分源类型的值 if 16p-1 > b n 其中bFLT_RADIXn 是基数-b 源类型的有效数字中的数字...

为了直观地看到这一点,可视化实数线上从 0 到 1 的十进制定点数。对于每个这样的数字 x,可视化从前一个定点数中间开始的线段并在下一个定点数中途结束。除端点外,该段中的所有点都更接近 x,而不是它们与前一个或下一个数字的距离。现在,考虑所有单个十六进制数字 j/16 的位置。它们位于其中的一些部分。但是,如果有 100 个段(来自两位十进制数字),则大多数段不包含其中一个十六进制数字。如果增加十六进制位数,p,直到 16p−1 > bn,那么16进制数之间的间距小于段的宽度,每段包含一个16进制数。

这表明使用 p 十六进制数字足以区分由 bn 十进制数字组成的数字。 (这已经足够了,但它可能比必要的多。)这意味着存在恢复原始十进制数所需的所有信息,并且避免在恢复原始十进制数时失去任何准确性是编程从十六进制转十进制正确。

如果不考虑前导零,则“像任何其他十六进制数字一样”打印分数是不够的。十进制数“3.7”和“3.007”是不同的,所以小数部分不能只格式化为“7”。如果采用约定将小数部分**包括尾随零**转换为十六进制,那么这可以工作。例如,如果十进制定点数在小数点后有四个十进制数字,则将 3.7 和 3.007 的小数部分视为 7000 和 0070 并将它们转换为十六进制将保留所需的信息。转换回来时,将十六进制转换为十进制,将其格式化为四位数,并将其插入十进制定点数。在需要速度的情况下,这可能是一个合适的解决方案,但它不能很好地代表人类使用。

当然,如果一个人只是希望保留数字中的信息,以便可以传输或存储并稍后恢复,那么人们不妨简单地传输代表数字的位,使用最容易计算的任何转换,例如将所有原始位格式化为十六进制。

【讨论】:

  • 我很难想象您对使用 p 十六进制数字的描述。我将努力解决这个问题并报告结果。在那之前,你有我的赞成票。谢谢
  • @AlwaysNub:想象一下 100 个十进制值 .00、.01、.02、... .98、.99 分布在 0 和 1 之间。这 16 个十六进制值 .0、.1、 … .A、.B、.C、.D、.E、.F 说谎?显然,每对十进制值之间没有一个十六进制值。您需要 256 个十进制值来确保每对十进制值之间都有一个。因此,用于十六进制显示的精度必须至少与十进制精度一样精细(“精细”在精细与粗糙意义上)。
  • 好的。我跟着你。我没有时间深入研究这个,因为我整个星期都很忙。这个周末我会做一些计算,看看我需要多少个十六进制数字。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
相关资源
最近更新 更多