7

我注意到,当我x = 0.56657011973046234在 sqlite 数据库中存储一个 double 值,然后再检索它时,我得到y = 0.56657011973046201. 根据sqlite 规范.NET 规范(我最初都懒得去阅读这两个规范:)这是预期的和正常的。

我的问题是,虽然高精度并不重要,但我的应用程序处理用户输入/选择代表基本 3D 信息的双精度数,然后对它们运行模拟以找到结果。并且此输入可以保存到 sqlite 数据库中,以便稍后重新加载和重新运行。

出现混淆是因为新创建的一系列输入显然会以稍微不同的方式模拟存储和重新加载后的相同输入(因为双精度值已更改)。这是合乎逻辑的,但不是可取的。

我还没有完全了解如何处理这个问题,但与此同时,我想将用户输入限制/限制为可以精确存储在 sqlite 数据库中的值。所以如果用户输入0.56657011973046234,它实际上被转化为0.56657011973046201

但是,给定一个数字,我无法弄清楚数据库中将存储什么值,而实际上却无法从数据库中存储和检索它,这似乎很笨拙。有没有既定的方法来做到这一点?

4

6 回答 6

3

答案可能是将双精度值存储为 17 位有效数字字符串。看看 SQLite 如何处理实数与文本之间的区别(为简单起见,我将使用命令行界面进行说明):

sqlite> create table t1(dr real, dt varchar(25));
sqlite> insert into t1 values(0.56657011973046234,'0.56657011973046234');
sqlite> select * from t1;
0.566570119730462|0.56657011973046234

以真正的亲和力存储它是导致问题的原因——SQLite 只给你一个 15 位的近似值。如果将其存储为文本,则可以使用 C# 程序检索原始字符串并将其转换回原始双精度。

于 2010-12-03T00:34:04.400 回答
2

假设 SQL Lite 和 .NET 都正确实现了 IEEE 规范,如果在两边都使用相同的浮点类型,您应该能够获得相同的数值结果(因为从数据库传递时不应更改值到 C#,反之亦然)。

目前,您在 SQL Lite 中使用 8 字节 IEEE 浮点(单)(*),在 C# 中使用 16 字节浮点(双)。C# 中的float类型对应 8 字节的 IEEE 标准,因此使用此类型代替double可以解决问题。

(*) SQL Lite 文档说 REAL 是一个浮点值,存储为一个 8 字节的 IEEE 浮点数

于 2010-11-17T01:43:59.853 回答
2

Double round 有一个带有指定位数的参数的实现。使用它来四舍五入到 14 位(比如说): rval = Math.Round(Val, 14)

然后在从数据库接收到值时进行四舍五入,并在模拟开始时,即。所以在价值观匹配?

详情:

http://msdn.microsoft.com/en-us/library/75ks3aby.aspx

另一个想法是,如果您不比较数据库中的值,而只是存储它们:为什么不简单地将它们存储为二进制数据?那么所有的比特都会被逐字存储和恢复?

于 2010-11-17T01:45:38.027 回答
1

如果您希望十进制输入值往返,那么您必须将它们限制为 15 个有效数字。如果您希望 SQLite 内部双精度浮点值往返,那么您可能不走运;这需要打印到至少 17 个有效数字,但据我所知,SQLite 将它们打印到最多 15 个(编辑也许 SQLite 专家可以确认这一点?我只是阅读了源代码并对其进行了跟踪——我是正确,精度限制为 15 位。)

我在 Windows 上的 SQLite 命令界面中测试了您的示例。我插入0.56657011973046234,选择返回0.566570119730462。在 C 中,当我将 0.566570119730462 分配给 double 并将其打印为 17 位时,我得到 0.56657011973046201;这与您从 C# 获得的值相同。0.56657011973046234 和 0.56657011973046201 映射到不同的浮点数,换句话说,SQLite double 不会往返。

于 2010-11-18T16:15:51.157 回答
1

您可以使用字符串将 # 存储在数据库中。就我个人而言,我已经完成了 winwaed 在存储之前和从数据库(使用 numeric() )获取之后四舍五入的建议。

我记得被银行家四舍五入烧死了,但这可能只是不符合规范。

于 2010-11-17T01:48:34.897 回答
1

您可以将双精度值存储为字符串,并且在将双精度值转换为字符串时使用往返格式,可以保证在解析时生成相同的值:

string formatted = theDouble.ToString("R", CultureInfo.Invariant);
于 2010-11-17T02:06:21.000 回答