我正在处理财务数据,所以它有很多并且需要相对高精度(64 位浮点或更宽)。
我工作场所的标准做法似乎是将所有这些都表示为 c# 十进制类型,这是一个 128 位宽的浮点数,专门用于支持四舍五入的自由 base10 操作。
由于 64 位足够宽以保持代表性精度,因此将数据转换为更广泛的类型以进行所有计算(mult、div、add 等)然后回到 64 位以存储在内存中(这是它花费的地方)是荒谬的吗?大多数时候)?
供参考:内存绝对是这里的限制资源。
我正在处理财务数据,所以它有很多并且需要相对高精度(64 位浮点或更宽)。
我工作场所的标准做法似乎是将所有这些都表示为 c# 十进制类型,这是一个 128 位宽的浮点数,专门用于支持四舍五入的自由 base10 操作。
由于 64 位足够宽以保持代表性精度,因此将数据转换为更广泛的类型以进行所有计算(mult、div、add 等)然后回到 64 位以存储在内存中(这是它花费的地方)是荒谬的吗?大多数时候)?
供参考:内存绝对是这里的限制资源。
使用十进制(128 位)而不是双精度(64 位)和浮点数(32 位)通常与大小无关。跟基地有关。虽然 double 和 float 是浮点型二进制点类型,但 decimal 是一种浮点型小数点类型 - 正是这种特性使它可以准确地表示像 0.1 这样的数字,而 float/double 则不能。
我们不能没有 64 位十进制类型没有概念上的原因,在许多情况下这确实足够了 - 但在出现这种类型或您自己编写之前,请不要使用“更短的"(和二进制浮点)类型的浮点数/双精度数,用于财务计算。如果你这样做,你就是在自找麻烦。
如果您建议编写一种可以转换为十进制/从十进制转换并且仍然是浮点十进制类型的存储类型,那么即使它无法进行任何计算,这听起来也是一个潜在的好主意。如果您曾经被要求转换一个您无法准确表示的十进制值,您在考虑该怎么做时需要非常小心。老实说,我有兴趣看到这样的类型。唔...
(正如其他答案所表明的那样,在执行此操作之前,我真的要确保是数字占用了内存。如果您不需要这样做,那么推测性地引入额外的复杂性毫无意义。)
64bit 浮点数无法保持财务数据的精度。这不是空间问题,而是数据类型使用哪种数字系统的问题;double 使用 base-2,decimal 是 base-10,base-2 不能表示精确的 base-10 小数,即使它有 1000 位精度。
不相信我?运行这个:
double d = 0.0;
for (int i = 0; i < 100; i++)
d += 0.1;
Console.WriteLine(d);
> 9.99999999999998
如果您需要以 10 为底的计算,则需要小数类型。
(编辑:该死的,又被 Jon Skeet 打败了……)
如果十进制类型确实是瓶颈,您可以使用大量便士(或 1/8 美分或任何您的单位)而不是十进制美元。
您应该使用分析器来查看哪些对象占用了大量内存。如果您的十进制对象是罪魁祸首,那么我会说是的。否则你只是在猜测。Profiler 肯定会告诉你。
如果您不介意性能下降,将您的数字存储在 64 位,将它们转换为十进制类型进行计算,并将结果转换回 64 位是完全合理的。
在我工作的地方,我们需要这种精确度,所以这正是我们在这里所做的。通过强制转换,我们的速度提高了两个数量级,但我们永远不必担心浮点运算中的大错误。如果没有强制转换,计算可能会非常不准确,具体取决于数字的范围和正在执行的计算类型。
有关浮点运算的更多信息,以及为什么错误会蔓延到您的计算中,请参阅http://docs.sun.com/source/806-3568/ncg_goldberg.html上的“每个计算机科学家应该了解的关于浮点运算的知识”
正如大多数其他帖子已经指出的那样,在 128 位十进制和 64 位浮点表示之间进行转换并不是始终保持准确性的转换。
但是,如果您正在处理金融股的价格,您可以考虑将它们表示为整数(便士的数量)而不是十进制值(小数美元的数量)。以便士为单位执行所有财务计算,然后仅在请求时以小数形式向外界公开。
另一种方法可能是提高系统的算法效率,而不是“压缩”存储类型。您真的需要一次在内存中存储所有数据吗?你能以某种方式虚拟化它吗?
如果不是,考虑到您正在管理的数据量,您可能需要考虑以减少冗余的方式组织数据。例如,并非每只股票都有一个历史价格(有些公司存在的时间还不够远)。因此,将您的数据组织为按天(或按年)排列的股票价格字典,而不是每只股票的表格结构。可能还有其他选择,具体取决于您的数据如何可用以及您打算如何使用它执行计算。
如果 64 位浮点确实足以代表您想要的精度,这似乎非常合理。正如您所说,额外精度小数通常纯粹用于最大限度地减少多次操作的累积误差。
您需要进行数值分析,看看这种做法(保持 128 位)是否荒谬,或者只是懒惰,或者真的有必要。
“只是添加更多内存”是可以接受的答案吗?
正确编码和测试在这些表示之间移动值的建议方法涉及多少成本。将这个成本与将更多内存装入一台应用程序作为 64 位进程运行的机器进行比较。
来自MSDN decimal:浮点类型和十进制类型之间没有隐式转换;因此,必须使用强制转换来在这两种类型之间进行转换。
在您使用的情况下,看起来需要进行演员表。
话虽如此,了解这里的大多数其他人在用浮点表示货币的问题上所提出的问题是非常重要的。
您可以考虑创建/查找可用于您的系统的 64 位 BCD(二进制编码十进制)实现。
相同的双精度数转换为小数,然后转换为 byte[],然后压缩占用 c.2x 更少的空间(我刚刚使用几个压缩库对此进行了测试:Blosc 带默认值,lz4,zlib 带或不带随机播放,带随机播放的小数是最好的)。
一种选择是将压缩的小数存储在内存或磁盘上,因为现在 CPU 正在挨饿。在此处查看许多演示文稿:http: //blosc.org/docs/