等效于 VBA 指数形式的 C# 数据类型

标签 c# .net vba excel

我有一个旧的 VBA 应用程序,它生成的值类似于 1.123456789123456789123456789E-28。当我在 C# 中搜索等效数据类型时,我在 SO Difference between decimal, float and double in .NET? 中找到了这篇文章。根据这篇文章的建议,十进制数据类型在 C# 中具有最大的大小。所以我使用了 decimal 数据类型,但我发现 decimal 在表示 VBA 以指数形式表示的大值方面似乎受到限制。所以我再次谷歌搜索并找到了这篇文章 https://msdn.microsoft.com/en-us/library/ae55hdtk.aspx 。如本文所述,

Nonintegral number values can be expressed as mmmEeee, in which mmm is the mantissa (the significant digits) and eee is the exponent (a power of 10). The highest positive values of the nonintegral types are 7.9228162514264337593543950335E+28 for Decimal, 3.4028235E+38 for Single, and 1.79769313486231570E+308 for Double.

这意味着 Double 数据类型具有最大的取值范围。所以现在我对十进制和 double 感到困惑。

然后我用下面的代码做了一个小实验

    double dbl = 1.123456789123456789123456789E-28;
    decimal dcl = 1.123456789123456789123456789E-28M;
    MessageBox.Show(dbl.ToString());
    MessageBox.Show(dcl.ToString());

dbl 打印值为 1.123456789123456789123456789E-28,而 dcl 值变为 0.00000000000000000000000000001; 有人可以解释这里发生了什么吗?在 C# 中以相同的精度表示像 VBA 中的大指数值的等效数据类型是什么?

最佳答案

根据C#语言规范:https://msdn.microsoft.com/en-us/library/aa691085%28v=vs.71%29.aspx

  • A real literal suffixed by F or f is of type float. For example, the literals 1f, 1.5f, 1e10f, and 123.456F are all of type float.
  • A real literal suffixed by D or d is of type double. For example, the literals 1d, 1.5d, 1e10d, and 123.456D are all of type double.
  • A real literal suffixed by M or m is of type decimal. For example, the literals 1m, 1.5m, 1e10m, and 123.456M are all of type decimal. This literal is converted to a decimal value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker's rounding (Section 4.1.7). Any scale apparent in the literal is preserved unless the value is rounded or the value is zero (in which latter case the sign and scale will be 0). Hence, the literal 2.900m will be parsed to form the decimal with sign 0, coefficient 2900, and scale 3.

查看第三个要点,您可以看到短语“...通过取精确值...将此文字转换为十进制值...”。您获得的值 ( 0.0000000000000000000000000001 ) 是您开始使用的输入文字 ( 1.123456789123456789123456789E-28M ) 的转换结果。当然,根据关于转换的第三个要点的第二部分四舍五入的值“...如有必要,使用银行家舍入法四舍五入到最接近的可表示值...”。

对于 decimal 是这样,但是对于 floatdouble 指数符号可以由数据类型本身保留,因此不需要转换/舍入。

添加:

要进一步扩展上述内容,请参阅:https://msdn.microsoft.com/en-us/library/364x0z75.aspx

这是 decimal 数据类型的定义。如那里所述: decimal 的范围是 (-7.9 x 1028 to 7.9 x 1028) / (100 to 28)28 to 29 significant digits 。您的文字 1.123456789123456789123456789E-28M 超出了该限制,因此在转换时,1 右侧的所有内容都会按照上述规则四舍五入。

解决方案(?):

如果您需要比 decimal 所能提供的更高的精度,您可能需要考虑实现您自己的类,这绝对是可行的。考虑搜索 BigDecimal 的 C# 实现以获取想法。

我在快速谷歌上找到的一个实现:https://gist.github.com/nberardi/2667136

我不能说它的正确性,但它至少可以作为你的起点。

关于等效于 VBA 指数形式的 C# 数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40594196/

相关文章:

c# - 抛出 ArgumentNullException

c# - 在这种情况下如何返回 List<MyInterface>

vba - Excel VBA - 循环变量

c# - C# 中对象的有效 JSON

c# - 如何要求正在运行的进程打开文件?

c# - 如何设置电源设置关闭 : never (turn off the display= never, 让计算机进入休眠状态 = 从不),通过 c# 代码

vba - MS Access VBA IF()

vba - 如何包裹Excel光标以将其保持在特定范围内

c# - 在 C# 中检查一个 VB.NET 对象是否为 null 会产生意外的编译错误

C# 代码列出从起始方法调用的所有方法?