代码之家  ›  专栏  ›  技术社区  ›  HasanG Joe Dabones

为什么在access query中看到-0000000000000001?

  •  0
  • HasanG Joe Dabones  · 技术社区  · 14 年前

    我有一个sql:

    SELECT Sum(Field1), Sum(Field2), Sum(Field1)+Sum(Field2)
    FROM Table
    GROUP BY DateField
    HAVING Sum(Field1)+Sum(Field2)<>0;
    

    3 回复  |  直到 14 年前
        1
  •  1
  •   June7    4 年前

    我确信这是因为float数据类型(在MS-Access中也称为Double或Single)是不精确的。它和十进制不同,十进制是一个简单的10次方数值。如果我没记错的话,浮点值可以有不同的分母,这意味着它们并不总是精确地转换回10进制。

    解决方法是将Field1和Field2从float/single/double更改为decimal或currency。如果您给出需要存储的最小值和最大值的示例,包括所需的最小值和最大值,如0.0001或0.9999,我们可能会给您更好的建议。

    请注意,2007年以前的Access版本在按十进制值排序时可能会出现问题。请阅读这篇文章的评论,了解更多的观点。在许多情况下,这对人们来说不是问题,但在其他情况下可能是。

    一般来说,float应该用于那些最终可能非常小或非常大(小于或大于小数点所能容纳的值)的值。您需要了解float以牺牲一些精度为代价来保持更精确的比例。也就是说,小数将溢出或下溢,而浮点可以继续。但是浮点数只有有限的有效位数,而小数位数都是有效的。

    如果无法更改列类型,则可以通过舍入最终计算来解决此问题。直到最后一刻才轮到你。

    更新

    对我使用十进制的建议的批评已经被消除了,不是关于结果的意外顺序,而是在相同位数的情况下,浮点值总体上更精确。

    对这个事实没有异议。然而,我认为人们更常见的情况是,他们的价值观实际上是以10为基数计算的,或者预期是以10为基数来表达的。我在论坛上一次又一次地看到关于他们的浮点数据类型有什么问题的问题,我没有看到关于十进制的这些问题。这对我来说意味着人们应该从十进制开始,当他们准备好如何以及何时使用float时,他们可以学习它,并在他们有能力的时候开始使用它。

    同时,虽然人们总是推荐十进制可能有点沮丧 ,不要让自己脱离现实世界,在现实世界中,有更熟悉的舍入错误而牺牲非常轻微的精度降低是有价值的。

    Decimal(1) / 3 * 3 顺从的 1.999999999999999999999999999

    因此,如果我们有两种方法来做实际上是在说同一件事,它们都可以非常精确地表示数字到一个可笑的有效数字数字,并且都需要舍入,但是其中一个已经舍入了 明显更熟悉 四舍五入错误比另一个,我不能接受推荐更熟悉的一个在任何方面都是坏的。对于一个能够执行 a - a 却得不到 0 作为答案?他会感到困惑,当他试图搞清楚的时候,他的工作会被打断。然后他会在留言板上寻求帮助,并得到一个简单的答案“使用十进制”。那他就死定了 很好 再过五年,直到有一天他变得足够好奇,最终学习并真正掌握了float的功能,并能够正确地使用它。

    也就是说,归根结底,我不得不说,抨击我推荐十进制在外太空似乎有点不合适。

    最后,我想指出的是,以下说法并非完全正确,因为它过于笼统:

    float和double类型以基数2存储数字,而不是以基数10存储数字。

    e 因此,它的基数经济性比基2表示法更为理想(似乎这对99.999%的计算机用户来说真的很重要)。另外,说“float和double类型”可能有点误导,因为double是float,但float不是double。Float是浮点的缩写,但是 是浮点数 亚型

        2
  •  2
  •   dan04    14 年前

    问题有时是字段1和 字段2的值类似于:9.5-10.3 结果为-0.80000000000001。可能 有人解释为什么会这样吗 如何解决?

    这个 float double 类型以2为基数存储数字,而不是以10为基数。有时,一个数字可以精确地用有限的位来表示。

    9.5 → 1001.1
    

    有时也不行。

    10.3 → 1010.0 1001 1001 1001 1001 1001 1001 1001 1001...
    

    在后一种情况下,数字将四舍五入到 被代表为 双重的 :

    1010.0100110011001100110011001100110011001100110011010 base 2
    = 10.300000000000000710542735760100185871124267578125 base 10
    

    当以二进制进行减法运算时,得到:

    -0.11001100110011001100110011001100110011001100110100000
    = -0.800000000000000710542735760100185871124267578125
    

    输出例程通常会隐藏大多数“噪声”数字。

    • Python3.1将其舍入到 -0.8000000000000007
    • SQLite 3.6将其舍入到 -0.800000000000001 .
    • printf %g 把它圆到 -0.8 .

    双重的 近似值为-0.8,即:

    - 0.11001100110011001100110011001100110011001100110011010
    = -0.8000000000000000444089209850062616169452667236328125
    

    双重的 ,表达式 9.5 - 10.3 == -0.8

    这个 decimal

    对于这样的问题,最常见的答案是“使用十进制算术”。在这个特定的例子中,这确实得到了更好的输出。使用Python的 decimal.Decimal

    >>> Decimal('9.5') - Decimal('10.3')
    Decimal('-0.8')
    

    不过,你还是得应付

    >>> Decimal(1) / 3 * 3
    Decimal('0.9999999999999999999999999999')
    >>> Decimal(2).sqrt() ** 2
    Decimal('1.999999999999999999999999999')
    

    这些可能是 舍入误差比二进制数的舍入误差要大,但这并不意味着舍入误差 不太重要

    更多

    许多的 更快(在PC上),因为它有专用的硬件。

    十进制没有什么特别的。这只是根据我们手指的数量随意选择的。

    如果说一个新生儿的体重是0x7.5磅(用更熟悉的术语来说,是7磅5盎司),那么说它的体重是7.3磅(是的,两者之间有0.2盎司的差异,但在允许范围内)同样准确。一般来说,十进制在表示物理测量值方面没有优势。

    钱是不同的

    仔细斟酌的 从某种程度上说,金钱是 因此是一个精确的数量。奇怪的是,它是以0.01的倍数来计算的,而不是像大多数其他离散量那样以1的倍数来计算的。

    如果你的“10.3”真的是10.30美元,那么你

    (除非你用的是1/16美元时的历史股价,在这种情况下,二进制是足够的;-))

    你得到了一个正确到15位有效数字的答案。这对所有实际用途都是正确的。如果您只是想隐藏“噪音”,请使用SQL ROUND

        3
  •  1
  •   quentin-starin    14 年前

    解决方法是在值上使用舍入函数来切断多余的数字。像这样(我只是四舍五入到小数点后的4位有效数字,但您当然应该使用适合您的数据的任何精度):

    SELECT Sum(Field1), Sum(Field2), Round(Sum(Field1)+Sum(Field2), 4)
    FROM Table
    GROUP BY DateField
    HAVING Round(Sum(Field1)+Sum(Field2), 4)<>0;