Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 将一个整数除以另一个值可能为负数的整数后,对结果进行整数舍入的算法_C_Algorithm_Rounding - Fatal编程技术网

C 将一个整数除以另一个值可能为负数的整数后,对结果进行整数舍入的算法

C 将一个整数除以另一个值可能为负数的整数后,对结果进行整数舍入的算法,c,algorithm,rounding,C,Algorithm,Rounding,我正在使用C源代码,它有一个函数RptRound,在各种报告中使用,该函数接受两个值,一个值和第二个值(如计数),将它们相除,然后对结果进行取整。被分割的金额值通常是货币金额,例如美元乘以100,以美分表示 我的问题是,如果lAmount和sDivisor的值均为负值,则当前使用的函数是否会提供正确的舍入,从而导致其除法结果为正值 研究成圆的问题,它似乎不像我最初认为的那样简单。然而,这里的目的似乎是进行一种舍入。或者更确切地说是从零开始四舍五入。但是,此函数仅在除数sDivisor的值为正时才

我正在使用C源代码,它有一个函数RptRound,在各种报告中使用,该函数接受两个值,一个值和第二个值(如计数),将它们相除,然后对结果进行取整。被分割的金额值通常是货币金额,例如美元乘以100,以美分表示

我的问题是,如果lAmount和sDivisor的值均为负值,则当前使用的函数是否会提供正确的舍入,从而导致其除法结果为正值

研究成圆的问题,它似乎不像我最初认为的那样简单。然而,这里的目的似乎是进行一种舍入。或者更确切地说是从零开始四舍五入。但是,此函数仅在除数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为负,lAmount为正,则结果从零舍入结果为负,舍入为负,就像sDivisor为负,lAmount为负一样,结果为正,舍入为正。如果sDivisor为正且lAmount为正,则结果从零舍入结果为正且舍入得更正;如果sDivisor为正且lAmount为负,则结果从零舍入结果为负且舍入得更负

然而,经过一段时间的阅读,我对这一变化的确定程度大大降低,因此我正在寻找更多的反馈

注意:由于DCURRENCY当前是一个长函数,因此该函数在对返回值进行转换时会生成编译器警告。当D电流变为与D13DIGITS相同的长-长时,这将消失


这里的负除数看起来有点奇怪,所以考虑一个已签名的和一个未签名的除数。有符号函数只是对两个操作数求反

将除数的一半加上,而不是按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);
}

这里的负除数看起来有点奇怪,所以考虑一个已签名的和一个未签名的除数。有符号函数只是对两个操作数求反

将除数的一半加上,而不是按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;
}

此外,我更倾向于返回一个特殊的无效值来进行除法,比如long0x80000000。

简单的想法是在除法之前加上或减去除数值的一半,因为这将从零取整

为了使@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;
}

此外,我更倾向于返回一个特殊的无效值,用于除以零,比如long0x80000000。

Quot=lAmount*10;对于接近LONG_MAX/10或LONG_MIN/10的任何值,都是溢出UB。其他方法不需要*10。lAmount、sDivisor和预期结果的一些样本值将增加负面案例的清晰度。使用sDivisor<0有其他解释。依我看,为什么不使用无符号除数来避免这个问题?@chux不确定你所说的其他方法是什么意思不需要*10。你能详细说明一下吗?此外,我不确定您使用sDivisor<0的意思是否有其他解释。关于上溢和下溢的观点很好。@chux有些情况下,某些类型的数据项的计数可能为负数,因此使用无符号除数似乎不合适。您可能是正确的。然而,与10和5相比,2和1可以用于更宽的范围或下面提到的半除数技巧;对于接近LONG_MAX/10或LONG_MIN/10的任何值,都是溢出UB。其他方法不需要*10。lAmount、sDivisor和预期结果的一些样本值将增加负面案例的清晰度。使用sDivisor<0有其他解释。依我看,为什么不使用无符号除数来避免这个问题?@chux不确定你所说的其他方法是什么意思不需要*10。你能详细说明一下吗?此外,我不确定您使用sDivisor<0的意思是否有其他解释。关于上溢和下溢的观点很好。@chux有些情况下,某些类型的数据项的计数可能为负数,因此使用无符号除数似乎不合适。您可能是正确的。然而,与10和5不同,2和1可以用于更宽的范围或下面提到的半除数技巧。舍入部分可以,但if除数的其他部分!=RptRoundU函数中的0可能需要一些考虑?@Groo已更改,以匹配除数==0 case中OP的原始代码。OP正在考虑此问题。@RichardChambers
e还将处理可能发生溢出的情况,如lAmount+=除数/2;和-lAmount,但这似乎是第二个问题。@计算过程中的chux溢出/下溢是D13DIGITS变量类型为long的原因。此代码最初用于一个不支持long-long的小方框,因此定义了一个64位整数类型,使用该64位整数类型定义了一组用于64位算术的函数,然后将其转换回long。舍入部分正常,但if除数的其他部分!=RptRoundU函数中的0可能需要一些考虑?@Groo已更改,以匹配OP在除数==0的情况下的原始代码。OP正在考虑此问题。@RichardChambers迂腐代码还将处理可能发生溢出的情况,如lAmount+=除数/2;和-lAmount,但这似乎是第二个问题。@计算过程中的chux溢出/下溢是D13DIGITS变量类型为long的原因。这段代码最初用于一个不支持long-long的小盒子,因此定义了一个64位整数类型,其中包含一组函数,用于使用该64位整数类型的64位算术,然后将其转换回long。在if中使用XOR运算符非常有趣。如果尝试除以零,我不愿意更改返回值,因为我不确定报告是否希望它始终是有效的计算值,或者如果sDivisor为零,则仅为零。好的,我现在知道半除数值的原因了。@RichardChambers:如果这是您正在重构的现有遗留代码,保留0可能是有意义的,只是为了避免破坏现有功能。我如何确定从零取整是否总是合适的?我不确定这段代码是否是故意这样设计的,或者它与提供的数据一起工作只是一个意外,或者是否有人在现场遇到了不准确的情况,没有人抱怨。异或运算符在if中的有趣使用。如果尝试除以零,我不愿意更改返回值,因为我不确定报告是否希望它始终是有效的计算值,或者如果sDivisor为零,则仅为零。好的,我现在知道半除数值的原因了。@RichardChambers:如果这是您正在重构的现有遗留代码,保留0可能是有意义的,只是为了避免破坏现有功能。我如何确定从零取整是否总是合适的?我不确定这段代码是否是故意以这种方式设计的,或者它与提供的数据一起工作只是一个意外,或者是否有人在现场遇到了不准确的情况,没有人投诉。