以升序循环遍历所有可表示的小数

时间:2018-09-22 21:12:55

标签: c# floating-point

如果我使用float的低31位(指数和尾数)并逐一循环,则所得的浮点数将从0开始到{{1 }},然后到float.MaxValue,然后再转到float.PositiveInfinity的许多不同位模式。

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

奖金:是否可以快速计算可能的数字?

其他信息:可以将1.0和1.00视为两个不同的数字。

1 个答案:

答案 0 :(得分:1)

decimal格式的符号位 s ,96位有效位 f 和指数 e 从0开始至28(含)。 ( s f e )的表示值为(-1) s f / 10 e

定义( s f e )的规范表示为( s f •10 n e + n )表示最大整数 n ,其中 f •10 n <2 96 e ≤28。如果 e 不为28,则规范有效位数在上限(2 96 / 10),2 96 −1(含)范围内。

我们可以通过以下方式按升序遍历非负decimal值:

    Set s = 0, e = 28.
    For f from 0 to 2^96 - 1, inclusive:
        Process (s, f, e) as a decimal value.
    For e from 27 down to 0, inclusive:
        For f from ceiling(2^96 / 10) to 2^96 - 1, inclusive:
            Process (s, f, e) as a decimal value.

我们可以看到这是升序的,因为f上的每个循环都以比上一个循环结束的更大的表示值开头。我们可以看到包含了每个可表示的值,因为任何规范表示( s f e )的值都出现在{{ 1}},其中f的值为 e 。我们无法看到任何重复的值,因为每个可表示的值在其规范表示中仅被处理了一次。

要将其限制为特定的上下限 L U ,我们可以找到 L U的规范表示形式。这些表示的组成部分告诉我们ef的开始和结束位置。该算法的替代形式可能更适合于此。假设efL L 的规范表示的 e f ,对于{{ 1}}和eL。那么一个算法是:

    (0) Set s to 0, f to fL, and e to eL.
    (1) If e ≤ eU and f > fU, stop.
    (2) Process (s, f, e) as a decimal number.
    (3) Set f to f+1.
    (4) If f is less than 2^96, go to (1).
    (5) Set e to e-1 and f to f/10.
    (6) Go to (1).

对负数的扩展是显而易见的。