通过整数进行分数计数

时间:2010-02-09 15:53:21

标签: c# algorithm

我收到一个整数,表示小数面额的美元金额。我想要一种算法,可以添加这些数字而无需解析并将它们转换为双精度或小数。

例如,我收到整数50155,这意味着50和15.5 / 32美元。然后我收到10210,即10和21/32美元。所以50 15.5 / 32 + 10 21/32 = 61 4.5 / 32,因此:

50155 + 10210 = 61045

同样,我想避免这种情况:

int a = 50155;
int b = a / 1000;
float c = a % 1000;
float d = b;
d += c / 320f;
// d = 50.484375

我更喜欢这个:

int a = 50155;
int b = 10210;
int c = MyClass.Add(a.b); // c = 61045
...
public int Add(int a, int b)
{
    // ?????
}

提前感谢您的帮助!

7 个答案:

答案 0 :(得分:4)

嗯,我认为你不需要使用浮点......

public static int Add(int a, int b)
{
    int firstWhole = a / 1000;
    int secondWhole = b / 1000;
    int firstFraction = a % 1000; 
    int secondFraction = b % 1000;
    int totalFraction = firstFraction + secondFraction;
    int totalWhole = firstWhole + secondWhole + (totalFraction / 320);
    return totalWhole * 1000 + (totalFraction % 320);
}

或者,您可能希望创建一个可以转换为整数格式的自定义结构,并重载+运算符。这将允许您编写更易读的代码,这些代码不会意外导致其他整数被视为略微奇怪的格式。

编辑:如果你被迫坚持使用“单整数”格式,但要稍微调整一下,你可能要考虑使用512而不是1000.这样你可以使用简单的掩码和移位:

public static int Add(int a, int b)
{
    int firstWhole = a >> 9;
    int secondWhole = b >> 9;
    int firstFraction = a & 0x1ff
    int secondFraction = b & 0x1ff;
    int totalFraction = firstFraction + secondFraction;
    int totalWhole = firstWhole + secondWhole + (totalFraction / 320);
    return (totalWhole << 9) + (totalFraction % 320);
}

仍然有320的混乱,但它至少有点好。

答案 1 :(得分:3)

在代表整美元的部分中打破字符串,以及代表美元部分的部分。对于后者,而不是将其视为10.5美元的三十秒,它可能更容易将其视为105美元的三百二十美元(即将十倍乘以分子总是一个整数)。

从那里开始,数学运算相当简单(如果编写有点单调乏味):添加分数。如果超过一美元,则携带一美元(并从分数部分减去320)。然后加上全部美元。同样减法 - 尽管在这种情况下你需要考虑借贷而不是携带。

答案 2 :(得分:3)

修改
这个答案表明,一个人“远离”浮动算法。令人惊讶的是,OP表明他的基于浮点的逻辑(由于专有原因未显示)的速度是下面整数模解决方案的两倍!来表明FPU毕竟不是那么糟糕......

明确地说,远离浮子(对于这个特殊问题)。整数算术更有效,并且不会引入舍入错误问题。

以下内容应该可以解决问题 注意:如上所述,假设A和B为正。

int AddMyOddlyEncodedDollars (int A, int B) {
  int sum;
  sum = A + B
  if (sum % 1000 < 320);
     return sum
  else
     return sum + 1000 - 320;
}

编辑:关于C的模运算符的效率 我非常依赖于编译器...由于模数值在编译时是已知的,我希望大多数现代编译器都采用“乘以[通过倒数]和移位”方法,这很快。 这种对性能的关注(用这种相当人为的格式)是对过早优化的要求,但话说再说一遍,我看到金融行业的软件得到了极大的优化(礼貌地说),并且理所当然。

答案 3 :(得分:2)

作为学习的一个点,这种表示称为“fixed point”。您可以查看许多实现。我强烈建议你不要使用int作为顶级数据类型,而是创建一个名为Fixed的类型来封装操作。当你错误地将一个普通的int添加到一个固定的点数而没有先缩放它,或者缩放一个数字并忘记去除它时,它会使你的bug数量减少。

答案 4 :(得分:1)

对我来说看起来像是一个奇怪的编码。

无论如何,如果格式是10-base Nxxx,其中N是表示整数美元的整数,xxx被解释为

(xxx / 320)

并且你想将它们加在一起,你需要处理的唯一事情是当xxx超过320时进行携带:

int a = ..., b = ...; // dollar amounts
int c = (a + b); // add together
// Calculate carry
int carry = (c % 1000) / 320; // integer division
c += carry * 1000;
c -= carry * 320;
// done

注意:这是有效的,因为如果a和b被正确编码,则小数部分最多加起来为638,因此整个美元部分没有“溢出”。

答案 5 :(得分:0)

如果你坚持使用ints,你就无法在没有解析的情况下解决问题 - 毕竟你的数据不是整数。我要求(迄今为止)3个答案的证据,这些答案在执行算术之前都会将你的内容解析为它们的组件。

另一种方法是使用带有2个(整数)分量的有理数,一个用于整个部分,一个用于小数部分中的第320个数。然后实现适当的有理算术。与以往一样,请仔细选择您的数据表示,并使您的算法更容易实现。

我不能说我认为这种替代方案在任何比较轴上都特别好,但它可能满足你不要解析的冲动。

答案 6 :(得分:0)

请注意:此帖子错误,错误错误。我会在尝试傻瓜时立即将其删除。

以下是我的说法:您可以按时交换空间

构造前10位到元组的映射:美元数,碎片数32。 然后对整数使用位操作:

  • 忽略位11及以上,应用地图。
  • 将整数移10次,从上面的映射中添加小额更改
  • 你现在拥有美元和数量
  • 添加两者
    • 将溢出移至金额

接下来,要转换回“规范”表示法,您需要为您的piecesof32设置反向查找映射并“借”美元以填充这些位。将货币卸下10次并添加32件。

编辑:我应该删除它,但我太惭愧了。当然,无法工作。我太蠢了:(

原因是:向右移动10与除以1024相同 - 这并不是说某些较低位有一个美元金额而是一些32个金额。十进制和二进制表示法不会很好地分裂。这就是为什么我们使用十六进制表示法(4位分组)。长号。