2012-05-22 74 views
4

我們已經有了一個表中的Oracle數據庫定義爲:閱讀整數浮點

CREATE TABLE AVALUES 
(
    ACODE VARCHAR2(4) NOT NULL, 
    ATYPE NUMBER NOT NULL, 
    ANAME VARCHAR2(50), 
    CREATED DATE DEFAULT SYSDATE 
) 

在德爾福我們在ADOQuery成分類似於這樣的查詢返回的價值,我們的應用程序:

with qryComp do 
begin 
    Close; 
    SQL.Text := 
    'SELECT ATYPE FROM AVALUES ORDER BY CREATED'; 
    Open; 
    while not EOF do 
    begin 
    AddComponents('NAME' + FieldByName('ATYPE').AsString); 
    Next; 
    end; 
    Close; 
end; 

部署在許多不同的客戶端PC上,這已經運行良好多年,我們的代碼沒有任何改變。然而,在一些客戶端PC上,它最近開始返回,例如1.999999999969而不是,這會導致應用程序崩潰。我們嘗試過尋找問題,但它非常間歇 - 通過遠程桌面連接到客戶端計算機,我們無法複製它。

對於我可以做的事情有什麼建議可以進一步調查?由於它是間歇性的,只發生在幾臺電腦上,所以很難調試。我認爲這可能是Oracle客戶端的問題,但我不確定我們如何才能真正驗證這一點。

感謝您的任何幫助。

+1

整數在IEEE754浮點中完全可表示。必須對這樣的值進行計算才能返回。似乎很奇怪。你如何將這些值放入數據庫中?你是否在執行浮點計算?如果你認爲這是一個整數,你爲什麼要作爲浮點存儲?如果它確實是一個整數,那麼解決方案就是以整數形式存儲。 –

+0

ATYPE是否真的需要Oracle NUMBER全浮點精度?或者你能否聲明一些類似NUMBER(6)的東西? NUMBER根據您聲明的方式來處理不同的情況。使用適當的聲明還可以節省列大小的空間,由公式ROUND((length(p)+ s)/ 2))+ 1給出,其中p是精度,s取值爲0或1,取決於數字標誌。如果您只是使用NUMBER,p = 38。另外NUMBER不會以IEEE754格式存儲數據。 BINARY_FLOAT和BINARY_DOUBLE做。有關詳細信息,請參閱「Oracle數據庫SQL參考」。 –

回答

13

我可以看到的唯一可能是客戶端計算機上的FPU控制字之間的差異導致精度的處理方式不同,因爲處理浮點類型時存在固有舍入問題。 (見Set8087CW在Delphi的文檔;鏈接指向XE2的文檔,但最近沒有顯著的變化,我所知道的,所以他們應該工作。)

有四種方法來解決它(一個可能性不大, 3相當容易):

  • 更改數據庫列實際上是integer類型,而不是一個NUMBER

  • 直接索要integer值,並自己進行轉換

    AddComponent('Name' + IntToStr(FieldByName('ATYPE').AsInteger));

  • 更改使用該柱,或者在使用點的代碼:

    AddComponents(Format('NAME%d', [FieldByName('ATYPE').AsInteger]));

AddComponents本身:

procedure AddComponents(Prefix: string; Value: Integer); 
begin 
    DoWhateverIDo(Prefix + IntToStr(Value)); 
end; 

// calling code 
AddComponents('Name', FieldByName('ATYPE').AsInteger); 
  • 明確設置808的值7CW在使用數據庫之前,並在完成後將其設置回來。這似乎是我最糟糕的選擇;在我上面發佈的文檔鏈接上有這樣做的例子。
+1

嗨!感謝指向Set8087CW的指針 - 事實證明,問題在於第三方DLL在某些情況下襬弄了這個值,現在我們知道,我們可以阻止它。 :) – Kieran

+2

優秀!很高興我能幫上忙。:) –

+4

如果問題出在控制字上,那麼你必須做浮點計算。但如果是這樣,並且你的應用程序對2和1.999999999之間的差異很敏感,那麼你有一個問題。如果敏感度導致崩潰,那麼我真的認爲你正在做一些嚴重錯誤的事情。僅僅運行在不同的硬件上可能會導致類似的差異,並且難以維持對FP控制字的控制。如果這真的是一個整數,那麼你必須從源頭上處理這個問題,而不是試圖對這些問題進行論證。 –

1

Oracle NUMBER數據類型是浮點數據類型,所以您有float/double近似的問題。請務必閱讀What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

我知道這是一個浮點數據類型。看起來很奇怪的是,在100箇中有99個返回了我們想要存儲的值,並且在這種情況下它不是,而是不是所有的時間。如果它與近似有關,我認爲它是一致的。 – Kieran

+0

你設置FPU控制字嗎? (http://docwiki.embarcadero.com/Libraries/en/System.Set8087CW) –

+0

它應該是一致的。控制字不應該像這樣讀取完全可表示的值。 –

2

我遇到了類似的問題,數據類型貨幣(博客文章:"Why 1.99 suddenly no longer equals 1.99")。它看起來像一些DLL修改FPU(處理器)控制字。這解釋了爲什麼這個問題是依賴於機器的。 我還發現Delphi包含一個SafeLoadLibrary函數,它可以恢復控制字。但這不是一個很大的幫助,因爲在加載DLL之後,仍然任何DLL函數的調用都會再次弄亂控制字。

+0

謝謝,這實際上是問題所在。 – Kieran