Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by look001 · Jul 17, 2018 at 08:51 PM · c#serializationfloatjson

JsonUtility serializes floats with way too many digits

I need to serialize a Vector3 to Json. For this i want to use the build in JsonUtility. But JsonUtility converts a Vector3 to floats with a lot of decimal places. I know that this is the way a float works but it is not practical for serialization to a file. The files will become unnecessarily large because of all the digits.

Here an example:

 Debug.Log(JsonUtility.ToJson(new Vector3(0.24f, 0.5f, 0.75f)));

will output:

 {"x":0.23999999463558198,"y":0.5,"z":0.75}

can i do something to make this more efficient? I used Json Net before where this was no problem. However Json Net is a lot slower than JsonUtility (see here) and i would like to use as little 3rd party libraries as possible.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by JVene · Jul 17, 2018 at 09:47 PM

You've found the float problem.

You could try a double, which may seem counter intuitive, and doesn't always solve the problem, but here's what's happening to you:

float isn't accurate. There is a limited amount of storage, and it is typically squeezed into 32 bits. It is fashioned with a two part design, a mantissa and exponent. It is the binary version of scientific notation (like 2.4 e-1). However, the mantissa is limited to fewer than 32 bits. The exponent takes up some of those bits. In the standard IEEE format for this (which I think C# is using here), this means you have 24 bits for the precision (a base 2 version of the digits involved), and 8 bits for the exponent (expressing the power of 2 those digits should be shifted), and both are signed (so you have negative exponents for shifts toward very small values).

As a result of this encoding, the representation isn't exactly. .24 becomes a close approximation that when converted into base 10 looks like a garbled mess.

It is, however, normal, and even internally, the number .24 may indeed be "known" to your C# code as the value JSON is showing, and not actually .24f.

Doubles have more precision, and therefore have a chance to be more accurate, but in practice all that really means is that the base 10 representations are different (maybe .24 looks exact, but .242 doesn't). There are various formats, some considered non-standard.

This goes all the way down to the CPU, as it uses at least some standard for these representations which may be the same used by the language, and thus fundamentally there's nothing you can actually do if you're going to use floats.

You could, however, use other numbering systems. Fixed point values could be a choice, where an integer (possibly 64 bits) represents units such that you have a fixed number of decimal values that never "float" like this. For example, you could decide you want 4 digits of precision, so you'd consider all integers 1000 units, so that 240 is actually .24.

Other than that, this is a fundamental issue for which there are a wide range of solutions you'll find all over the web, and can choose among many that might better suit your preference for a particular application.

Or, like many of us, just accept that's how it works and forget about it.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image look001 · Jul 17, 2018 at 10:31 PM 0
Share

Thank you for the explaination. It looks like i have to switch to another serializer. Just accepting is pretty bad i would say. if a float that has 3 digits is converted to 18 characters in the file it is a big deal. The file will use about 5 times more storage than it needs. I actually just need to serialize a float like ToString("F4") does. I realy have doubt in the JsonUtility if a basic float sometimes needs 6 times more space just for a super tiny accuracy difference. It is not possible to round floats in the serialized Json with JsonUtiliy! it's pretty stupid in my opinion!

avatar image JVene look001 · Jul 17, 2018 at 11:05 PM 0
Share

As far as I can see, the built in JSON has no configuration options for itself. That said, you should probably have a look at custom serialization in Unity, which might solve your problem.

I've never used it, but there are open source libraries like:

Open Source JSON

It appears to have options for serialization control, maybe a bit too granular, but it might do what you need. Incorporating it within Unity may be a squeeze, and perhaps there are others, but JSON is among the very simplest I/O means, and you might just open a file and write out text as you prefer it (rounding as required), in the correct output format. You could still use JSON built in to read it if you get the output formatting correct, which is all but trivial.

That said, opening a file and writing data isn't entirely platform independent - especially where iOS is concerned, so target hardware/os invades the topic.

avatar image Bunny83 · Jul 18, 2018 at 07:34 AM 1
Share

You're right, though Unity's JSON serializer (as well as most others) use double values by default. The number above has about 17 significant decimal digits (53 bits) which matches the range of a double value. A float / single value has only about 7 significant decimal digits (24 bits)


Using double is actually suggested by the JSON standard

  Since software that implements
  IEEE 754-2008 binary64 (double precision) numbers [IEEE754] is
  generally available and widely used, good interoperability can be
  achieved by implementations that expect no more precision or range
  than these provide, in the sense that implementations will
  approximate JSON numbers within the expected precision.


However there's no real general valid precision limits that have to be applied to json numbers. They could be as long as you want. Though for compatibility you should never assume a higher precision than what double provides. If you need more precision it's adviced to store the value as string. If you want to play around with float or double values and their binary representation, have a look at my floating point format editor window for Unity.


As for the speed differences between the different serializers: Unity did implement their json serializer in native code. So obviously no managed garbage will be allocated. Unity's serializer is quite limited in what it can serialize. In addition, as you said, it doesn't have any configurations or settings. This is what it makes so fast. Not having to deal with all possible cases and having to incorporate various settings while serializing makes it fast. It's the typical trade-off between features and speed. You have to decide what you need or how you can workaround what you need. The ISerializationCallbackReceiver could be used to simply replace the float with an int and store it as a multiple of 1000 as you said above.

avatar image
1

Answer by Bunny83 · Jul 18, 2018 at 07:48 AM

Just for completeness: If you don't care about how the value is stored in the json data and all you need is to store and read the data from Unity you can store the value either as integer or as string. This can be easily done with Unity's ISerializationCallbackReceiver interface. You could even wrap the serialization into a seperate struct / class like this:

 public struct FloatWrapper : ISerializationCallbackReceiver
 {
     [System.NonSerialized]
     public float someValue;
     [SerializeField]
     private int _someValue;
     public void OnAfterDeserialize()
     {
         someValue = _someValue / 1000f;
     }
     public void OnBeforeSerialize()
     {
         _someValue = (int)(someValue * 1000);
     }
 }

In your code you just use the public float value. However when serialized we actually store the value as integer so you basically preserve 3 decimal digits behind the decimal point. So a value like "25.12" would be stored as 25120. Another way would be to use a string as serialized value and format the float as you like using the serialization callbacks. However in this case the value in the json data would be a string and not a json number

     // [ .... ]
     private string _someValue;
     public void OnAfterDeserialize()
     {
         float.TryParse(_someValue, out someValue);
     }
     public void OnBeforeSerialize()
     {
         _someValue = someValue.ToString("UseYourDesiredFormat");
     }
     // [ .... ]

Of course you have to take care of that the deserialization of the string value into a float works. Of course as a string value you have two additional quote characters in your json data.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

529 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

JsonUtility and Arrays [Error - "JSON must represent an object type"] 2 Answers

How do I go about deserializing a json array? 3 Answers

Serializing subclass of generic class not working 1 Answer

C# class to JSON 1 Answer

Serialize a list of scriptable objects to Json 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges