Search Unity

float.ToString() Format

Discussion in 'Scripting' started by Simon75012, Oct 22, 2020.

  1. Simon75012

    Simon75012

    Joined:
    Sep 15, 2016
    Posts:
    79
    Hi,
    Code (CSharp):
    1. float my_float = 1.1234f;
    2. Debug.Log(my_float.ToString("F2"));
    I just realize that this command show the float in the device localisation format.
    Example :
    -Log in UK : "1.12"
    -Log in France : "1,12"
    The decimal separator is not a "." in every localisation.

    Is there a way to always have a "." and never have a ","?

    Thanks!
     
    NicBischoff likes this.
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    use a ToString overload that accepts IFormatProvider as an argument
    pass CultureInfo.InvariantCulture through this
    CultureInfo is found in System.Globalization.

    like so
    Code (csharp):
    1. using System.Globalization;
    2. using UnityEngine;
    3.  
    4. public class MyClass {
    5.  
    6.   public void MyMethod() {
    7.     var someNumber = Mathf.PI;
    8.     var label = someNumber.ToString("F3", CultureInfo.InvariantCulture); // F3 is to get exactly 3 digits beyond a decimal point
    9.     Debug.Log(label);
    10.   }
    11.  
    12. }
    this is from my head, I might be wrong about something, but you hopefully get the idea
     
    Last edited: Oct 22, 2020
  3. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,411
    i've used this to force dot, not sure if there are better alternatives:

    Code (CSharp):
    1. string CultureName = Thread.CurrentThread.CurrentCulture.Name;
    2. CultureInfo ci = new CultureInfo(CultureName);
    3. if (ci.NumberFormat.NumberDecimalSeparator != ".")
    4. {
    5.       ci.NumberFormat.NumberDecimalSeparator = ".";
    6.       Thread.CurrentThread.CurrentCulture = ci;
    7. }
     
    Novack and Hizir9 like this.
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    If you do it throughout like this, I'm sure it's enough to just do
    Code (csharp):
    1. Thread.CurrentThread.CurrentCulture = new CultureInfo(string.Empty);
    this enforces invariant culture

    similarly
    Code (csharp):
    1. Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
    it's the same thing basically
     
    Last edited: Oct 22, 2020
    mgear likes this.
  5. Simon75012

    Simon75012

    Joined:
    Sep 15, 2016
    Posts:
    79
    Thanks @orionsyndrome
    It worked, i just had to change "Culture.InvariantCulture" by "CultureInfo.InvariantCulture".
     
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    right right, that's what I meant (I'm fixing it)
     
  7. NicBischoff

    NicBischoff

    Joined:
    Mar 19, 2014
    Posts:
    204
    I had the same problem this week where save games from one machine suddenly had issues on another machine. I noted the comma, period issue and resolved it. It’s a heck of a possible issue because you might not notice it until release. My suggestion is to sanitize any sterilization with this in mind. This didn’t happen on 5.6 and seems to now occur on 2019 lts, but probably 2018 as well.
     
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    This has nothing to do with Unity. It's how C# operates by specification.
    And it's your job to pay attention and read such rules, guidelines, and specifications.
    I get that it's hard to notice sometimes. But now that you know, make sure it doesn't happen.
     
    Bunny83 likes this.
  9. NicBischoff

    NicBischoff

    Joined:
    Mar 19, 2014
    Posts:
    204
    Who are you talking to?
     
  10. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,411
    this was a change in unity 2019.x
    https://forum.unity.com/threads/pre...ad-of-dots-as-separators.847978/#post-5598706
     
    Joe-Censored and NicBischoff like this.
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Most likely to you ^^. It has nothing to do with the Unity version and it did happen in Unity 5. It even happened in Unity 2.6 (the version I started using Unity). I live in germany and we also have the comma as decimal seperator. Though on my machine I simply changed my system culture settings and replaced the decimal seperator with a dot. However as orionsyndrome said that's something you have to be aware of and you need to think about when parsing or serializing numbers.

    Keep in mind that it's not just the decimal seperator which differs. Within the CultureInfo you have a NumberFormatInfo with several other settings like the number of decimal digits, the goup seperator (which is the dot in german and french culture instead of the comma). If you have some time and want to get a rough overview, I can recommend Tom Scott's videos on I18N and Timezones ^^.
     
  12. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Note that the topic in the thread you linked was about Unity's own asset serialization. We talk here about pure .NET serialization / number formatting. It always has and still does use your current culture by default unless you change it. What they talked about is that Unity's own serialization did not pay attention to the culture and just let .NET convert the numbers into text. This does work unless you share your project with people who have a different / incompatible culture to your own. That's why any serialization code should use the invariant culture. Do not just use hardcoded en-US or en-GB since the cultures can change over time. So data serialized in the past could not be loaded properly in the future. The invariant culture is mostly equal to the english culture, but as the name suggests does never change.
     
    orionsyndrome likes this.
  13. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,411
    for me 2019.x broke string parsing,it was plain float.parse (no extra params),
    that used to work fine in different machines, in older unity versions.
     
    Joe-Censored and NicBischoff like this.
  14. NicBischoff

    NicBischoff

    Joined:
    Mar 19, 2014
    Posts:
    204
    Agreed. This was not the case pre 2019 in Unity and float.Parse(string) is most definitely behaving differently between 5.6 and 2019. My point still stands.
     
  15. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    look, they didn't break products that weren't broken to begin with.

    the way this works is that, prior to 2019, Unity DIDN'T comply to a standard, meaning that it did the right thing for you, by mistake (so arguably, it didn't do the right thing for everyone). in 2019, their compliance to the standard was fixed, meaning it ceased doing the right thing for you (but got standardized as it should be).

    so whoever managed this properly and opportunely, had no ill effects.
    and this feature has always been part of C#.

    also you have to voluntarily update a project to a 'broken' version of Unity for this to become a problem.
    claiming that it's Unity's problem is a little far-fetched. I mean for some people it was a problem before.
     
  16. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    The problem here is that C#/.NET's design is garbage insanity. The default culture should always be the invariant culture, as it's far more important that serialization works by default than that people get their display strings formatted "correctly" for the culture their computer is set to by default.

    In a world of json/xml, the vast majority of strings are never shown to the user, so Microsoft has gone the route of having the default behavior be correct in the minority of the cases - and they've chosen that people have to be careful to have their apps not break instead of having to be careful to show UI text a bit better.

    So the bug we used to have back in the days (I believe that it was only present on Windows) made that part of programming in C# a lot better than it was outside the Unity ecosystem. When Unity fixed the bug (as a side-effect of updating their Mono version, if I remember correctly), we advised Unity to reintroduce the old behavior by setting the default culture for everything to Invariant on all threads, as that's just better.

    They didn't do that, and that was wrong. Now all of my ToString calls take up 4 times as much space on the screen.

    F*** that.

    Hell, I'm from Norway, and our "culture" uses , instead of . for decimal separation. I did not give a single S*** that it showed up "wrong" before. It wasn't a problem. Every time Windows discovers that I'm not from the US, it's an utter disaster of things breaking in all directions all the time.

    GAH THIS IS SO DUMB
     
    Joe-Censored and NicBischoff like this.
  17. UnityMaru

    UnityMaru

    Community Engagement Manager PSM

    Joined:
    Mar 16, 2016
    Posts:
    1,227
    Hey... It's getting a little out of control here with the personal comments around understanding and such. Please tone it down :)
     
    Bunny83 likes this.
  18. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,108
    I haven't tried it actually, so maybe I'm overly optimistic, but it seems one might escape the clutches of culture, throughout the project, serialization included, if you do what I said in post #4?

    Also, maybe there is a compiler switch as well, I'm not sure, I'd have to research more.

    Here is, for example, a default culture setter for ALL threads, thus top level (it's been introduced in 4.6 it seems)

    Granted, it's a significant problem if it occurs silently in places that tend to be relatively invisible and are more than just a visual convenience, such as serialization.

    But regarding UI stringification, I've always had dedicated utilities with GetHumanizedString functions and similar, so maintenance-wise it's not such a big deal, my code was never cluttered with CultureInfo.InvariantCulture, I'd simply abstract the notion instead of doing ToString in situ.
     
    Bunny83 and Baste like this.
  19. acme3D

    acme3D

    Joined:
    Feb 4, 2009
    Posts:
    203
    Just stumbled upon a "bug" induced by converting a float to string. A few year after this thread was generated. I agree with the garbage/insanity that comes with C#. If you convert a float (which is x.xxxx) to a string, I expect to find the same thing on the other side (and not x,xxxx). Just because a string is a string, not a number: why do you need culture conversion by default???
     
  20. BroTools

    BroTools

    Joined:
    Feb 24, 2022
    Posts:
    2
    I assume it's because some locations/languages favor commas so the language doesn't assume it's a period without the culture set.C# and the ToString(0 or Float conversation should do that heavy lifting. I agree it's an oddity.
     
  21. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    This is already the wrong premise. A float is not "x.xxxx". A float are 32 bits which are seperated into a sign bit, 8 exponent bits and 23 mantissa bits. That's what a float is, nothing more, nothing less. When you convert a float into a decimal representation, this conversion is done with a certain culture setting. Half the world uses a comma as decimal seperator while the other half uses a dot. Pretty much the whole of europe uses a comma.

    Yes, the international SI standard uses a dot, but that mainly applies to science.

    Software that reads user input or displays numbers to the user is supposed to display them according to the local culture setting. If you want to serialize data you should always use the invariant culture. That's the point of the invariant culture, because it is guaranteed to never change.

    The world has different cultures and yours may not be the one that is globally used or valid. Even though the invariant culture is more or less identical with the US culture, the US culture could change in the future. For example in Windows you have the region settings in the control panel. You as a user also would expect that programs should obey the setting you have setup for your culture.
     
    Last edited: Apr 14, 2022
    orionsyndrome and ZO5KmUG6R like this.
  22. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    The culture conversion behavior by default kind of makes sense if your job is to develop UI's.
     
    ZO5KmUG6R and passerbycmc like this.
  23. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,993
    Note that I want to stress that there is no culture "conversion" going on as there is no "default" culture attached to numbers themselfs. Any string representation of a number has to follow some kind of format and there is no globally valid standard. The closest to an international standard is the SI system. Though even there we have essentially two standards where both comma and dot may be used as a decimal point. The SI standard does use a space as grouping character or none at all. This is to avoid confusion on the international level. So 299 792.458 km/s or 299 792,458 km/s can be interpreted the same no matter your local culture.
     
    Joe-Censored and ZO5KmUG6R like this.