我写财务应用程序,我经常决定使用双倍与使用小数。
我的所有数学都适用于小数不超过5位且不大于~100,000的数字。我觉得所有这些都可以表示为双打而不会出现舍入错误,但是从来没有确定过。
我会继续从小数转换为双倍以获得明显的速度优势,除了在一天结束时,我仍然使用ToString方法将价格传输到交易所,并且需要确保它始终输出我期望的数字。 (89.99而不是89.99000000001)
问题:
更新:我必须在我的应用程序运行之前处理大约100亿次价格更新,并且我已经实现了带有小数的明显保护原因,但是只需要约3个小时才能打开,双打会大大减少我的开启时间。有没有一种安全的方法来做双打?
答案 0 :(得分:79)
答案 1 :(得分:23)
这里有两个可分开的问题。一个是双精度是否具有足够的精度来容纳你需要的所有位,另一个是它可以准确地代表你的数字。
至于确切的表示,你是谨慎的,因为像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位整数类型尝试缩放整数运算。哪个更快将取决于您的硬件平台。
答案 2 :(得分:20)
始终使用十进制进行任何财务计算,否则您将永远追逐1个舍入错误。
答案 3 :(得分:12)
因此,您必须在调用ToString()之前决定是否可以处理舍入,或者是否需要找到一些其他机制来处理将结果转换为字符串时舍入结果。或者你可以继续使用十进制算术,因为它将保持准确,并且一旦发布了支持硬件中新的IEEE 754十进制算术的机器,它将变得更快。
强制性交叉引用:What Every Computer Scientist Should Know About Floating-Point Arithmetic。这是许多可能的URL之一。
有关十进制算术的信息以及此Speleotrove站点的新IEEE 754:2008标准。
答案 4 :(得分:8)
只需使用长并乘以10的幂。完成后,除以10的相同幂。
答案 5 :(得分:5)
小数应始终用于财务计算。数字的大小并不重要。
我解释的最简单方法是通过一些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);
现在打印出 True !
如果你想避免这类问题,我建议你坚持使用小数。
答案 6 :(得分:1)
我建议你回答this question给我的答案。
使用long,存储您需要跟踪的最小量,并相应地显示值。