簡體   English   中英

將一個整數除以值可能為負的整數后結果的整數舍入算法

[英]Algorithm for integer rounding of result after division of one integer by another whose values may be negative

我正在使用C源代碼,該源代碼具有RptRound()函數,該函數已在各種報表中使用,該函數接受兩個值,一個數量和一個第二個值(例如一個計數),將它們除然后取整。 被除以的金額值通常是貨幣金額,例如美元乘以100,以美分表示。

我的問題是,如果lAmountsDivisor的值均為負,從而導致它們的除法為正,則當前使用的函數是否將提供正確的舍入。

考察四舍五入的問題,似乎它沒有像我最初想象的那樣被切割和干燥。 但是,這里的目的似乎是要進行“ Round-Half-Up”類型的舍入。 或者更確切地說,是“從零回合”。 但是,僅當除數sDivisor值為正時,此函數才這樣做。

當前功能如下:

DCURRENCY RptRound( DCURRENCY lAmount, SHORT sDivisor )
{
    if (sDivisor) {                      /* Not Divide 0 Case */
        D13DIGITS   Quot, Quot1;

        if ( lAmount < 0 ) {
            Quot1 = -5;
        } else {
            Quot1 = 5;
        }
        Quot = lAmount * 10;
        Quot /= (LONG)sDivisor;
        Quot += Quot1;
        Quot /= 10;
        return Quot;
    }
    return (0);
}

看起來只要sDivisor始終為正,則此函數將給出正確的舍入結果,將x.5的正值四舍五入為(x +1),將-x.5的負值四舍五入(更負)到(x-1)。

但是在我看來,如果lAmountsDivisor都為負,導致結果為正,則舍入將是不正確的,因為偏差值Quot1在應該為正時將為負。 結果將是x.5將被四舍五入為x而不是x + 1(如果兩者均為負數)。 甚至更糟的是,如果x.2都為負數,則將四舍五入為x-1。

所以我想用以下內容代替上面的內容。

DCURRENCY RptRound( DCURRENCY lAmount, SHORT sDivisor )
{
    D13DIGITS   Quot = 0;

    if (sDivisor) {                      /* Not Divide 0 Case */
        Quot = lAmount;
        Quot *= 10;                      // multiply by 10 with larger number of digits
        Quot /= sDivisor;
        // add the bias and divide now in case both lAmount and sDivisor are negative.
        // this will get us to the closest whole number value of the result.
        if ( Quot < 0 ) {
            Quot += -5;      // add half of -10 to make more negative
        } else {
            Quot += 5;       // add half of +10 to make more positive
        }
        Quot /= 10;          // divide by 10 to get to nearest whole number of result.
    }

    return Quot;
}

在此版本中,如果sDivisor為負且lAmount為正,則結果從零舍入(結果為負並四舍五入為負),如果sDivisor為負且lAmount為負(結果為正且四舍五入為正)。 如果sDivisor為正且lAmount為正,則結果將四舍五入為零(結果為正,且四舍五入為正數);如果sDivisor為正,且lAmount為負,則結果將舍入為零(結果為負,四舍五入為負)。

但是,經過一番閱讀后,我對該更改的確定性大大降低了,因此我正在尋找其他反饋。

注意:由於DCURRENCY當前long因此在對返回值進行轉換時,此函數會生成編譯器警告。 一旦DCURRENCY變為與D13DIGITS相同的long long ,它將消失。

warning C4244: 'return' : conversion from 'D13DIGITS' to 'DCURRENCY', possible loss of data

負除數在這里看起來有些奇怪,因此請考慮一個帶符號的除數。 帶符號的函數僅對兩個操作數求反。

而不是按比例縮放10並加+/- 5並除以10,而是將除數增加一半。

DCURRENCY RptRoundU(DCURRENCY lAmount, unsigned Divisor) {
  if (Divisor > 0) {
    if  lAmount < 0) {
      lAmount -= Divisor/2;
    } else {
      lAmount += Divisor/2;
    }  
    lAmount /= (LONG) sDivisor;
    return lAmount;
  }
  return 0;
}

DCURRENCY RptRoundS(DCURRENCY lAmount, signed Divisor) {
  return Divisor < 0 ? RptRoundU(-lAmount, 0u-Divisor) : RptRoundU(lAmount, Divisor);
}

這個想法只是在除法之前添加或減去除數的一半,因為它將舍入為零。

為了使@chux的答案略短一些,您可以僅在其中一個值為負數時減去該值,即

DCURRENCY RptRound( DCURRENCY lAmount, SHORT sDivisor )
{
    if (!sDivisor)
        return 0; // or some invalid value

    if ((sDivisor < 0) ^ (lAmount < 0)) {
        lAmount -= (sDivisor / 2);
    } else {
        lAmount += (sDivisor / 2);
    }

    return lAmount / sDivisor;
}

另外,我的偏好是返回一個特殊的無效值以除以零,例如(long)0x80000000

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM