题
我写财务应用程序在那里我不断的战斗决定使用一个双vs使用十进制。
我所有的数学作品的数字不超过5小数位并不大于-100 000人。我有一种感觉,所有这些都可以表示为双打不管怎么说没有四舍五入错误的,但从来没有被确定。
我将继续前进和使从小数增加一倍的显而易见的速度利用,除了在一天结束的时候,我仍然使用ToString方法传送的价格向交流,并且需要确保它总是输出数预期。(的89.99,而不是89.99000000001)
问题:
- 是的速度优点真大天真测试的建议?(-100倍)
- 有没有办法保证的输出ToString是我想要什么?这是保证事实上,我的号码是总是表现的?
更新:我来处理约10亿美元的价格更新之前,我的应用程序可以运行,我们实现与小数点现在显而易见的保护原因,但它需要-3个小时,只是打开,双将大幅度减少我的开启时间。是否有一个安全的方式来做到这一双?
解决方案
- 浮点运算几乎总是以明显加快,因为它直接支持的硬件。迄今为止几乎没有广泛使用的硬件支持的十进制算法(虽然这种情况正在改变,见注释)。
- 财政应用程序 总是 使用十进制数字,数的恐怖故事源自使用浮点在财务应用程序是无穷无尽的,你应该能够找到许多这样的例子有一个谷歌搜索。
- 虽然小数的算术可以大大慢于浮点运算,除非你花大量的时间处理小数的数据影响在你的程序可能可以忽略不计。一如既往,执行适当分析之前你开始担心的差异。
其他提示
有两种可分离的问题。一种是,是否双具有足够精密,以保持所有位你需要的,另一个是在那里它可以表示你的号码完全一致。
至于确切的表示,你是对的,要谨慎,因为一个精确的小数喜欢的1/10没有确切的二进制的对应。然而,如果,你知道,你只需要5小数位精度,可以使用 缩放 运算在其中操作数字乘以10^5.因此,举例来说,如果你想要代表23.7205你真正代表它作为2372050.
让我们看看是否有足够的精度:双精密给你的53位精度。这相当于15岁以上的小数位数的精确度。因此,这将允许你五位小数点后和10位小数点前,这似乎是足够的。
我会把这C码中的一个。h文件:
typedef double scaled_int;
#define SCALE_FACTOR 1.0e5 /* number of digits needed after decimal point */
static inline scaled_int adds(scaled_int x, scaled_int y) { return x + y; }
static inline scaled_int muls(scaled_int x, scaled_int y) { return x * y / SCALE_FACTOR; }
static inline scaled_int scaled_of_int(int x) { return (scaled_int) x * SCALE_FACTOR; }
static inline int intpart_of_scaled(scaled_int x) { return floor(x / SCALE_FACTOR); }
static inline int fraction_of_scaled(scaled_int x) { return x - SCALE_FACTOR * intpart_of_scaled(x); }
void fprint_scaled(FILE *out, scaled_int x) {
fprintf(out, "%d.%05d", intpart_of_scaled(x), fraction_of_scaled(x));
}
可能有一些粗糙点,但应该足以让你开始。
没有任何开销,对另外,成本乘以或除以加倍。
如果你有访问C99,你也可以尝试缩整数的算术的使用 int64_t
64位整型。这是速度将取决于你的硬件平台。
总是使用十进制的任何财务计算,或者您将永远追逐1美分四舍五入的错误。
- 是的,软件运算真是100倍的速度慢于硬件。或者,至少,这是一个很慢,并且因子为100,给予或接受订单的数量级是正确的。早在旧天天气不好的时候你不能假设每个80386有80387浮点共同处理器,那么你有软件模拟的二进制浮点,那就是缓慢的。
- 没有;你是生活在一个虚幻的土地如果你认为一个纯粹的二进制的浮点都不能完全代表所有小数。二进制数字,可以结合两半,四分之三,八分之一,等等,但是,由于一个确切的位小数的0.01需要两个因素的五分之一和一个因素的四分之一(1/100 = (1/4)*(1/5)*(1/5)) 并且由于五分之一没有确切表示,在二元,你不能完全代表所有小数值与二进制的价值(因为0.01是一个反的例子,这不能完全代表,但是代表一个大类的数字不能完全代表).
所以,你必须决定是否可以处理的四舍五入之前,你叫ToString()或者是否需要找到其他一些机制,该机制将处理四舍五入的结果,因为他们被转化成一串。或者你可以继续使用十进制算法,因为它将保持准确的,并且它将得到更快的一次机被释放,支持新的IEEE754的十进制算在硬件。
强制性的交叉参考: 什么每一个计算机科学家应该知道的浮点运算.这是一个许多可能的网址。
信息的十进制算术和新IEEE754:2008标准在这 Speleotrove 网站。
只是使用一个长期和繁殖的一个功率为10。你完成后,将通过相同的功率10。
小数应始终用于财务计算。大小的数字并不重要。
最简单的方法对我来解释是通过某C#代码。
double one = 3.05;
double two = 0.05;
System.Console.WriteLine((one + two) == 3.1);
这些代码将打印出来 假 即使3.1是等到3.1...
同样的事情...但是,使用十进制:
decimal one = 3.05m;
decimal two = 0.05m;
System.Console.WriteLine((one + two) == 3.1m);
现在,这将打印出来 真的!
如果你想要避免这种问题,我建议你坚持小数。
我是指你给我的回答 这个问题.
使用长,储存量最小,你需要跟踪和显示的价值观。