C#中可空类型的替代方案

Rya*_*yan 12 c# nullable nan non-nullable

我正在编写适用于一系列数字数据的算法,有时,系列中的值必须为null.但是,由于此应用程序对性能至关重要,因此我避免使用可空类型.我已经对这些算法进行了性能测试,专门比较了使用可空类型和非可空类型的性能,在最好的情况下,可空类型的速度慢了2倍,但往往差得多.

最常用的数据类型是double,目前选择null的替代方法是double.NaN.但是我知道这不是NaN值的确切用途,所以我不确定是否有任何问题,我无法预见,最佳做法是什么.

我有兴趣找出以下数据类型的最佳空替代品:double/float,decimal,DateTime,int/long(尽管其他数据类型非常受欢迎)

编辑:我想我需要澄清我对性能的要求.数字数据的演出通过这些算法在几个小时的时间内处理.因此,虽然例如10毫秒或20毫秒之间的差异通常是微不足道的,但在这种情况下,它确实对所花费的时间产生了重大影响.

Mar*_*ell 18

好吧,如果您已经排除了Nullable<T>,那么您将获得域值 - 即您将其视为空值的幻数.虽然这并不理想,但这种情况并不少见 - 例如,许多主框架代码都将DateTime.MinValuenull 视为相同.这至少使损害远离共同的价值......

编辑以仅突出显示没有NaN的位置

所以,如果没有NaN,可能会使用.MinValue- 但只要记住,如果你不小心使用同一个值意味着相同的数字,会发生什么样的祸害......

显然,对于你需要的无符号数据.MaxValue(避免零!!!).

就个人而言,我会尝试使用Nullable<T>更安全地表达我的意图......可能有方法可以优化您的Nullable<T>代码.而且 - 当你在所有需要的位置检查神奇数字时,也许它不会比它快得多Nullable<T>

  • 我刚刚对 (i == int.MinValue || j == int.MinValue) 执行了快速简单的性能测试?int.MinValue : (i+j); 与可为空的 i+j 相比,令我惊讶的是,可为空的 i+j 慢了大约 3 倍! (2认同)

Fra*_*uma 5

在这个特定的极端情况下,我有点不同意 Gravell:一个 Null 变量被认为是“未定义”,它没有值。因此,无论用于表示什么都可以:即使是幻数,但对于幻数,您必须考虑到,当幻数突然变成“有效”值时,将来它总会困扰着您。使用 Double.NaN,您不必为此担心:它永远不会成为有效的 double。虽然,您必须考虑到双精度序列意义上的 NaN 只能用作“未定义”的标记,显然您也不能将其用作序列中的错误代码。

因此,无论用于标记“未定义”的任何内容:在值集的上下文中都必须清楚,该特定值被视为“未定义”的值,并且将来不会改变。

如果 Nullable 给您带来太多麻烦,请使用 NaN 或其他任何方法,只要您考虑后果:选择的值代表“未定义”并且将保留。


pet*_*hen 5

我正在做一个使用 NaN 作为null值的大型项目。我对它并不完全满意 - 出于与您类似的原因:不知道会出现什么问题。到目前为止,我们还没有遇到任何实际问题,但请注意以下几点:

NaN 算术- 虽然在大多数情况下,“NaN 提升”是一件好事,但它可能并不总是如您所愿。

比较- 如果您希望 NaN 比较相等,则值的比较会变得相当昂贵。现在,无论如何测试浮点数的相等性并不简单,但是排序 (a < b) 会变得非常难看,因为 nan 有时需要比正常值更小,有时需要更大。

代码感染- 我看到很多算术代码需要对 NaN 进行特定处理才能正确。因此,出于性能原因,您最终会得到“接受 NaN 的函数”和“不接受 NaN 的函数”。

其他非有限NaN 是唯一的非有限值。应该牢记...

浮点异常在禁用时不是问题。直到有人启用它们。真实故事:ActiveX 控件中 NaN 的静态初始化。听起来并不可怕,直到您将安装更改为使用 InnoSetup,它使用 Pascal/Delphi(?) 核心,默认情况下启用 FPU 异常。我花了一段时间才弄清楚。

所以,总而言之,没什么严重的,尽管我不想经常考虑 NaN。


我会尽可能多地使用 Nullable 类型,除非它们是(被证明是)性能/资源限制。一种情况可能是偶尔出现 NaN 的大向量/矩阵,或者默认 NaN 行为正确的大量命名单个值。


或者,您可以将索引向量用于向量和矩阵、标准的“稀疏矩阵”实现或单独的 bool/bit 向量。