【问题标题】:Looping through all representable decimals in ascending order按升序遍历所有可表示的小数
【发布时间】:2019-02-26 21:04:55
【问题描述】:

如果我取 float 的低 31 位(指数和尾数)并一个接一个地遍历它们,得到的浮点数按升序排列,从 0 开始,到 float.MaxValue,然后到 @ 987654325@,然后是float.NaN 的许多不同位模式。

这个不错的属性似乎不适用于decimal 数据类型。有没有办法以类似的方式按升序遍历所有可表示的十进制值(在下限和上限之间)?

奖励:是否有快速计算可能数字的方法?

附加信息:可以将 1.0 和 1.00 算作两个不同的数字。

【问题讨论】:

  • 你在这里读过乔恩的回答吗? stackoverflow.com/questions/3801440/… 或许能有所启发。据我所知,这可能是不可能的,因为同一个数字有多种表示形式。
  • @AlexandruClonțea:遍历所有可表示的值当然是可能的。一个人会跳过非规范表示(对于任何所需的规范分配)。
  • @EricPostpischil 啊....好点。可能是时候睡觉了。脑子慢。这么晚了不能编辑我的评论,我仍然认为那篇文章可能有用
  • @AlexandruClonțea:我读过这篇文章,我知道decimal 数据类型在内存中的样子。我仍然没有找到一个好方法来枚举或计算两个给定小数 min 和 max 之间的可表示小数。

标签: c# floating-point


【解决方案1】:

decimal 格式有一个符号位 s、一个 96 位有效位 f 和一个从 0 到 28 的指数 e , 包括的。 (s,f,e)的表示值为(-1)s sup> • f / 10e.

定义 (s, f, e) 的规范表示为 (s, f • 10n, e+n) 为最大整数n 其中 f • 10n96 和 e ≤ 28。如果 e 不是 28,则规范有效数字在上限 (296/10)、296-1 中,包括在内。

我们可以按升序遍历非负 decimal 值:

设置 s = 0,e = 28。 对于 f 从 0 到 2^96 - 1,包括: 将 (s, f, e) 处理为十进制值。 对于从 27 到 0 的 e,包括: 对于 f 从上限 (2^96 / 10) 到 2^96 - 1,包括: 将 (s, f, e) 处理为十进制值。

我们可以看到这是升序,因为f 上的每个循环都以比前一个循环结束的更大的表示值开始。我们可以看到每个可表示的值都包含在内,因为任何规范表示(sfe)的值都出现在@987654324 的循环中@ 其中e 的值为e。我们可以看到没有重复的值,因为每个可表示的值都只处理一次,在其规范表示中。

为了将其限制在特定的上下限 LU,我们可以找到 LU 的规范表示。这些表示的组成部分告诉我们在哪里开始和结束fe。算法的替代形式可能更适合于此。让fLeL 成为L 的规范表示的ef,同样对于fU 和@987654331 @。那么一个算法就是:

(0) 将 s 设置为 0,将 f 设置为 fL,将 e 设置为 eL。 (1) 如果 e ≤ eU 且 f > fU,则停止。 (2) 将 (s, f, e) 处理为十进制数。 (3) 将 f 设为 f+1。 (4) 如果 f 小于 2^96,则转到 (1)。 (5) 将 e 设置为 e-1,将 f 设置为 f/10。 (6) 转到(1)。

负数的扩展很明显。

【讨论】:

  • 感谢您抽出宝贵时间,我将对其进行测试,但第一次“深思熟虑”看起来很有希望!如果可能的话会多次投票:)
猜你喜欢
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-16
  • 1970-01-01
  • 2017-11-05
  • 2017-03-09
相关资源
最近更新 更多