2014-03-27 573 views
2

我正在執行一個獨立的企業COBOL程序,計算如下。我有一個計算多個操作和另一個完整的計算分裂。但是在這兩種情況下結果是不同的(最後4位數字)。COBOL COMPUTE計算

我已經使用計算器手動計算了這些值,結果與分割COMPUTE語句的結果相匹配。我已經通過使用中間結果的整個答案來嘗試計算,並且只使用最終答案的15位數字,並且在所有中間步驟(沒有舍入)中也只使用15位數字。但是這些結果中沒有一個與COMPUTE結果相結合。

有人能幫我理解爲什麼會有這樣的差異。

 05 WS-A    PIC S9(3)V9(15) COMP. 
     05 WS-B    PIC S9(3)V9(15) COMP. 
     05 WS-C    PIC S9(3)V9(15) COMP. 
     05 WS-D    PIC S9(3)V9(15) COMP. 
     05 WS-E    PIC S9(3)V9(15) COMP. 
     05 WS-RES   PIC S9(3)V9(15) COMP. 
     05 RES-DISP   PIC -9(2).9(16). 

     MOVE 3.56784    TO WS-A. 
     MOVE 1.3243284234   TO WS-B. 
     MOVE .231433897121334834 TO WS-C. 
     MOVE 9.3243243213   TO WS-D. 
     MOVE 7.0     TO WS-E. 

     COMPUTE WS-RES = WS-A/WS-B. 
     MOVE WS-RES TO RES-DISP. 
     COMPUTE WS-RES = WS-RES/WS-C. 
     MOVE WS-RES TO RES-DISP. 
     COMPUTE WS-RES = WS-RES/(WS-D + WS-E). 
     MOVE WS-RES TO RES-DISP. 
     COMPUTE WS-RES = WS-RES * (WS-C - WS-A) 
     MOVE WS-RES TO RES-DISP. 
     COMPUTE WS-RES = WS-RES + WS-E ** WS-B 
     MOVE WS-RES TO RES-DISP. 
     COMPUTE WS-RES = WS-RES + WS-D. 
     MOVE WS-RES TO RES-DISP. 

結果最後計算的合併=計算的20.1030727225138740

 COMPUTE WS-RES = WS-A/WS-B/WS-C/
       (WS-D + WS-E) * (WS-C - WS-A) + 
       WS-E ** WS-B + WS-D. 
     MOVE WS-RES TO RES-DISP. 

結果= 20.1030727225138680

+0

我已經更新了答案,有一個微妙的指數,我認爲這是你看到的實際問題。通過你所擁有的價值觀和計算,我認爲排序並不重要。想知道爲什麼你沒有診斷信息,我想我已經發現 –

+0

這種特殊情況是當彙編列表(LIST)可以派上用場。理解編譯器生成的代碼可以幫助理解結果。優化也可能會造成偏差,但我相信這將成爲Enterprise COBOL 5.1的更多問題,因爲它使用與C和PL/I相同的代碼生成器。對於「有趣」,我會拿你的原始代碼並比較生成的代碼。您已經從Bill那裏得到了一個很好的答案,並且比較了此處顯示的所有代碼(原始代碼和解決方案)中生成的代碼,這將有助於您更好地理解編譯器的工作方式。 – zarchasmpgmr

回答

3

慢,我知道,但我想我剛剛拿到了,爲什麼你定義的一切小數點後15位。否則你無法使其工作。

閱讀下面鏈接中的問題(當然還有答案)。您無需爲輸出指定具有所需精度的所有字段。

重新安排您的計算器。指數在主COMPUTE之外。先乘以。然後劃分。任何加法/減法自然適合。使用圓括號來準確指定您希望人們如何閱讀COMPUTE(編譯器不關心,它會按照所講的內容進行,但有時候人們不知道他們在說什麼)。

如果你這樣做(正確),你將得到與你的COMPUTE中的所有字段有15個小數位的答案相同的答案。

如果您不這樣做,您的COMPUTE(以及其他人在複製時)將永遠是脆弱的,並且在更改時容易出錯。

將計算器分解爲更小的計算器是一個好主意,就像您一樣,以便您可以看到要將哪些值輸入計算器。當您將字段設置爲正確的尺寸時,您可以做同樣的事情。

我將不得不完全重新寫這個,因爲多個更新使它變得凌亂......在某個時刻。

好的,確認。不同之處在於計算COMPUTE內的非整數指數,如手冊所述,然後將COMPUTE中的所有內容(所有中間字段)轉換爲浮點數,該浮點數的小數位數多於圖片條款中規定的15個。

由於乘法的原因,現在有一個診斷消息(已經取冪運算出來),它希望有36位數,但只能有30個(ARITH(COMPAT))或31個(ARITH(EXTEND))。如果高位數據被截斷,則會有運行時間消息。

