5

I'm about to create a dictionary where each value has a numeric key, obtained by an experimental calculation.

I know that double and any other floating-point type is not well suited to be used as a key, since it's hard to compare two floating-point numbers regarding uniqueness or equality.

Does anyone knows if Decimal is a good candidate with this respect? The alternative would be to convert the double to string with a given precision, but that sounds to me like an inelegant workaround.

svick
  • 236,525
  • 50
  • 385
  • 514
heltonbiker
  • 26,657
  • 28
  • 137
  • 252
  • 3
    Why do you want to use a decimal number as a key in a dictionary? It may help us to give you the best solution. – Cédric Bignon Feb 04 '13 at 18:59
  • My instrument gives back a list for each item in a list of input angles. So, the domain natural mapping would be a dictionary where each key is a real number (in the mathematical sense). This number would be used in calculations, but a precision of about six digits would be fine (instrument has much lower precision). – heltonbiker Feb 04 '13 at 19:08
  • OK, but why a Dictionary? What are the values of the dictionary? – Cédric Bignon Feb 04 '13 at 19:09
  • The values are a list of pixel positions in a photograph where a horizontal stripe pattern has been projected, and each stripe has an angle with the horizontal plane. – heltonbiker Feb 04 '13 at 19:11
  • @CédricBignon but to be honest, I think the angles are not the real input, but rather an attribute of a "stripe" or "fringe" object. Perhaps I will reformulate my implementation, but the "numeric values as dictionary keys" question is still valid and relevant :) – heltonbiker Feb 04 '13 at 19:12
  • I'd scale your floating-point number to a whole number value. For dollars and cents, you multiply by 100 and store the whole number of pennies. If you're ok with 6 digits of precision, multiply your floating point value by 10^6. You may need to introduce tolerance values for comparisons. If you subtract two close enough values, they may not have to equal zero, but be less than your tolerance value. – Beth Feb 04 '13 at 19:13

3 Answers3

6

There is not much difference between using float or decimal as key in dictionary. Both represent number with exponent - so both suffer from the same comparison issue just in different scale.

Either would be ok for Dictionary if you need bit-wise equality, if you need to keys for "about the same value" you need to make it custom key which would round values in some known way to put similar results in the same bucket...

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
1

If you are using decimal or double because int is not large enough, consider using long instead.

Also, I think comparing decimals or doubles should be fine as long as there isn't a fraction/decimal part, and contains only integers (-1,0,1,2,3,etc)

(Although I do not recommend using decimal/double where comparison matters to avoid any future unexpected errors)

If you only dealing with 6 digits precision, then casting to int should be fine.

sharp12345
  • 4,420
  • 3
  • 22
  • 38
1

I know this is an old question, but I believe my answer could help someone.

I really needed float keys.

Of course I ran into the precision problems and my dictionary was much larger than it needed to be (I wanted it to e.g. 1.0 and 0.999998 to be treated as the same). Using fixed-number of decimal digits is not a great solution (e.g. converting it to string as proposed by OP) as it uses absolute error for comparison while relative error is much more universal.

I ended up writing the following method:

float Quantize(float x)
{
    const float relMaxQuantError = 0.001f;

    float ret = Mathf.Log10(Mathf.Abs(x));
    float quantum = Mathf.Log10(1+relMaxQuantError); 
    ret = Mathf.Floor(ret/quantum) * quantum;
    ret = Mathf.Sign(x) * (Mathf.Pow(10, ret));

    return ret;
}

I quantize the floats using this method before storing it in the dictionary. The maximum allowed relative error can be controlled by the const (currently it is 0.1 %).

PS: Mathf is Unity's class. It can be easilly tweaked to use the standard Math.

Lukas Z.
  • 483
  • 6
  • 14