2

I am going a bit crazy here with the following section of code

  public static readonly float f = 1.25f;
  public static void init(){
     Debug.Log(f); // output: 1.25f
     FLIPPER_CENTERS = new float[,] { 
           { (20*f), (27*f) },    { FLIPPER_WIDTH - (20*f), (27*f)},
           { (6*f), (25*f) },     { MH_FLIPPER_WIDTH- (6*f), (25*f) },
           { (8), (15)},          { (SMALL_FLIPPER_WIDTH - 8), (15)},
           { (8), (20)},          { (67 - 8), (20)},
     };
     Debug.Log(FLIPPER_CENTERS[0,0]); // output: 0, expected 25;
  }

If I print the values of the first element of that array, I get [0, 0]. The last two elements are [59, 20], as expected.

The first value is supposed to be [25, 33,75]. Which I can get if I substitute (20*f) for (20*1.25f).

        { (20*1.25f), (27*1.25f) },    { FLIPPER_WIDTH - (20*f), (27*f)},

So here is the problem: if I leave the multiplication by f in the array initialization, the values are 0. However, if I change f to 1.25f all is good.

I have tried to figure out what is going on, but to no avail. I am certain the value of f is 1.25f and not 0. Can anyone shed some light on this for me please?

Edit:

To prove that f is not 0, I've tried 20/f for the first element. That didn't throw an exception and the output was still 0.

Partial Solution

Changing f from readonly to const solves the problem. However, I would really much like to know why this is happening.

  public const float f = 1.25f;

All this is running in Unity, it may have something to do with it.

ADB
  • 2,319
  • 1
  • 24
  • 35
  • What does your debugger say f is right when you set a break point at `FLIIPPER_CENTERS`? – BrianM Aug 22 '13 at 00:55
  • 2
    It appears that `f` is being used while it's still zero, i.e. before it gets assigned. Try making it `const float f=1.25f;` if you can, and see if it changes anything. – Sergey Kalinichenko Aug 22 '13 at 00:59
  • 4
    Just tested this and my results are coming out as expected. Are you leaving out some portion of your code? – awudoin Aug 22 '13 at 01:02
  • I agree with @dasblinkenlight. It seems as though 'f' might be zero when you set that matrix. – mrtig Aug 22 '13 at 01:07
  • The code above is from inside an instance function, init(). Also, if I print f, the value is 1.25f – ADB Aug 22 '13 at 01:21
  • @ADB Again....I just copy and pasted your code in VS and it is giving the expected output (25.0f). If `f` is not 0 because it's not giving a Divide by Zero error then something must be wrong with `FLIPPER_WIDTH`. How is that declared? – awudoin Aug 22 '13 at 01:45
  • 1
    I don't think it's possible for `f` to be used before it's assigned, because the static initializer will run before the `init` method can run. `f` is readonly, so the only other place it can be changed is in the constructor. Have you checked there? Finally, you'll find that divide by 0 does not necessarily throw an exception. See http://stackoverflow.com/q/4262286/56778 – Jim Mischel Aug 22 '13 at 03:43

1 Answers1

2

I see this question is tagged Unity3D.

Is it possible that f is a public variable exposing it to be modified in the Unity Editor? If so, any value set in the editor will override a value set in the code during variable declaration. The value set during declaration is simply used as a default value for the Unity Editor.

If this is the case then someone could have set f to 0 in the editor causing it to be 0 when you do your math.


Edited Answer After Some Testing: 8/22/2013

I was able to repeat your problem when using Unity. It seems there is a bug in Unity that doesn't allow variables to be used during initialization of an array at declaration. Everything works properly if it is a standard C# project, however, so this is related to Unity only.

The problem has nothing to do with f being static or readonly, only that it is a variable. The following code does not work:

public void init()
{ 
    float f = 1.25f;
    float[,] FLIPPER_CENTERS = new float[,] { 
       { (5+f), (27*f) },    { 30 - (20*f), (27*f)},
       { (6*f), (25*f) },     { 20 - (6*f), (25*f) },
       { (8), (15)},          { (10 - 8), (15)},
       { (8), (20)},          { (67 - 8), (20)},
    };
    Debug.Log(FLIPPER_CENTERS[0,0]); // Outputs 0 | Expected 6.25f
}

Anywhere the variable f is used in the array initialization will result in a 0. More specifically, it doesn't just set f = 0 it sets the whole expression to 0. For example, the first element in the array above, 5+f, would result in 0 - not 5. The elements with constants, however, evaluate normally (such as the last few elements). It seems if Unity is bailing out of the evaluation when it encounters a variable.

If, however, I define the array in one line and then set the elements later everything works normally. For example:

public void init()
{ 
    float f = 1.25f;
    float[,] FLIPPER_CENTERS = new float[8, 2];
    FLIPPER_CENTERS[0, 0] = 20*f;
    FLIPPER_CENTERS[0, 1] = 27*f;
    FLIPPER_CENTERS[1, 0] = 30 - (20*f);
    FLIPPER_CENTERS[1, 1] = 27*f;
    FLIPPER_CENTERS[2, 0] = 6*f;
    FLIPPER_CENTERS[2, 1] = 25*f;
    FLIPPER_CENTERS[3, 0] = 20 - (6*f);
    FLIPPER_CENTERS[3, 1] = 25*f;
    FLIPPER_CENTERS[4, 0] = 8;
    FLIPPER_CENTERS[4, 1] = 15;
    FLIPPER_CENTERS[5, 0] = 10 - 8;
    FLIPPER_CENTERS[5, 1] = 15;
    FLIPPER_CENTERS[6, 0] = 8;
    FLIPPER_CENTERS[6, 1] = 20;
    FLIPPER_CENTERS[7, 0] = 67 - 8;
    FLIPPER_CENTERS[7, 1] = 20;
    Debug.Log(FLIPPER_CENTERS[0,0]); // Outputs 25.0f | Expected 25.0f
}

Just did some further testing and it seems that the problem is only present with multidimensional arrays. The following gives expected output:

public void init()
{ 
    float f = 1.25f;
    float[] FLIPPER_CENTERS = new float[] {
        (f), (f * 2), (f * 3), (f * 4),
        (f + 1), (f + 2), (f + 3), (f + 5)
    };
    Debug.Log(FLIPPER_CENTERS[0]); // Outputs 1.25f | Expected 1.25f
}

This certainly seems like a bug in Unity to me. It is generally recommended, however, that const be used over static readonly. Using const provides a performance benefit (albeit slight) since it is converted into a literal at compile time. In addition, using const will avoid this problem altogether.

I know you already figured out const works, just wanted to give you a little information that I discovered.

awudoin
  • 541
  • 2
  • 8
  • @ADB: Please post the _actual_ code then, there's likely something else going on here. – Chris Sinclair Aug 22 '13 at 01:23
  • @ADB You definitely left things out of your code making it hard to help you. You code snippet doesn't show that it's readonly static... Please update your question with all the code. – awudoin Aug 22 '13 at 01:29
  • Done. The init function has more stuff in in of course, but the output are bounding the important area of the code – ADB Aug 22 '13 at 01:37