我收到一个整数,表示小数面额的美元金额。我想要一种算法,可以添加这些数字而无需解析并将它们转换为双精度或小数。
例如,我收到整数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)
{
// ?????
}
提前感谢您的帮助!
答案 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。 然后对整数使用位操作:
接下来,要转换回“规范”表示法,您需要为您的piecesof32设置反向查找映射并“借”美元以填充这些位。将货币卸下10次并添加32件。
编辑:我应该删除它,但我太惭愧了。当然,无法工作。我太蠢了:(
原因是:向右移动10与除以1024相同 - 这并不是说某些较低位有一个美元金额而是一些32个金额。十进制和二进制表示法不会很好地分裂。这就是为什么我们使用十六进制表示法(4位分组)。长号。