4

我有一个需要转换为当前形式的数据库表。该表具有三列 Double 类型(Pervasive.SQL如果有人关心的话,它是 )。

我的问题是这张表已经存在了很长时间,并且它已经被代码可以追溯到大约 15 年或更长时间。

从历史上看,我们一直使用Double.MinValue(或当时任何等效的语言)来表示"blank"用户提供的值。换句话说,值的缺失实际上存储为我们以后可以识别并智能地做出反应的值。

所以,今天我的问题是我需要遍历这些记录并将它们插入到一个新创建的表中(这就是我所说的“转换”)。但是,我在要转换的表中没有看到一致的值。以下是我肯定知道的:

2.2250738585072014E-308
3.99285938963E-313
3.99099435427E-313
1.1125369292536007E-308
-5.389000690742776E279
2.104687961E-314

现在,我认识到Double.MinValue可能存在或至少可以代表其他方式。做了一些谷歌搜索后,我发现第一个是Double.MinValue(实际上DBL_MIN在这里引用:http: //msdn.microsoft.com/en-us/library/6bs3y5ya (v=vs.100).aspx )的另一种表示。

我不想太啰嗦,所以如果这些信息不足以帮助我,我会提出问题。可以这么说,我需要一种可靠的方法来发现所有先前的“最小值”值,并Double.MinValue在循环这些数据行时将它们替换为 C# 常量。

如果证明是dataRow["Value"] < someConstant,那就这样吧。但我会让数学理论家帮助我下定决心。

谢谢你的时间。

编辑:

当我找到它们时,这就是我对这些值所做的事情。它是组装要写入数据库的值的通用方法的一部分:

else if (c.DataType == typeof(System.Double))
{
    if (inRow[c] == DBNull.Value)
        retString += @"NULL";
    else
    {
        Double d;
        if (Double.TryParse(inRow[c].ToString(), out d))
        retString += d.ToStringFull();
    }
}

直到现在,它只是简单地接受了他们。这很糟糕,因为当应用程序找到它们时,它们看起来像是可接受的数据,而不像Double.MinValue。因此,不被视为空白。但这就是他们。

4

2 回答 2

10

这是彻头彻尾的疯狂。让我们详细看看其中的一些数字。这些都是仅略大于零的微小数字:

2.2250738585072014E-308

这是 1 / 2 1022 - 这是一个正常的双倍。这是您的集合中的两个“特殊”数字之一;它是大于零的最小正常双精度。你名单上其余的小双打都是不正常的双打。

1.1125369292536007E-308

这是 1 / 2 1023 - 这是一个低于正常值的双倍。这也是一个特殊的数字;它是大于零的最小正常双精度的一半。(我最初说它是最大的次正规双,但当然这不是真的;见评论。)

3.99285938963E-313

这没什么特别的。它是一个次正规的双精度数,等于分子为 154145 且分母为 2 的相当大的幂的分数。

3.99099435427E-313

这也没什么特别的。这次的分子是 154073。

2.104687961E-314

这也没什么特别的。分子是 2129967929,分母是 2 的更大幂。

到目前为止,所有数字都非常接近于零且为正数。这个数字远非零和负数,因此很突出:

-5.389000690742776E279

但这也没什么特别的。它甚至没有接近绝对值最大的负双倍,大约是-1.79E308,大约是十亿倍。

这是一团糟。

我的建议是立即停止这种疯狂行为。使用非常接近零的值来表示“空白”值是绝对没有意义的;非常接近零的值应四舍五入为零,而不是视为空白!

Double 已经有一个“空白”值的代表,即 Double.NaN -- Not A Number;当域已经包含特定的“无效”值时,使用有效值来表示无效值是很奇怪的。(请记住,实际上存在大量不同的 NaN 位模式;使用 IsNaN 来确定 double 是否为 NaN。)

所以我的建议是:

  • 单独检查数据库中每个低于正常或非常小的正常双精度数。其中一些可能应该为零,并且由于舍入误差而最终成为微小的值。用零替换它们。那些应该为空的,替换为数据库空(最佳实践)或双 NaN(可接受,但不如数据库空。)

  • 编写一个程序来查找数据库中绝对值不可能大的每个数字,并将其替换为数据库 null 或 double NaN。

  • 更新所有客户端,以便他们了解您用来表示空白值的约定。

于 2013-06-03T16:19:34.100 回答
0

您似乎想检查 adouble是否真的很小且为正数或真的很大、有限且为负数。(其他人在评论中详细说明了您的方法存在的一些问题;我不打算在这里讨论。)像这样的测试:

if (d == d && (d > 0 && d < 1e-290 || d < -1e270 && d + d != d))

可能会大致按照您的意愿行事。您可能需要调整上面的数字。d == d测试正在检查NaN,而测试d + d != d正在检查无穷大。

于 2013-06-03T16:06:36.567 回答