关于c#:追踪NaN浮动的原因


Tracking down the cause of a NaN float

我有浮阵

1
public float[] Outputs;

在我的代码中,有一些东西正在更新数组值并导致NAN。这是一个非常罕见的错误,我无法为自己的生活找出导致它的原因。

如何在代码更改最小的情况下进行更改以跟踪它?最好是将该数组设为私有并重命名,然后创建一个名为outputs for get and setting的属性,该属性在每次设置时都执行NaN检查。然后,我可以在设置NaN并检索调用堆栈时轻松地引发异常,而不是在另一段代码尝试使用它时进一步发现它。像这样的-实际上是编译的。

我得到错误:

1
2
3
"Bad array declarator: To declare a managed array the rank specifier precedes
 the variable's identifier. To declare a fixed size buffer field, use the fixed
 keyword before the field type."

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    public float[] _outputs;

    public float Outputs[int index]  
    {
        get
        {
            return _outputs[index];
        }
        set
        {
            if (float.IsNaN(value))
                throw new Exception("Blar blar");
            _outputs[index] = value;
        }
    }

编辑:感谢您提供答案,其他任何寻求答案的人都可以阅读:为什么C不实现索引属性?


您不能在C中使用命名索引器,作为解决方法,您可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Indexer<T>
{
    private T[] _values;

    public Indexer(int capacity)
    {
        _values = new T[capacity];
    }

    protected virtual void OnValueChanging(T value)
    {
        // do nothing
    }

    public T this[int index]
    {
        get { return _values[index]; }
        set
        {  
            OnValueChanging(value);
            _values[index] = value;
        }
    }
}

public class FloatIndexer : Indexer<float>
{
    public FloatIndexer(int capacity)
        : base(capacity)
    {
    }

    protected override void OnValueChanging(float value)
    {
        if (float.IsNaN(value))
            throw new Exception("Blar blar");
    }
}

public class Container
{
    public Container()
    {
        Outputs = new FloatIndexer(3);
    }

    public FloatIndexer Outputs { get; private set; }
}
...
var container = new Container();
container.Outputs[0] = 2.5f;
container.Outputs[1] = 0.4f;
container.Outputs[2] = float.NaN; // BOOM!
...

我将其更新为更通用的,这样您就可以将其用于各种其他类型,而不仅仅是float


实际上,不可能声明具有特定名称的索引器。必须将对象环绕并使用:

1
public float this[int index] { ...}

对于这种情况,您可以使用包装类:

1
2
3
4
5
public class ArrayWrapper
{
    public float this[int index] { ...}
    public ArrayWrapper(float[] values) { .... }
}

要使用它,需要使用ArrayWrapper类作为属性类型。

作为替代方法,您可以使用扩展方法(因为您需要更改代码,所以不是很好):

1
public static void SetFloat(this float[] @this, int index, float value) { ... }

用这种方法:

1
targetObject.Outputs.SetFloat(0, Single.NaN);