【问题标题】:Floating point precision different in the almost same views?在几乎相同的视图中浮点精度不同?
【发布时间】:2011-12-27 02:16:42
【问题描述】:

使用下一个 bash 脚本创建数据库:

#! /bin/bash
curl -X PUT http://127.0.0.1:5984/sales
IFS=$';'
vals=`cat sales_upload.json`
for i in $vals 
do
    curl -X POST http://127.0.0.1:5984/sales -H "Content-Type: application/json" -d $i
done
unset IFS

和资源文件:

{
    "Type" : "customer",
    "LastName" : "Welsh", 
    "FirstName" : "Jim",
    "Address" : "340 West 50th Street, New York, NY",
    "TotalSpent" : 734.34
};
{
    "Type" : "customer",
    "LastName" : "Zuch", 
    "FirstName" : "Bo",
    "Address" : "116 10th Avenue, New York, NY",
    "TotalSpent" : 1102.47
};
{
    "Type" : "customer",
    "LastName" : "Libby", 
    "FirstName" : "Joe",
    "Address" : "611 Fifth Avenue, New York, NY",
    "TotalSpent" : 290.01
};
{
    "Type" : "customer",
    "LastName" : "Grant", 
    "FirstName" : "Sue",
    "Address" : "7 West 55th Street, Manhattan, NY",
    "TotalSpent" : 430.83
};
{
    "Type" : "salesman",
    "LastName" : "Green", 
    "FirstName" : "Gwen",
    "Level" : 1
};
{
    "_id" : "_design/logic",
    "language" : "javascript",
    "views" :
    {
        "customers": {
            "map" : "function(doc) { if (doc.Type == 'customer')  emit(null, {LastName: doc.LastName, FirstName: doc.FirstName, Address: doc.Address}) }"
        },
        "total_purchases": {
            "map" : "function(doc) { if (doc.Type == 'customer')  emit(null, doc.TotalSpent) }",
            "reduce" : "function(keys, values) { return sum(values) }"
        }
    }
}

当我打电话时 curl -X GET http://127.0.0.1:5984/sales/_design/logic/_view/total_purchases

我明白了:

{"rows":[ {"key":null,"value":2557.65} ]}

但是如果我在 total_purchases 中将 emit 的第一个参数更改为 emit(doc.LastName, doc.TotalSpent),那么我会得到:

{"rows":[ {"key":null,"value":2557.6499999999996} ]}

为什么会这样?

【问题讨论】:

    标签: couchdb floating-accuracy


    【解决方案1】:

    您的答案之间的差异是由于您更改了视图功能。发出的第一个参数决定了如何构建视图索引。在第一种情况下,所有发出的值都将存储在“null”键下。在第二个示例中,您现在已经将索引分布在不同的键上,即客户的姓氏。

    因此,couchdb 中的内部 btree 在视图之间会有所不同。那么为什么总和会得到不同的结果呢?

    CouchDB 使用增量 map/reduce。你可以在这里阅读: http://damienkatz.net/2008/02/incremental_map.html

    Damien 从那篇帖子中指出了这一点:

    为了使增量 Map/Reduce 成为可能,Reduce 函数不仅要求它必须是引用透明的,而且它还必须对数组值输入是可交换和关联的,以便能够根据自己的输出进行 reduce 并得到同样的答案,像这样:

    f(Key, Values) == f(Key, [ f(Key, Values) ])

    reduce 函数的这种要求允许 CouchDB 将中间缩减直接存储到 btree 索引的内部节点中,并且视图索引更新和检索将具有对数成本。它还允许索引跨机器分布,并在查询时以对数成本减少。

    增量设计使得使用 map/reduce 实时查询大型分区集群成为可能,而不必等待整个 map/reduce 作业完成或拥有陈旧的、偶尔更新的索引。缺点是可能更难以关联和交换的方式编写 Reduce 函数。

    因此,我假设发生的情况是,在第一个视图中,由于它们都在同一个键下,因此没有存储的中间缩减。而在第二个视图中,正在存储临时总和。您可能会看到浮点数存储在这些中间和中的方式的差异。看这里: Is floating point math broken?

    两个建议可以帮助您解决这个问题。首先是使用对Erlang 版本的reduce 函数的“内置”调用。见这里:

    http://wiki.apache.org/couchdb/Built-In_Reduce_Functions

    调用略有不同:"reduce": "_sum"

    其次,您可以将浮点数转换为整数,如下所示: Is floating point math broken?

    希望这会有所帮助。

    【讨论】:

    • 你知道,当我将客户数量增加到 7 时,即使将 null 作为关键字段,它的输出也会出现错误的精度。但无论如何,谢谢和+1。
    • 你是不是又加了一个?它可能仍然是“增量的”。 erlang _sum 函数你试过了吗?
    猜你喜欢
    • 2015-05-17
    • 1970-01-01
    • 2018-10-31
    • 2014-03-12
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 2023-02-04
    • 2023-03-26
    相关资源
    最近更新 更多