2010-11-17 72 views
7

我注意到,當我存儲一個雙精度值,例如x = 0.56657011973046234在sqlite數據庫中,然後在稍後檢索,我得到y = 0.56657011973046201。根據sqlite spec.NET spec(我原本都不打算讀這兩個:)這是預期的和正常的。如何將C#double「修剪」爲它將存儲在sqlite數據庫中的值?

我的問題是,雖然高精度並不重要,但我的應用程序會處理用戶輸入/選擇表示基本3D信息的雙打,然後在其上運行模擬來查找結果。這個輸入可以被保存到一個sqlite數據庫中,以後重新加載並重新運行。

發生混淆是因爲新創建的一系列輸入顯然會以與稍後以相同的輸入存儲和重新加載(雙值更改時)稍有不同的方式進行模擬。這是合乎邏輯的,但不是渴望的。

我還沒有完全瞭解如何處理這個問題,但同時我想限制/限制用戶輸入值,這些值可以精確地存儲在sqlite數據庫中。所以如果用戶輸入0.56657011973046234,它實際上被轉換成0.56657011973046201

但是,我一直無法弄清楚,給定一個數字,將存儲在數據庫中的值是什麼,實際上從數據庫中存儲和檢索它看起來很笨重。有沒有一個確定的方法來做到這一點?

+3

你知道,如果皇家麥比微電腦做到了這一點,愛德華洛倫茲就永遠不會發現混沌理論。 :) – 2010-11-17 01:35:59

+0

@fostandy:這些實際值(0.56657011973046234和0.56657011973046201)還是你製作的? 0.56657011973046201是17位數字,所以它應該往返與0.56657011973046234(我在C中檢查過,它不是)相同的double值。 – 2010-11-17 13:48:44

+0

@Rick Regan - 0.56657011973046234是我從random.NextDouble()獲得的東西。 0.56657011973046201是我將它存儲在sqlite數字字段中並再次獲取後獲得的。據我瞭解(這是有限的)最後2位數字不保證往返。 – fostandy 2010-11-18 03:46:40

回答

2

雙輪有一個實現與一個參數,指定的位數。用這個來四捨五入到14位數字(比如說):rval = Math.Round(Val,14)

然後當從數據庫接收到數值,並在模擬開始時,即。所以在值匹配?

詳情:

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

另一個想法,如果你沒有在數據庫中比較值,只是將它們存儲:爲什麼不乾脆將它們存儲爲二進制數據?那麼所有的位都會被逐字存儲和恢復?

2

假設SQL Lite和.NET都正確實現了IEEE規範,如果您在兩邊都使用相同的浮點類型,您應該能夠獲得相同的數值結果(因爲不應該更改該值當從數據庫傳遞到C#時,反之亦然)。

目前,您在SQL Lite中使用8字節IEEE浮點(單個)(*),在C#中使用16字節浮點(雙精度)。 C#中的float類型對應於8字節IEEE標準,因此使用此類型而不是double可以解決此問題。 (*)SQL Lite文檔說,REAL是的浮點值,存儲爲8字節的IEEE浮點數

+0

C#float是4字節,C#double是8字節,所以我在C#中使用8字節浮點(雙精度)。因此,我最初預期這些值在檢索後是相同的,但它們並不是因爲C#double,而符合IEEE規範的_complying_實際上包含附加信息。 SQLite不保存這些信息,因爲它只符合IEEE規範。 – fostandy 2010-11-17 04:37:29

1

您可以使用一個字符串將#存儲在數據庫中。就我個人而言,我已經完成了winwaed在存儲之前和從db(使用numeric())中獲取數據之後提出的舍入。

我記得被銀行家四捨五入的灼傷,但它可能只是不符合規範。

1

可以雙存儲爲一個字符串,並利用轉換雙爲字符串時,往返格式,它保證產生相同的值解析時:

string formatted = theDouble.ToString("R", CultureInfo.Invariant); 
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不會往返。

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#程序檢索原始字符串並將其轉換回原始的double。

相關問題