注意。使用ARITH(COMPAT)15是精度不會丟失的最大有效位數(64位浮點數)。 ARITH(EXTEND)保證精度,但是在處理中有一個開銷(128位浮點)。

回到較早...

一直在想這個。您正在使用18位數字,並且您沒有提到將ARITH(EXTEND)用作編譯選項,並且未提及爲大型COMPUTE生成的任何診斷消息。這很有趣。

在COBOL中沒有做過很多指數運算,然後只用了整數。所以我看了一下手冊。由於分數指數所有在您的大型COMPUTE中都是以浮點形式完成的。這並不重要,但它意味着事情的執行速度要比定義中小數點後15位的預期要高。在你的小型計算機中,這不會發生。

我建議採取冪出大COMPUTE的,計算的是單獨乾脆把在大計算該結果(一個簡單的加法替換冪)。我懷疑在那個階段編譯器會開始抱怨結果中的有效位數。如果確實如此,那麼如果實際上丟失了一個有效數字,則會得到運行時間消息。

您應該:

  1. 取冪走出大COMPUTE,並與冪
  2. 單獨COMPUTE的結果替換它的每個字段定義其數據所需的最大尺寸(不最大可能的一切)
  3. (可能)更改爲COMP-3 COMP,但測試它自己
  4. Parenthesise一切使人體讀者知道的順序編譯器會做的事情在
  5. 如果在COMPUTE中仍然存在有關可能截斷的警告,請查看ARITH(EXTEND)編譯器選項,但不要將其作爲修補程序來使用,只在需要時才使用它,並記錄該程序的用法

我會盡量在稍後再確認一下,但我認爲這樣會把它整理出來。

以下是開始,還適用於一般情況下,雖然沒有直接針對具體問題(問題被迫到一切較高的浮點精度VS只能被迫爲冪)相關:

你小COMPUTE的問題在於你沒有按照與大COMPUTE的元素相同的順序執行它們。

()不是爲了好玩,或者只是爲了將事物分組在一起,他們在計算中建立優先級。

還有什麼建立優先權?運營商使用。優先順序是什麼?那麼,你必須在手冊中查看它,記住它,或者每次忘記時都要熟悉它。嗯....不是一個好建議。

另外,其他人將在您編寫或更改的程序上工作。他們可能「知道」COMPUTE的工作方式(我的意思是他們不這樣做,但認爲他們這樣做,所以不會查找)。雙重不好的建議。

所以....

使用()並確定要在其中做事情的順序。

也要注意你可能失去意義的地方。看看這個,AS/400: Using COMPUTE function, inconsistent results with different field definition,閱讀並理解企業COBOL手冊的參考部分。

作爲本網站鏈接問題的摘要,請先乘以最後一位,確保中間結果不會丟失重要數字。除非你故意要丟失數字,在這種情況下,這些計算機會單獨失去重要性,並對代碼進行評論,以便沒有人「修復」它。

此外,在大型機上使用COMP/COMP-4/BINARY/COMP-5來處理帶有小數位的字段是不尋常的。一旦對COMPUTEs滿意,複製程序並將字段定義更改爲COMP-3/PACKED-DECIMAL。在每個程序的計數器上放一個循環,看看是否注意到CPU使用率有任何顯着差異。

1

我拷貝,編輯和一個微小的改動運行您的程序:

  • 聲明RES-DISPPIC -9(3).9(15)避免編譯器截斷警告
  • 增加了新的變數WS-EXP PIC S9(3)V9(15) COMP
  • 增加了一個新的計算做的比爾伍德建議通過將冪運算分解成如下單獨計算:
COMPUTE WS-EXP = WS-E ** WS-B 
    COMPUTE WS-RES = WS-A/WS-B/WS-C/ 
    (WS-D + WS-E) * (WS-C - WS-A) + 
    WS-EXP + WS-D. 

在此程序中發出的唯一編譯器警告是針對上面的第二個COMPUTE語句。消息是:

IGYPG3113-W Truncation of high-order digit positions may occur due to intermediate results exceeding 30 digits 

上面的計算結果與您的分段計算完全相同:020.103072722513874。 您的所有功能於一身的COMPUTE語句不會導致編譯器警告。但是內部取冪導致在整個計算過程中使用更高精度的中間結果(更少的舍入),產生稍有不同的結果:020.103072722513868。

這裏還有一個有趣的觀察。使用ARITH(COMPAT)我得到的結果與問題完全相同,使用ARITH(EXTEND)I 得到020.103072722513877作爲片段計算,020.103072722513874作爲所有功能於一身的COMPUTE(與 相同)與ARITH(COMPAT)編譯時)。

這一切都表明,您需要在進行復雜計算時真正研究數值精度,舍入和截斷規則。由於編程人員可以使用不同的數字數據類型的數量,所以這是 尤其適用於COBOL。