小数与双倍速度

我写财务应用程序,我经常决定使用双精度和使用小数。

我所有的math工作的数字不超过5位小数,不大于〜100,000。 我有一种感觉,无论如何,所有这些都可以表示为双打,而不是四舍五入的错误,但从来没有确定。

为了明显的速度优势,我会继续从小数切换到双打,除了在一天结束时,我仍然使用ToString方法将价格传递给交易所,并且需要确保总是输出数字I期望。 (89.99而不是89.99000000001)

问题:

  1. 速度优势真的和天真的testing一样大吗? (〜100次)
  2. 有没有办法保证ToString的输出是我想要的? 这是由我的号码总是可代表的事实保证?

更新:在我的应用程序可以运行之前,我必须处理大约100亿次的价格更新。为了明显的保护性原因,我现在已经用十进制实现了,但是打开它需要3个小时,双打会大大减less我的开启时间。 双打是否有安全的方法?

  1. 由于硬件直接支持浮点运算,所以浮点运算几乎总是快得多。 到目前为止,几乎没有广泛使用的硬件支持十进制算术(虽然这正在改变,请参阅注释)。
  2. 金融应用程序应该总是使用十进制数字,在金融应用程序中使用浮点数引起的恐怖故事是无止境的,您应该能够通过Googlesearchfind许多这样的例子。
  3. 虽然十进制算术可能比浮点algorithm慢得多,除非您花费大量的时间处理十进制数据,对您的程序的影响可能是微不足道的。 与往常一样,在开始担心差异之前进行适当的分析。

这里有两个独立的问题。 一个是double是否有足够的精度来保存你需要的所有位,另一个是它可以准确地表示你的数字的地方。

至于确切的表示,你是谨慎的,因为一个精确的小数如1/10没有确切的二进制对应。 但是,如果您知道只需要5位十进制数字的精度,则可以使用缩放算术,在这种算术中,您对乘以10 ^ 5的数字进行操作。 因此,例如,如果您想表示23.7205,则表示为2372050。

让我们看看是否有足够的精度:双精度给你53位的精度。 这相当于15+十进制数字的精度。 所以这会允许你在小数点后面有5位数字,在小数点前面是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位整数types尝试缩放整数算术。 哪个更快将取决于您的硬件平台。

总是使用十进制进行任何财务计算,否则将永远追逐一个四舍五入的错误。

  1. 是; 软件算术确实是硬件的100倍。 或者说,至less是慢了很多,一百倍,或者一个数量级,都是正确的。 回到过去的糟糕时代,当你不能假定每个80386都有一个80387浮点协处理器时,那么你也有二进制浮点的软件模拟,而且这个速度很慢。
  2. 没有; 如果你认为一个纯二进制浮点数能精确地代表所有的十进制数,你就生活在一个幻想的地方。 二进制数可以组合二分之一,四分之一,八分之一等,但由于0.01的精确小数需要两个因子五分之一和四分之一因子(1/100 =(1/4)*(1/5)*(1 / 5)),并且由于五分之一在二进制中没有精确的表示,所以不能精确地表示所有带有二进制值的十进制值(因为0.01是一个不能准确表示的反例,但代表了一个巨大的十进制数不能完全表示)。

因此,在调用ToString()之前,您必须决定是否可以处理四舍五入,或者是否需要find一些其他机制来处理将结果转换为string的四舍五入结果。 或者你可以继续使用十进制算术,因为它将保持准确,并且一旦机器被发布,硬件中支持新的IEEE 754十进制算术,它将变得更快。

强制性的交叉引用: 每个计算机科学家应该知道什么是浮点运算 。 这是许多可能的url之一,并导致PDF文件。 Sun有一个HTML版本,显然是同一篇论文的一个编辑版本。

有关十进制算术的信息以及此Speleotrove站点(之前由IBM托pipe的材料)中新的IEEE 754:2008标准。

只要使用一个长和乘以10的幂。完成后,除以相同的幂10。

小数应该总是用于财务计算。 数字的大小并不重要。

我解释的最简单的方法是通过一些C#代码。

 double one = 3.05; double two = 0.05; System.Console.WriteLine((one + two) == 3.1); 

即使3.1等于3.1,那么这些代码也会打印出False

同样的事情…但使用小数:

 decimal one = 3.05m; decimal two = 0.05m; System.Console.WriteLine((one + two) == 3.1m); 

这将打印出真正的

如果你想避免这种问题,我build议你坚持小数。

我把这个问题的答案转给你。

使用长时间,存储您需要跟踪的最小量,并相应地显示值。