XNA Float Parsing

Monkey Targets Forums/XNA/XNA Float Parsing

Raz(Posted 2011) [#1]
Hi Mark, I recently put a game I am working on (Ninjah) forward for peer review on Xbox. It failed because it would not work on systems that use a different decimal mark (e.g. spain uses a comma). This causes float.parse to fail. Here's a quote from the "Evil Checklist" http://forums.create.msdn.com/forums/t/19525.aspx

Caveat 1: Floating point number parsing. If your game uses textual representations of floating point numbers in its save data (either in game data or in game saves) and then needs to parse this text back into a float value while loading, then you must be careful to avoid culture/locale-based parsing problems. (The "test case 9" of above is an attempt to find bugs caused by this.)
Background: Different countries use different characters as the decimal separator. For example in the US and UK, a dot "." is used. I.e. "1.5" or similar. But for example Spain and Germany use a comma "," - i.e. "1,5" or similar.
Whenever you convert a float into a string with "value.ToString()" or parse a text into a float with "float.Parse(text)", the .NET framework will use the decimal separator that matches the currently selected locale. On the Xbox, the locale in turn is defined by the language that the Xbox dashboard is set to. So if you have a value of 1/2 and do "value.ToString()" on it, then on a Xbox set to English, the resulting string will be "0.5" but on a Xbox set to Spanish, the resulting string will be "0,5". Similarly, "float.Parse(text)" will also expect the separator that matches the currently language, so if the text "0.5" is parsed on a Spanish Xbox (which expects a "," as the separator), the result will be incorrect.
This has a lot of potential for bugs: Assume that you deploy your game with data that uses the "." and this game is played on a Spanish Xbox. Loading your data will fail, or at least give unexpected results. Or assume that someone plays your game on a Spanish Xbox and saves his game. In the game save, a "," will be used as the separator. Now the player changes his Xbox language to English and restarts the game. When is game save is loaded, the parser will expect a "." as the separator, which does not match the "," that is actually in the data and will thus result in a loading error.
Therefore, you should under all circumstances avoid plain calls to value.ToString() and float.Parse(text).
Instead, use value.ToString(CultureInfo.InvariantCulture) whenever your need to convert a float to a text and float.Parse(text, CultureInfo.InvariantCulture) whenever you need to parse this text back into a float.
This will have the effect that the data is always written and parsed with a dot "." as the separator.
Of course you then also need to make sure that all data that you deploy with the game also uses the dot "." as the decimal separator.
Note: Simply "plussing" a float to a string is comparable to using the plain value.ToString(). So you should avoid doing stuff like "this is text" + floatValue + "more text" when saving data. Instead use "this is text " + floatValue.ToString(CultureInfo.InvariantCulture) + "more text".
And of course the above applies only to saving data. If you want to convert a float into a text for display on screen, you should continue to use the normal value.ToString(), so that each player sees the value with the correct decimal separator for his country.
Note, that the XMLSerializer is not affected by this problem. It is only something that you need to look out for if you are writing/parsing float values manually.