Sql server 使用浮动或十进制计算应用程序美元金额?

Sql server 使用浮动或十进制计算应用程序美元金额?,sql-server,vb.net,database-design,currency,accounting,Sql Server,Vb.net,Database Design,Currency,Accounting,我们正在用VB.NET和SQL Server重写遗留的会计系统。我们引入了一个新的.NET/SQL程序员团队来进行重写。系统的大部分已经使用浮动完成了美元金额。我编写的遗留系统语言没有浮点,所以我可能会使用十进制 你的建议是什么 美元金额应使用浮动数据类型还是十进制数据类型 这两种方法的优点和缺点是什么 在我们的每日scrum中提到的一个缺点是,当计算返回结果超过两个小数点位置的金额时,必须小心。听起来你得把金额四舍五入到小数点后两位 另一个缺点是所有显示和打印的金额必须有一个显示两个小数点位置

我们正在用VB.NET和SQL Server重写遗留的会计系统。我们引入了一个新的.NET/SQL程序员团队来进行重写。系统的大部分已经使用浮动完成了美元金额。我编写的遗留系统语言没有浮点,所以我可能会使用十进制

你的建议是什么

美元金额应使用浮动数据类型还是十进制数据类型

这两种方法的优点和缺点是什么

在我们的每日scrum中提到的一个缺点是,当计算返回结果超过两个小数点位置的金额时,必须小心。听起来你得把金额四舍五入到小数点后两位

另一个缺点是所有显示和打印的金额必须有一个显示两个小数点位置的格式语句。我注意到有几次没有这样做,而且数量看起来不正确。(即10.2或10.2546)


pro表示浮点值仅占用磁盘上的8个字节,而十进制值将占用9个字节(十进制12,2)

浮点值不是精确的表示形式,可能会出现精度问题,例如在添加非常大和非常小的值时。这就是为什么建议对货币使用十进制类型,尽管精度问题可能非常罕见


为了澄清,decimal 12,2类型将精确存储这14位数字,而float则不会,因为它在内部使用二进制表示。例如,0.01不能用浮点数精确表示-最接近的表示形式实际上是0.009999998

您是否考虑过使用货币数据类型存储美元金额


关于十进制占用一个字节的缺点,我想说不在乎它。在100万行中,您只会多使用1 MB,而现在的存储非常便宜。

无论您做什么,都需要小心舍入错误。使用比您在中显示的精度更高的精度进行计算。

使用Float for money的唯一原因是如果您不关心准确的答案

问问你的会计师!他们会对你使用浮子表示不满。像以前的一些帖子一样,只有在不在乎准确性的情况下才使用float。虽然在钱的问题上我总是反对


在会计软件中,浮动是不可接受的。使用带4个小数点的小数点。

首先,您应该阅读此内容。然后,你应该考虑使用某种类型的软件包(例如java BigNIM,Python十进制模块),否则你会陷入一个伤害的世界。然后确定使用本机SQL十进制类型是否足够


存在浮点数/双精度浮点数(ed)以公开现在几乎过时的快速x87 fp。如果你关心计算的准确性和/或没有完全弥补它们的局限性,就不要使用它们。

浮点有意外的无理数

例如,您不能将1/3存储为十进制,它将是0.3333。。。(等等)

浮点数实际上存储为二进制值和2的幂指数

因此1.5存储为-1(或3/2)的3 x 2

使用这些基数为2的指数创建一些奇数无理数,例如:

将1.1转换为浮点数,然后再将其转换回,结果将类似于:1.0999999989

这是因为1.1的二进制表示形式实际上是154811237190861 x 2^-47,比double可以处理的多

关于这个问题的更多信息,但基本上,对于存储,最好使用小数

在Microsoft SQL server上,您有
money
数据类型-这通常最适合用于金融存储。精确到小数点后4位

对于计算,你有更多的问题-不准确度是很小的一部分,但把它放进幂函数,它很快就会变得重要


然而,小数对任何一种数学都不是很好——比如说,十进制幂并没有天生的支持。

对于我帮助开发的一个银行系统,我负责系统中的“应计利息”部分。每天,我的代码都会计算出当天余额的应计利息(earn)

对于这种计算,需要极高的准确性和保真度(我们使用了甲骨文的浮动),这样我们才能记录累积的“十亿分之一便士”

当涉及到“资本化”利息(即将利息支付回您的账户)时,金额被四舍五入到一便士。账户余额的数据类型为小数点后两位。(事实上,它更为复杂,因为它是一个多货币系统,可以在许多小数位上工作——但我们总是四舍五入到该货币的“便士”)。是的,那里有“分数”的损失和收益,但当计算机数字被实现时(支付或支付的金钱),它总是真实的金钱价值

这使会计师、审计员和测试人员感到满意


因此,请与您的客户核实。他们会告诉你他们的银行/会计规则和惯例。

你的会计师会想控制你的取舍方式。使用float意味着您将不断地进行取整,通常使用
FORMAT()
type语句,这不是您想要的方式(而是使用
floor
/
天花


您有货币数据类型(
money
smallmoney
),应该使用这些数据类型,而不是float或real。存储十进制(12,2)将消除舍入,但也会在中间步骤中消除舍入-这在金融应用程序中根本不是您想要的。

始终使用十进制。由于四舍五入问题,浮点值将不准确。

浮点数只能表示基数的负倍数之和-对于二进制浮点数,当然是2

只有四个十进制分数可以用二进制浮点精确表示
0.3 = 3/(2^1 * 5^1) = 0.3

0.3 = [0.25/0.5] [0.25/0.375] [0.25/3.125] [0.2825/3.125]

          1/4         1/8         1/16          1/32
int cents = num % 100;
int dollars = (num - cents) / 100;
printf("%d.%02d", dollars, cents);
#include <stdio.h>

int main()
{
    printf("Mapping 100 numbers between 0 and 1 ");
    printf("to their hexadecimal exponential form (HEF).\n");
    printf("Most of them do not equal their HEFs. That means ");
    printf("that their representations as floats ");
    printf("differ from their actual values.\n");
    double f = 0.01;
    int i;
    for (i = 0; i < 100; i++) {
        printf("%1.2f -> %a\n",f*i,f*i);
    }
    printf("Printing 128 'float-compatible' numbers ");
    printf("together with their HEFs for comparison.\n");
    f = 0x1p-7; // ==0.0071825
    for (i = 0; i < 0x80; i++) {
        printf("%1.7f -> %a\n",f*i,f*i);
    }
    return 0;
}
    DECLARE @Float1 float, @Float2 float, @Float3 float, @Float4 float; 
    SET @Float1 = 54; 
    SET @Float2 = 3.1; 
    SET @Float3 = 0 + @Float1 + @Float2; 
    SELECT @Float3 - @Float1 - @Float2 AS "Should be 0";

Should be 0 
---------------------- 
1.13797860024079E-15
DECLARE @Fixed1 decimal(8,4), @Fixed2 decimal(8,4), @Fixed3 decimal(8,4); 
SET @Fixed1 = 54; 
SET @Fixed2 = 0.03; 
SET @Fixed3 = 1 * @Fixed1 / @Fixed2; 
SELECT @Fixed3 / @Fixed1 * @Fixed2 AS "Should be 1";

Should be 1 
--------------------------------------- 
0.99999999999999900