首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这是PLINQ虫吗?

这是PLINQ虫吗?
EN

Stack Overflow用户
提问于 2011-02-18 07:19:52
回答 1查看 250关注 0票数 2

PLINQ输出与顺序处理和Parallel.For循环不同的原因

我想加10,000,000数字的平方根之和..以下是3种情况的代码:

顺序循环:

代码语言:javascript
复制
double sum = 0.0;
for(int i = 1;i<10000001;i++)
sum += Math.Sqrt(i);

它的输出是:21081852648.717

现在使用Parallel.For循环:

代码语言:javascript
复制
object locker = new object();
double total ;

Parallel.For(1,10000001,
()=>0.0,
(i,state,local)=> local+Math.Sqrt(i),
(local)=>
{
  lock(locker){ total += local; }
}
);

它的输出是:21081852648.7199

现在使用PLINQ

代码语言:javascript
复制
double tot =  ParallelEnumerable.Range(1, 10000000)
                .Sum(i => Math.Sqrt(i)); 

它的输出是:21081852648.72

为什么锁相环输出与Parallel.For和顺序环路有区别?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-02-18 07:32:21

我强烈怀疑这是因为带双数的算术不是真正的联想。在求和值时,信息可能会丢失,而丢失了什么信息将取决于操作的顺序。

下面是一个显示这种效果的例子:

代码语言:javascript
复制
using System;

class Test
{
    static void Main()
    {
        double d1 = 0d;
        for (int i = 0; i < 10000; i++)
        {
            d1 += 0.00000000000000001;
        }
        d1 += 1;
        Console.WriteLine(d1);

        double d2 = 1d;
        for (int i = 0; i < 10000; i++)
        {
            d2 += 0.00000000000000001;
        }
        Console.WriteLine(d2);
    }
}

在第一种情况下,我们可以添加非常小的数字很多次,直到它们变得足够大,当添加到1时仍然是相关的。

在第二种情况下,添加0.00000000000000001到1总是只会得到1,因为在双倍中没有足够的信息来表示1.00000000000000001,所以最后的结果仍然是1。

编辑:我想到了另一个可能会让事情混乱的方面。对于局部变量,JIT编译器能够(并且允许)使用80位FP寄存器,这意味着可以在信息丢失较少的情况下执行算术。例如,变量必须是64位的,但情况并非如此。在Parallel.For中,total变量实际上是生成类中的实例变量,因为它是由lambda表达式捕获的。这可能会改变结果--但它很可能取决于计算机架构、CLR版本等。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5038636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档