奇怪的数字错误
Bizarre numerical errors
我正在实现一个简单的二态粒子滤波器。如果您不知道什么是粒子过滤器,那没关系 - 简短版本是我需要计算权重介于 0 和 1 之间以及值介于 0 和 1 之间的加权均值。每个粒子都有一个值和一个权重。
虽然 C# 给我带来了非常奇怪的数值问题。
在尝试调试时,我的代码如下所示:
ConcurrentBag<Particle> particles; //this is inputted as an argument to my function
double mean = 0.0;
double totalWeight = 0.0;
foreach (Particle p in particles)
{
mean += p.Value * p.Weight;
totalWeight += p.Weight;
if (p.Value > 1.01 || p.Weight > 1.01)
{
Console.WriteLine("Value " + p.Value);
Console.WriteLine("Weight " + p.Weight);
Console.WriteLine("wtf");
}
}
if (totalWeight == 0.0)
{
//in this case, everything has miniscule weight, so let's just return 0.0 to avoid this precision corner case.
return new Bernoulli(0.0);
}
double oldMean = mean;
mean /= totalWeight;
return mean;
带有 "wtf" 的 if 语句用于调试目的,它正在被触发。但是,打印出来的是:
值 1.0
权重 0.01
这个 if 语句根本不应该为真!发生了什么事?
编辑:关于调试的一点更新。这是我目前的全部功能:
public override IDistribution createDistribution(ConcurrentBag<Particle> particles)
{
if (particles.Count == 0)
{
throw new Exception("Cannot create Distribution from empty particle collection");
}
if (!particles.ToArray()[0].GetType().IsAssignableFrom(typeof(BinaryParticle)))
{
throw new Exception("Cannot create Bernoulli Distribution from non-Binary Particle");
}
decimal mean = 0.0m;
decimal totalWeight = 0.0m;
foreach (Particle p in particles)
{
mean += (decimal)(p.Value * p.Weight);
totalWeight += (decimal)p.Weight;
if ((p.Weight > 1.01))
{
{
Console.WriteLine("Value " + p.Value);
Console.WriteLine("Weight " + p.Weight);
Console.WriteLine("Value " + p.Value.ToString("0.0000000"));
Console.WriteLine("wtf");
}
}
if (totalWeight == 0.0m)
{
//in this case, everything has miniscule weight, so let's just return 0.0 to avoid this precision corner case.
return new Bernoulli(0.0);
}
decimal oldMean = mean;
mean /= totalWeight;
try
{
return new Bernoulli((double)mean);
}
catch (Exception e)
{
decimal testMean = 0.0m;
decimal testTotalWeight = 0.0m;
Console.WriteLine(e);
foreach (Particle p in particles)
{
testMean += (decimal)(p.Value * p.Weight);
testTotalWeight += (decimal)p.Weight;
Console.WriteLine("weight is " + p.Weight);
Console.WriteLine("value is " + p.Value);
Console.WriteLine("Total mean is " + testMean);
Console.WriteLine("Total weight is " + testTotalWeight);
}
Console.WriteLine(testMean / testTotalWeight);
throw new Exception();
}
}
"mean" 给出的值与 catch 块中写入行中打印的值不同。我不知道为什么。此外,奇怪的是,当权重为 0.01 时,权重 > 1.01 才是真实条件。
好吧,你们会生气的,所以让我先说声对不起:-)
问题实际上是竞争条件,并且与我对 C# 中锁的工作方式的误解有关。我锁定了一个对象,它的实例可以在不同的方法中改变,其中粒子袋正在改变。用专用锁对象替换它解决了我的问题。
对不起^_^;;
我正在实现一个简单的二态粒子滤波器。如果您不知道什么是粒子过滤器,那没关系 - 简短版本是我需要计算权重介于 0 和 1 之间以及值介于 0 和 1 之间的加权均值。每个粒子都有一个值和一个权重。
虽然 C# 给我带来了非常奇怪的数值问题。
在尝试调试时,我的代码如下所示:
ConcurrentBag<Particle> particles; //this is inputted as an argument to my function
double mean = 0.0;
double totalWeight = 0.0;
foreach (Particle p in particles)
{
mean += p.Value * p.Weight;
totalWeight += p.Weight;
if (p.Value > 1.01 || p.Weight > 1.01)
{
Console.WriteLine("Value " + p.Value);
Console.WriteLine("Weight " + p.Weight);
Console.WriteLine("wtf");
}
}
if (totalWeight == 0.0)
{
//in this case, everything has miniscule weight, so let's just return 0.0 to avoid this precision corner case.
return new Bernoulli(0.0);
}
double oldMean = mean;
mean /= totalWeight;
return mean;
带有 "wtf" 的 if 语句用于调试目的,它正在被触发。但是,打印出来的是:
值 1.0 权重 0.01
这个 if 语句根本不应该为真!发生了什么事?
编辑:关于调试的一点更新。这是我目前的全部功能:
public override IDistribution createDistribution(ConcurrentBag<Particle> particles)
{
if (particles.Count == 0)
{
throw new Exception("Cannot create Distribution from empty particle collection");
}
if (!particles.ToArray()[0].GetType().IsAssignableFrom(typeof(BinaryParticle)))
{
throw new Exception("Cannot create Bernoulli Distribution from non-Binary Particle");
}
decimal mean = 0.0m;
decimal totalWeight = 0.0m;
foreach (Particle p in particles)
{
mean += (decimal)(p.Value * p.Weight);
totalWeight += (decimal)p.Weight;
if ((p.Weight > 1.01))
{
{
Console.WriteLine("Value " + p.Value);
Console.WriteLine("Weight " + p.Weight);
Console.WriteLine("Value " + p.Value.ToString("0.0000000"));
Console.WriteLine("wtf");
}
}
if (totalWeight == 0.0m)
{
//in this case, everything has miniscule weight, so let's just return 0.0 to avoid this precision corner case.
return new Bernoulli(0.0);
}
decimal oldMean = mean;
mean /= totalWeight;
try
{
return new Bernoulli((double)mean);
}
catch (Exception e)
{
decimal testMean = 0.0m;
decimal testTotalWeight = 0.0m;
Console.WriteLine(e);
foreach (Particle p in particles)
{
testMean += (decimal)(p.Value * p.Weight);
testTotalWeight += (decimal)p.Weight;
Console.WriteLine("weight is " + p.Weight);
Console.WriteLine("value is " + p.Value);
Console.WriteLine("Total mean is " + testMean);
Console.WriteLine("Total weight is " + testTotalWeight);
}
Console.WriteLine(testMean / testTotalWeight);
throw new Exception();
}
}
"mean" 给出的值与 catch 块中写入行中打印的值不同。我不知道为什么。此外,奇怪的是,当权重为 0.01 时,权重 > 1.01 才是真实条件。
好吧,你们会生气的,所以让我先说声对不起:-)
问题实际上是竞争条件,并且与我对 C# 中锁的工作方式的误解有关。我锁定了一个对象,它的实例可以在不同的方法中改变,其中粒子袋正在改变。用专用锁对象替换它解决了我的问题。
对不起^_^;;