c# डेल्फी में MidpointRounding.AwayFromZero के साथ Math.Round() के बराबर क्या है?




delphi delphi-7 (2)

मैं डेल्फी में MidpointRounding.AwayFromZero साथ c # समान Math.Round उपयोग कैसे करूं?

इसके बराबर क्या होगा:

double d = 2.125;
Console.WriteLine(Math.Round(d, 2, MidpointRounding.AwayFromZero));

आउटपुट: 2.13

डेल्फी में?


मेरा मानना ​​है कि डेल्फी आरटीएल के SimpleRoundTo फ़ंक्शन अनिवार्य रूप से यह करता है, कम से कम अगर एफपीयू राउंडिंग मोड "सही" है। कृपया इसके प्रलेखन और कार्यान्वयन को ध्यान से पढ़ें, और फिर तय करें कि क्या यह आपके उद्देश्यों के लिए पर्याप्त है।

लेकिन सावधान रहें कि इस तरह के एकल राउंडिंग ऑपरेशन के लिए राउंडिंग मोड सेट करना एक स्थानीय समस्या को हल करने के लिए वैश्विक परिवर्तन का उपयोग कर रहा है। इससे समस्याएं (मल्टी-थ्रेडिंग, लाइब्रेरी आदि) हो सकती हैं।

बोनस बकबक: प्रश्न "नियमित" (पूर्णांक के लिए) गोलाई के बारे में था, मुझे लगता है कि मैंने एक दृष्टिकोण की कोशिश की थी

function RoundMidpAway(const X: Real): Integer;
begin
  Result := Trunc(X);
  if Abs(Frac(X)) >= 0.5 then
    Inc(Result, Sign(X));
end;

बजाय।

बेशक, समान अंशों के सामान्य मामले के लिए भी समान फ़ंक्शन लिखना संभव है। (लेकिन सही ढंग से किनारे के मामलों, अतिवृष्टि, फ्लोटिंग-पॉइंट मुद्दों आदि को संभालने के लिए सावधान रहें।)

अद्यतन: मेरा मानना ​​है कि निम्नलिखित चाल (और तेज है):

function RoundMidpAway(const X: Real): Integer; overload;
begin
  Result := Trunc(X);
  if Abs(Frac(X)) >= 0.5 then
    Inc(Result, Sign(X));
end;

function RoundMidpAway(const X: Real; ADigit: integer): Real; overload;
const
  PowersOfTen: array[-10..10] of Real =
    (
      0.0000000001,
      0.000000001,
      0.00000001,
      0.0000001,
      0.000001,
      0.00001,
      0.0001,
      0.001,
      0.01,
      0.1,
      1,
      10,
      100,
      1000,
      10000,
      100000,
      1000000,
      10000000,
      100000000,
      1000000000,
      10000000000
    );
var
  MagnifiedValue: Real;
begin
  if not InRange(ADigit, Low(PowersOfTen), High(PowersOfTen)) then
    raise EInvalidArgument.Create('Invalid digit index.');
  MagnifiedValue := X * PowersOfTen[-ADigit];
  Result := RoundMidpAway(MagnifiedValue) * PowersOfTen[ADigit];
end;

बेशक, यदि आप इस फ़ंक्शन को उत्पादन कोड में उपयोग करेंगे, तो आप कम से कम 50 यूनिट परीक्षण मामलों को भी जोड़ देंगे जो इसकी शुद्धता का परीक्षण करते हैं (दैनिक चलाने के लिए)।

अद्यतन: मेरा मानना ​​है कि निम्नलिखित संस्करण अधिक स्थिर है:

function RoundMidpAway(const X: Real; ADigit: integer): Real; overload;
const
  FuzzFactor = 1000;
  DoubleResolution = 1E-15 * FuzzFactor;
  PowersOfTen: array[-10..10] of Real =
    (
      0.0000000001,
      0.000000001,
      0.00000001,
      0.0000001,
      0.000001,
      0.00001,
      0.0001,
      0.001,
      0.01,
      0.1,
      1,
      10,
      100,
      1000,
      10000,
      100000,
      1000000,
      10000000,
      100000000,
      1000000000,
      10000000000
    );
var
  MagnifiedValue: Real;
  TruncatedValue: Real;
begin

  if not InRange(ADigit, Low(PowersOfTen), High(PowersOfTen)) then
    raise EInvalidArgument.Create('Invalid digit index.');
  MagnifiedValue := X * PowersOfTen[-ADigit];

  TruncatedValue := Int(MagnifiedValue);
  if CompareValue(Abs(Frac(MagnifiedValue)), 0.5, DoubleResolution * PowersOfTen[-ADigit]) >= EqualsValue  then
    TruncatedValue := TruncatedValue + Sign(MagnifiedValue);

  Result := TruncatedValue * PowersOfTen[ADigit];

end;

लेकिन मैंने इसका पूरी तरह से परीक्षण नहीं किया है। (वर्तमान में यह 900+ यूनिट परीक्षण मामलों से गुजरता है, लेकिन मैं परीक्षण सूट को अभी तक पर्याप्त नहीं मानता हूं।)


आप जो देख रहे हैं, वह SimpleRoundTo साथ संयोजन में SimpleRoundTo फ़ंक्शन है। जैसा कि दस्तावेज कहते हैं:

SimpleRoundTo निकटतम मान लौटाता है जिसमें दस की निर्दिष्ट शक्ति होती है। यदि AValue दो निकटतम मूल्यों के बीच में है, जिसमें दस (ऊपर और नीचे) की निर्दिष्ट शक्ति है, तो यह फ़ंक्शन वापस आ जाता है:

  • AValue पॉजिटिव होने पर प्लस इनफिनिटी की ओर वैल्यू।

  • यदि AValue ऋणात्मक है और FPU गोलाई मोड rmUp पर सेट नहीं है, तो माइनस इनफिनिटी की ओर मान

ध्यान दें कि फ़ंक्शन का दूसरा पैरामीटर TRoundToRange जो .NET के Math.Round पद्धति में भिन्न डिगिसिस की संख्या के बजाय घातांक (10 की शक्ति) को संदर्भित करता है। इसलिए 2 से 2 दशमलव स्थानों पर आप राउंड-टू रेंज का उपयोग करते हैं।

uses Math, RTTI;

var
  LRoundingMode: TRoundingMode;
begin
  for LRoundingMode := Low(TRoundingMode) to High(TRoundingMode) do
  begin
    SetRoundMode(LRoundingMode);
    Writeln(TRttiEnumerationType.GetName(LRoundingMode));
    Writeln(SimpleRoundTo(2.125, -2).ToString);
    Writeln(SimpleRoundTo(-2.125, -2).ToString);
  end;
end;

rmNearest

2,13

-2,13

rmDown

2,13

-2,13

rmUp

2,13

-2,12

rmTruncate

2,13

-2,13





delphi-7