代码之家  ›  专栏  ›  技术社区  ›  Øyvind Bråthen

当使用int作为除数时,计算公式的最佳方法是什么?

  •  4
  • Øyvind Bråthen  · 技术社区  · 15 年前

    我经常发现自己有一个表达式,其中除法是一个大公式的一部分。我将给出一个简单的例子来说明这个问题:

    int a = 2;
    int b = 4;
    int c = 5;
    int d = a * (b / c);
    

    在这种情况下,d等于0,但我希望它是1,因为4/5乘以2等于1 3/5,当转换为int时,get的“rounded”为1。所以我发现自己不得不将c强制转换为double,然后由于这使得表达式也成为double,所以将整个表达式强制转换为int。

    int a = 2;
    int b = 4;
    int c = 5;
    int d = (int)(a * (b / (double)c));
    

    在这个小例子中,情况并没有那么糟糕,但是在一个大公式中,这个get相当混乱。

    另外,我想演员阵容会对表演产生影响。

    所以我的问题基本上是,是否有比同时计算除数和结果更好的方法。

    我知道在这个例子中,将a*(b/c)更改为(a*b)/c可以解决这个问题,但是在更大的现实场景中,不可能进行这种更改。

    编辑(从现有程序添加案例):

    在本例中,我将根据滚动条的大小和它的容器的大小计算滚动条的位置。因此,如果有双倍的元素适合页面,滚动条将是容器高度的一半,如果我们已经滚动了一半的元素,这意味着滚动条的位置应该向下移动1/4,这样它将位于容器的中间。计算工作正常,显示良好。我只是不喜欢代码中表达式的外观。

    代码的重要部分放在这里并附加在下面:

    int scrollerheight = (menusize.Height * menusize.Height) / originalheight;
    int maxofset = originalheight - menusize.Height;
    int scrollerposition = (int)((menusize.Height - scrollerheight) * (_overlayofset / (double)maxofset));
    

    OriginalHeight这里是所有元素的高度,因此在上面描述的情况下,这将是menusize.height的两倍。

    4 回复  |  直到 15 年前
        1
  •  1
  •   Matthew Flaschen    15 年前

    首先,C截断int除法的结果,当强制转换为int时,没有取整。

    没办法了 b / c 首先不进行任何转换。

        2
  •  2
  •   Dan Tao    15 年前

    免责声明 我把这些都打出来了,然后我想, 我应该贴这个吗?我是说,很漂亮 坏的 想法,因此没有 真的? 帮助OP… 最后,我想,嘿,我已经把它全部打印出来了;我不妨继续点击“发布你的答案”。尽管这是个“坏”主意,但还是有点有趣(对我来说,无论如何)。所以也许你会从阅读中得到一些奇怪的好处。

    出于某种原因,我怀疑上述免责声明不会保护我免遭否决,尽管…


    这是一个完全疯狂的想法。

    实际上,我不建议把它放在任何生产环境中, 完全 因为我真的想到了 刚才 这意味着我还没有完全考虑过,而且我确信这其中有大约10亿个问题。这只是个主意。

    但基本概念是创建一个可用于算术表达式的类型,在内部使用 double 对于表达式中的每个项,只计算为所需的类型(在本例中: int 结束 .

    你可以从这样的类型开始:

    // Probably you'd make this implement IEquatable<Term>, IEquatable<double>, etc.
    // Probably you'd also give it a more descriptive, less ambiguous name.
    // Probably you also just flat-out wouldn't use it at all.
    struct Term
    {
        readonly double _value;
    
        internal Term(double value)
        {
            _value = value;
        }
    
        public override bool Equals(object obj)
        {
            // You would want to override this, of course...
        }
    
        public override int GetHashCode()
        {
            // ...as well as this...
            return _value.GetHashCode();
        }
    
        public override string ToString()
        {
            // ...as well as this.
            return _value.ToString();
        }
    }
    

    然后你会定义 implicit 转换为/来自 双重的 以及要支持的类型(再次: int )这样地:

    public static implicit operator Term(int x)
    {
        return new Term((double)x);
    }
    
    public static implicit operator int(Term x)
    {
        return (int)x._value;
    }
    
    // ...and so on.
    

    接下来,定义操作本身: Plus , Minus 等等,对于您的示例代码,我们需要 Times (用于 * ) DividedBy (用于 / ):

    public Term Times(Term multiplier)
    {
        // This would work because you would've defined an implicit conversion
        // from double to Term.
        return _value * multiplier._value;
    }
    
    public Term DividedBy(Term divisor)
    {
        // Same as above.
        return _value / divisor._value;
    }
    

    最后,写一个 static 帮助程序类以使您能够执行 Term -基于您想使用的任何类型的操作(可能只是 int 初学者:

    public static class TermHelper
    {
        public static Term Times(this int number, Term multiplier)
        {
            return ((Term)number).Times(multiplier);
        }
    
        public static Term DividedBy(this int number, Term divisor)
        {
            return ((Term)number).DividedBy(divisor);
        }
    }
    

    所有这些会给你带来什么? 几乎什么都没有! 但是它会清除表达式,隐藏所有那些难看的显式类型转换,使代码显著地更有吸引力,并且 更不可能调试 . (再一次, 这不是背书 只是个疯狂的主意。)

    所以不是这样:

    int d = (int)(a * (b / (double)c)); // Output: 2
    

    你会得到这个:

    int d = a.Times(b.DividedBy(c)); // Output: 2
    

    值得吗?

    好吧,如果不得不写铸造操作 世界上最糟糕的事情 ,像, 更糟糕的是,这比依赖那些对自身利益来说太聪明的代码还要糟糕。 然后 也许吧 这样的解决方案是值得追求的。

    因为上面显然不是真的…答案是相当有力的 . 但我只是想我还是要分享这个想法,以表明这样的事情是(也许)可能的。

        3
  •  1
  •   TimW    15 年前

    乘以b乘以100。最后除以100。

        4
  •  1
  •   tia    15 年前

    在这种情况下,我建议使用 double 相反,因为你不需要“精确”的精度。

    但是,如果你真的觉得你想在没有浮点运算的情况下完成这一切,我建议你创建一个分数类,它要复杂得多,效率也低得多,但是你可以跟踪所有的被除数和除数,然后一次计算所有的数。