为啥 SQL 浮点数与 C# 浮点数不同

Posted

技术标签:

【中文标题】为啥 SQL 浮点数与 C# 浮点数不同【英文标题】:Why is a SQL float different from a C# float为什么 SQL 浮点数与 C# 浮点数不同 【发布时间】:2010-09-12 11:01:15 【问题描述】:

您好,我从 DataSet 中的 DataTable 中提取了一个 DataRow。我正在访问在 SQL 中定义为浮点数据类型的列。我正在尝试将该值分配给局部变量(c# float 数据类型),但得到一个 InvalidCastExecption

DataRow exercise = _exerciseDataSet.Exercise.FindByExerciseID(65);
_AccelLimit = (float)exercise["DefaultAccelLimit"];  

现在,玩弄这个我确实让它工作了,但它没有任何意义,而且感觉不对。

_AccelLimit = (float)(double)exercise["DefaultAccelLimit"];

谁能解释我在这里缺少什么?

【问题讨论】:

【参考方案1】:

它“感觉不对”的原因是因为 C# 对 unboxingcasting 使用相同的语法,这是两个非常不同的东西。 exercise["DefaultAccelLimit"] 包含一个双精度值,被装箱为一个对象。需要(double) 才能将对象拆箱重新转换为双精度对象。前面的 (float) 然后 casts 将双精度值转换为浮点值。 C# 不允许在同一操作中进行装箱和强制转换,因此必须先取消装箱,然后再进行强制转换。

即使演员表是非破坏性的也是如此。如果将浮点数装箱为要转换为双精度的对象,则可以这样做:(double)(float)object_var

【讨论】:

【参考方案2】:

我认为这里已经回答了主要问题,但我觉得有必要为问题的部分添加一些内容,说明这有效。

_AccelLimit = (float)(double)exercise["DefaultAccelLimit"];

这个“有效”的原因和它“感觉不对”的原因是你在第二次演员(左边的那个)之前将双精度降级为浮点数,所以你正在失去精度并有效地告诉编译器认为可以截断返回的值。

一句话,这行表明...... 获取一个对象(在这种情况下恰好包含一个双精度对象) 将对象转换为双精度(丢失所有对象包装) 将双精度转换为浮点数(失去双精度的所有精细精度)

例如如果值是说 0.0124022806089461 并且您执行上述操作,那么 AccelLimit 的值将是 0.01240228

因为这是 c# 中的浮点数可以从双精度值中获得的程度。 这是一件危险的事情,我很确定它也是截断而不是四舍五入,但有人可能想确认这一点,因为我不确定。

【讨论】:

【参考方案3】:

如果您计划对数据执行数学计算,通常您永远不会希望在 SQL Server(或真实)中使用浮点数,因为它是不精确的数据类型,并且会引入计算错误。如果需要精度,请改用十进制数据类型。

【讨论】:

大多数数学和工程计算都可以。现在,财务和会计计算当然是不同的。【参考方案4】:

Microsoft SQL Server 中的浮点数相当于 C# 中的 Double。原因是浮点数只能逼近十进制数,浮点数的精度决定了该数字逼近十进制数的准确程度。 Double 类型表示双精度 64 位浮点数,其值范围从负 1.79769313486232e308 到正 1.79769313486232e308,以及正或负零、PositiveInfinity、NegativeInfinity 和 Not-a-Number (NaN)。

【讨论】:

【参考方案5】:

SQL 中的浮点数是 CLR (C#/VB) 中的 Double。 MSDN 上有a table of SQL data types with the CLR equivalents。

【讨论】:

它们相似但肯定不等价。根据 IEEE 规范,Double 支持 +Infinity、-Infinity 和 NaN 的值,但 SQL float 绝对不支持。并会抛出溢出错误。希望 MSDN 将其添加到他们的信息页面。 好的。那么你的答案是什么?【参考方案6】:

根据 the documentation for SQLDbType,SQL 浮点数是双精度。

【讨论】:

它们相似但肯定不等价。根据 IEEE 规范,Double 支持 +Infinity、-Infinity 和 NaN 的值,但 SQL float 绝对不支持。并且会抛出溢出错误。 我同意 Alain May 的 cmets,但我还不明白为什么。我见过 .net double 表示会破坏 SQL 浮点数的情况。示例包括无穷大值和某些接近零的负指数。我怀疑 MS 针对存储效率进行了优化。 @RaoulRubin:见MSDN documentation for TSQL floats。他们从未提及 IEEE 合规性,并声明它遵循一些未命名的 ISO 标准。快速搜索会得到 ISO/IEC 10967,它声明它与 IEEE 754 兼容,但不能保证完全实现。

以上是关于为啥 SQL 浮点数与 C# 浮点数不同的主要内容,如果未能解决你的问题,请参考以下文章

为啥 % 运算符不能用于 C/C++ 中的浮点数但可以用于 Java 和 C#? [复制]

为啥 std::abs() 不能与浮点数一起使用

C中的浮点数与预期略有不同

在 Swift 中将半精度浮点数(字节)转换为浮点数

为啥我们在 OpenGL (ES) android 中以字节分配块而不是浮点数,尽管我们大部分时间都使用浮点数

浮点数比较为啥没有相等的函数