C#编译器不限制浮点文本小数部分的位数

C#编译器不限制浮点文本小数部分的位数,c#,C#,这只是为了学术目的 我注意到对于整型文字,我们可以声明多达 18446744073709551615这是2^64-1或ulong.MaxValue。定义大于此值会产生编译时错误 对于浮点文本,我们可以声明它们的整数部分,最多为999…999(9重复308次)。用更多的数字声明整数部分会再次产生编译时错误。我感兴趣的一件事是,编译器似乎允许我们指定小数部分,不限位数。实际上,小数部分的无限位数是没有意义的 问题: 是否有一个常数表示C#编译器内部为浮点数的小数部分定义的最大位数 如果存在这样一个常

这只是为了学术目的

我注意到对于整型文字,我们可以声明多达
18446744073709551615
这是
2^64-1
ulong.MaxValue
。定义大于此值会产生编译时错误

对于浮点文本,我们可以声明它们的整数部分,最多为
999…999
9
重复308次)。用更多的数字声明整数部分会再次产生编译时错误。我感兴趣的一件事是,编译器似乎允许我们指定小数部分,不限位数。实际上,小数部分的无限位数是没有意义的

问题:

  • 是否有一个常数表示C#编译器内部为浮点数的小数部分定义的最大位数

  • 如果存在这样一个常量,当用户指定的小数部分超出其限制时,为什么C#编译器不抛出编译时错误

  • 最小工作示例1 最小工作示例2 IL:

  • 是的,但它们不是十进制数字
  • 当规范为十进制且表示为二进制时,很容易指定无法精确表示的小数部分<代码>0.3已经需要近似值

  • 我不知道浮点文本中允许的小数数量有任何限制,尽管测试这种限制是否确实存在应该相对简单,但如果确实存在,它可能更多地取决于编译器内部,而不是特定于浮点值本身。然而,我认为值得思考的是,限制文字中小数的数量是否有意义。我认为这里的关键点是无法表示的数字之间的区别,因为它们超出了double数据类型(由编译器拾取)的支持范围,而无法在数据类型中精确表示


    确实有许多十进制数不能精确地表示为双精度(例如0.1),但编译器会默默地接受它们,将它们转换为最接近的可表示值,如果不这样做,将会带来极大的不便。因此,为什么要对超过小数的文字进行不同的处理?

    在大多数情况下,浮点数无论如何都是所需实数的近似值(除非它恰好是可以精确表示的值之一)。此外,近似值定义良好:只需四舍五入到最接近的可表示值。另一方面,没有有效的方法将整数(或实数的整数部分)四舍五入到最接近的可表示值。例如,将2^100四舍五入到2^64-1意味着什么?

    我不能肯定,但如果我不得不猜测,它可能在以下新闻中出现:如果指定的文本不能在指定的类型中表示,则会发生编译时错误。类型为
    float
    double
    的实文本的值是通过使用IEEE“四舍五入到最近的”模式来确定的。因此,在这种情况下,这个疯狂的长值可以“表示”为浮点数(几乎所有的值都是近似值),也可以是“IEEE四舍五入到最近的”模式“这可能允许这样做。您不需要太多的数字来查看行为,
    0.999999999999 5
    表示为
    0.999999999999
    ,其中
    0.999999999999 51
    表示为
    1
    。对于小数位,它似乎四舍五入到最接近的可表示值(只要它在
    Double.MinValue
    Double.MaxValue
    之间)。因此
    constdouble d=0.999…
    (重复到2000位)在IL代码中被编译为
    1
    。也就是说,
    constdouble@d=1;
    编译为与
    constdouble@Double=0.999…;完全相同的IL代码;
    可能不会“有意义”,但由于您输入的任何势力都可能不作为精确值存在,因此它可能使用相同的近似规则,并且是可表示的,而在最小/最大范围之外则不可表示(因此是一个错误)。
    namespace FloatingPoint
    {
        class Program
        {
            static void Main(string[] args)
            {
                const ulong @ulong = 18446744073709551615;
                const double @double = 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
    
            }
        }
    }
    
    using System;
    
    namespace FloatingPoint
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                const double x01 = 0.9;
                const double x02 = 0.99;
                const double x03 = 0.999;
                const double x04 = 0.9999;
    
                const double x05 = 0.99999;
                const double x06 = 0.999999;
                const double x07 = 0.9999999;
                const double x08 = 0.99999999;
    
                const double x09 = 0.999999999;
                const double x10 = 0.9999999999;
                const double x11 = 0.99999999999;
                const double x12 = 0.999999999999;
    
                const double x13 = 0.9999999999999;
                const double x14 = 0.99999999999999;
                const double x15 = 0.999999999999999;
                const double x16 = 0.9999999999999999;
    
                const double x17 = 0.99999999999999999;
                const double x18 = 0.999999999999999999;
                const double x19 = 0.9999999999999999999;
                const double x20 = 0.99999999999999999999;
    
                Console.WriteLine(x01);
                Console.WriteLine(x02);
                Console.WriteLine(x03);
                Console.WriteLine(x04);
                Console.WriteLine(x05);
                Console.WriteLine(x06);
                Console.WriteLine(x07);
                Console.WriteLine(x08);
                Console.WriteLine(x09);
                Console.WriteLine(x10);
                Console.WriteLine(x11);
                Console.WriteLine(x12);
                Console.WriteLine(x13);
                Console.WriteLine(x14);
                Console.WriteLine(x15);
                Console.WriteLine(x16);
                Console.WriteLine(x17);
                Console.WriteLine(x18);
                Console.WriteLine(x19);
                Console.WriteLine(x20);
    
            }
        }
    }
    
    /* output:
    
    0.9
    0.99
    0.999
    0.9999
    0.99999
    0.999999
    0.9999999
    0.99999999
    0.999999999
    0.9999999999
    0.99999999999
    0.999999999999
    0.9999999999999
    0.99999999999999
    0.999999999999999
    1
    1
    1
    1
    1
    */
    
    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      // Code size       302 (0x12e)
      .maxstack  1
      IL_0000:  nop
      IL_0001:  ldc.r8     0.90000000000000002
      IL_000a:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_000f:  nop
      IL_0010:  ldc.r8     0.98999999999999999
      IL_0019:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_001e:  nop
      IL_001f:  ldc.r8     0.999
      IL_0028:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_002d:  nop
      IL_002e:  ldc.r8     0.99990000000000001
      IL_0037:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_003c:  nop
      IL_003d:  ldc.r8     0.99999000000000005
      IL_0046:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_004b:  nop
      IL_004c:  ldc.r8     0.99999899999999997
      IL_0055:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_005a:  nop
      IL_005b:  ldc.r8     0.99999990000000005
      IL_0064:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_0069:  nop
      IL_006a:  ldc.r8     0.99999998999999995
      IL_0073:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_0078:  nop
      IL_0079:  ldc.r8     0.99999999900000003
      IL_0082:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_0087:  nop
      IL_0088:  ldc.r8     0.99999999989999999
      IL_0091:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_0096:  nop
      IL_0097:  ldc.r8     0.99999999999
      IL_00a0:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00a5:  nop
      IL_00a6:  ldc.r8     0.99999999999900002
      IL_00af:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00b4:  nop
      IL_00b5:  ldc.r8     0.99999999999989997
      IL_00be:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00c3:  nop
      IL_00c4:  ldc.r8     0.99999999999999001
      IL_00cd:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00d2:  nop
      IL_00d3:  ldc.r8     0.999999999999999
      IL_00dc:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00e1:  nop
      IL_00e2:  ldc.r8     0.99999999999999989
      IL_00eb:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00f0:  nop
      IL_00f1:  ldc.r8     1.
      IL_00fa:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_00ff:  nop
      IL_0100:  ldc.r8     1.
      IL_0109:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_010e:  nop
      IL_010f:  ldc.r8     1.
      IL_0118:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_011d:  nop
      IL_011e:  ldc.r8     1.
      IL_0127:  call       void [mscorlib]System.Console::WriteLine(float64)
      IL_012c:  nop
      IL_012d:  ret
    } // end of method Program::Main