2012-08-13 24 views
6

में एबीएस फ़ंक्शन विफल हो रहा है डेल्फी 6 या डेल्फी 2010 में, प्रकार मुद्रा (vtemp1, vtemp2) के दो चर घोषित करें और उन्हें 0.0 9 का मान खिलाएं। एबीएस फ़ंक्शन के साथ चरों में से एक एम्बेड करें और इसे दूसरे से तुलना करें। आप तुलनात्मक रूप से सकारात्मक परिणाम प्राप्त करने की अपेक्षा करेंगे क्योंकि संकलक घड़ी abs (vtemp1) और vtemp2 के लिए समान मान बताती है। विचित्र रूप से अगर कथन विफल रहता है !!!डेल्फी

नोट्स: -यह समस्या केवल अनुभव है जब संख्या 0.09 से निपटने (कोशिश कर कई अन्य के पास मूल्यों सामान्य परिणामों से पता चला) चर बजाय मुद्रा की डबल के रूप में, समस्या अस्तित्व समाप्त हो जाता -Declaring।

+2

पुन: पेश नहीं कर सकते – kludg

+3

([कैसे खतरनाक यह चल बिन्दु मूल्यों की तुलना के लिए? है] http://stackoverflow.com/questions/10334688/how-dangerous-is-it-to-compare-floating-point -वृत्त) – valex

+0

'गणित' या इसी तरह से 'समान वैल्यू' का प्रयोग करें। –

उत्तर

16

मुझे लगता है कि कारण प्रकार रूपांतरण है। Abs() फ़ंक्शन real परिणाम देता है, इसलिए currency परिवर्तनीय real पर रहता है। प्रलेखन पर एक नज़र डालें:

मुद्रा एक निश्चित बिंदु डेटा प्रकार है जो मौद्रिक गणना में गोल करने वाली त्रुटियों को कम करता है। Win32 प्लेटफ़ॉर्म पर, यह दशमलव स्थान का प्रतिनिधित्व करने वाले चार अंतिम महत्वपूर्ण अंकों के साथ के साथ स्केल किए गए 64-बिट पूर्णांक के रूप में संग्रहीत किया जाता है। जब कार्य और भाव में अन्य वास्तविक प्रकार के साथ मिश्रित, मुद्रा का मूल्य स्वचालित रूप से विभाजित हैं या द्वारा 10000.

गुणा इसलिए मुद्रा ठीक हो गई है और वास्तविक फ्लोटिंग प्वाइंट है। अपने प्रश्न के लिए नमूना कोड है:

program Project3; 
{$APPTYPE CONSOLE} 

const VALUE = 0.09; 
var a,b : currency; 
begin 
    a := VALUE; 
    b := VALUE; 

    if a = Abs(b) then writeln('equal') 
    else writeln('not equal', a - Abs(b)); 

    readln; 
end. 

क्योंकि प्रकार रूपांतरण के उत्पादन बराबर नहीं परिणाम;

संकलक घड़ी x : real जोड़ना चाहते हैं तो फोन x := abs(b);, x जोड़ने देखता सूची में, इसे चुनें और Edit watch दबाएं, फिर अस्थायी बिंदु का चयन पेट (vtemp1) और vtemp2

कोशिश के लिए एक ही मूल्य का पता चलता है । X0.899...967 बन जाता है।

न केवल 0.09 मूल्य इस तरह के परिणाम उत्पन्न करता है। आप इस कोड को जांचने के लिए कोशिश कर सकते हैं:

for i := 0 to 10000 do begin 
     a := a + 0.001; 
     b := a; 
     if a <> abs(b) then writeln('not equal', a); 
    end; 

इसलिए, यदि आपको मुद्रा चर के पूर्ण मूल्य की आवश्यकता है - बस इसे करें। फ्लोटिंग-पॉइंट abs() का उपयोग न करें:

function Abs(x : Currency):Currency; inline; 
    begin 
     if x > 0 then result := x 
     else result := -x; 
    end; 
+0

त्वरित उत्तरों के लिए धन्यवाद, जैसा कि आपने बताया है, मैंने इस समस्या से बचने के लिए एक समान कामकाज का उपयोग किया था। हालांकि स्पष्टीकरण समझ में आता है, क्या इसे डेल्फी आईडीई में या संकलक में ही एक बग नहीं माना जाता है? – Johny

+2

@ खैचिग - औपचारिक रूप से यह एक बग नहीं है बल्कि एक दस्तावेज व्यवहार ("डिज़ाइन किया गया") है। मैं मानता हूं कि यह एक बुरा व्यवहार है, और एम्बरकाडेरो इसे ठीक कर सकता है ('एबीएस (मुद्रा) 'को मुद्रा प्रकार वापस कर सकता है, एक फ्लोट नहीं)। – kludg

6

थोड़ा स्पष्टीकरण। 'मुद्दा' प्रदर्शित होता है या नाव मूल्यों की तुलना की जाती:

var 
    A: Currency; 

begin 
    A:= 0.09; 
    Assert(A = Abs(A)); 
end; 

है ऐसा इसलिए है क्योंकि Abs(A) एक नाव मान देता है, और A = Abs(A) एक नाव के रूप में कार्यान्वित किया जाता है की तुलना करें।

मैं इसे पुन: पेश नहीं कर सका है, तो मुद्रा मूल्यों की तुलना की जाती:

var 
    A, B: Currency; 
begin 
    A:= 0.09; 
    B:= Abs(A); 
    Assert(A = B); 
end; 

लेकिन दूसरा नमूना भी एक संभावित बग है क्योंकि B:= Abs(A) आंतरिक रूप से मुद्रा को गोलाई (int64) के साथ एक नाव विभाजन/गुणा 10000 के द्वारा होता है, और एफपीयू राउंडिंग मोड पर निर्भर करता है।


मैंने qc report #107893 बनाया है, इसे खोला गया था।

1

मुझे अभी पता चला है कि डेल्फी XE2 एबीएस फ़ंक्शन मुद्रा प्रकार को अधिभारित नहीं करता है।

देखें Delphi XE2 docwiki

इन पेट

  • समारोह पेट द्वारा समर्थित (एक्स:): केवल प्रकार के होते हैं रियल; अधिभार;
  • फ़ंक्शन एब्स (एक्स:): Int64; अधिभार;
  • फ़ंक्शन एब्स (एक्स:): इंटीजर; अधिभार;